1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/errno.h> 28 #include <sys/cmn_err.h> 29 #include <sys/ksynch.h> 30 #include <sys/kmem.h> 31 #include <sys/ddi.h> 32 33 #define __NSC_GEN__ 34 #include "nsc_dev.h" 35 #include "../nsctl.h" 36 37 /* 38 * (Un)Freeze Module 39 * 40 * This module provides a means to 'freeze' a device and ensure 41 * that no SP software has an open reference to that device. Later 42 * the device can be 'unfrozen' and the SP software can resume 43 * normal operations. 44 * 45 * This module is required because it is possible to place a virtual 46 * volume driver (RAID-0, 1 or 5) into a state whereby it needs to be 47 * disabled for corrective action. The (un)freeze facility provides a 48 * method of doing this without downtime. 49 * 50 * A device that is frozen should be frozen on all nodes. It is the 51 * responsibility of the management software or the user to perform 52 * the freeze and unfreeze on the required nodes. 53 */ 54 55 extern nsc_mem_t *_nsc_local_mem; 56 57 typedef struct _nsc_frz_s { 58 struct _nsc_frz_s *next; 59 nsc_path_t *token; 60 char path[NSC_MAXPATH]; 61 } _nsc_frz_t; 62 63 64 extern int _nsc_frz_stop(char *, int *); /* forward decl */ 65 66 static _nsc_frz_t *_nsc_frz_top; 67 static nsc_def_t _nsc_frz_def[]; 68 static kmutex_t _nsc_frz_sleep; 69 static nsc_io_t *_nsc_frz_io; 70 71 72 void 73 _nsc_init_frz(void) 74 { 75 mutex_init(&_nsc_frz_sleep, NULL, MUTEX_DRIVER, NULL); 76 77 _nsc_frz_io = nsc_register_io("frz", 78 NSC_FREEZE_ID | NSC_FILTER, _nsc_frz_def); 79 80 if (!_nsc_frz_io) 81 cmn_err(CE_WARN, "nsctl: _nsc_init_frz: register failed"); 82 } 83 84 85 void 86 _nsc_deinit_frz(void) 87 { 88 if (_nsc_frz_io) 89 (void) nsc_unregister_io(_nsc_frz_io, 0); 90 91 _nsc_frz_io = NULL; 92 93 mutex_destroy(&_nsc_frz_sleep); 94 } 95 96 97 /* 98 * int _nsc_frz_start(char *path, int *rvp) 99 * Freeze a device 100 * 101 * Calling/Exit State: 102 * Must be called from a context that can block. 103 * Returns 0 for success, or one of the following error codes: 104 * EINVAL - invalid 'path' argument 105 * ENOMEM - failed to allocate memory 106 * EALREADY - 'path' is already frozen 107 * 108 * Description: 109 * Registers 'path' to be accessed through the NSC_FREEZE_ID 110 * io module, and forces any open file descriptors for 'path' 111 * to be re-opened as appropriate. 112 */ 113 int 114 _nsc_frz_start(path, rvp) 115 char *path; 116 int *rvp; 117 { 118 _nsc_frz_t *frz, *xfrz; 119 int rc; 120 121 *rvp = 0; 122 123 if (strlen(path) >= NSC_MAXPATH) 124 return (EINVAL); 125 126 frz = nsc_kmem_zalloc(sizeof (*frz), KM_SLEEP, _nsc_local_mem); 127 if (!frz) 128 return (ENOMEM); 129 130 (void) strcpy(frz->path, path); 131 132 mutex_enter(&_nsc_frz_sleep); 133 134 for (xfrz = _nsc_frz_top; xfrz; xfrz = xfrz->next) 135 if (strcmp(frz->path, xfrz->path) == 0) 136 break; 137 138 if (!xfrz) { 139 frz->next = _nsc_frz_top; 140 _nsc_frz_top = frz; 141 } 142 143 mutex_exit(&_nsc_frz_sleep); 144 145 if (xfrz) { 146 nsc_kmem_free(frz, sizeof (*frz)); 147 return (EALREADY); 148 } 149 150 frz->token = nsc_register_path(path, NSC_DEVICE, _nsc_frz_io); 151 152 if (!frz->token) { 153 (void) _nsc_frz_stop(path, &rc); 154 return (EINVAL); 155 } 156 157 return (0); 158 } 159 160 161 /* 162 * int _nsc_frz_stop(char *path, int *rvp) 163 * Unfreeze a device 164 * 165 * Calling/Exit State: 166 * Must be called from a context that can block. 167 * Returns 0 or an error code. 168 * 169 * Description: 170 * Removes the path registration for the NSC_FREEZE_ID io module 171 * and forces any re-opens as appropriate. 172 */ 173 int 174 _nsc_frz_stop(path, rvp) 175 char *path; 176 int *rvp; 177 { 178 _nsc_frz_t **xfrz, *frz = NULL; 179 int rc = 0; 180 181 *rvp = 0; 182 183 mutex_enter(&_nsc_frz_sleep); 184 185 for (xfrz = &_nsc_frz_top; *xfrz; xfrz = &(*xfrz)->next) 186 if (strcmp(path, (*xfrz)->path) == 0) { 187 frz = *xfrz; 188 break; 189 } 190 191 if (!frz) { 192 mutex_exit(&_nsc_frz_sleep); 193 return (EINVAL); 194 } 195 196 if (frz->token) 197 rc = nsc_unregister_path(frz->token, NSC_PCATCH); 198 199 if (rc) { 200 mutex_exit(&_nsc_frz_sleep); 201 return (rc); 202 } 203 204 (*xfrz) = frz->next; 205 206 mutex_exit(&_nsc_frz_sleep); 207 208 nsc_kmem_free(frz, sizeof (*frz)); 209 210 return (0); 211 } 212 213 214 /* 215 * int _nsc_frz_isfrozen(char *path, int *rvp) 216 * Tests whether a device is frozen. 217 * 218 * Calling/Exit State: 219 * Returns 0 or EINVAL. 220 * Sets *rvp to 1 if the device was not frozen, and 0 otherwise. 221 * This function returns historical information. 222 */ 223 int 224 _nsc_frz_isfrozen(path, rvp) 225 char *path; 226 int *rvp; 227 { 228 _nsc_frz_t *frz; 229 230 *rvp = 1; 231 232 if (! _nsc_frz_io) 233 return (EINVAL); 234 235 mutex_enter(&_nsc_frz_sleep); 236 237 for (frz = _nsc_frz_top; frz; frz = frz->next) 238 if (strcmp(frz->path, path) == 0) { 239 *rvp = 0; 240 break; 241 } 242 243 mutex_exit(&_nsc_frz_sleep); 244 245 return (0); 246 } 247 248 249 /* 250 * static int 251 * _nsc_frz_open(char *path, int flag, blind_t *cdp) 252 * Dummy open function. 253 * 254 * Description: 255 * This is the "Open" function for the I/O module. 256 * It is just a dummy. 257 */ 258 259 /* ARGSUSED */ 260 261 static int 262 _nsc_frz_open(path, flag, cdp) 263 char *path; 264 int flag; 265 blind_t *cdp; 266 { 267 *cdp = 0; 268 return (0); 269 } 270 271 272 /* 273 * static int 274 * _nsc_frz_close() 275 * Dummy close function. 276 * 277 * Description: 278 * This is the "Close" function for the I/O module. 279 * It is just a dummy. 280 */ 281 static int 282 _nsc_frz_close() { return (0); } 283 284 285 /* 286 * static int 287 * _nsc_frz_attach() 288 * Attach a device to this i/o module. 289 * 290 * Calling/Exit State: 291 * Returns EACCES in all cricumstances. 292 * 293 * Description: 294 * This function is called by the nsctl module when it wishes 295 * to attach the device to this I/O module (ie. as part of 296 * nsc_reserve() processing). This function unconditionally 297 * returns an error which forces the nsc_reserve() to fail, and 298 * so no access to possible to the underlying device. 299 */ 300 static int 301 _nsc_frz_attach() { return (EACCES); } 302 303 304 static nsc_def_t _nsc_frz_def[] = { 305 "Open", (uintptr_t)_nsc_frz_open, 0, 306 "Close", (uintptr_t)_nsc_frz_close, 0, 307 "Attach", (uintptr_t)_nsc_frz_attach, 0, 308 "Provide", 0, 0, 309 0, 0, 0 310 };