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/ksynch.h> 28 #include <sys/kmem.h> 29 #include <sys/sdt.h> 30 31 #include <sys/varargs.h> 32 #include <sys/unistat/spcs_s.h> 33 34 #include "safestore.h" 35 #include "safestore_impl.h" 36 #include "sd_trace.h" 37 38 typedef struct safestore_modules_s { 39 struct safestore_modules_s *ssm_next; 40 safestore_ops_t *ssm_module; 41 } safestore_modules_t; 42 43 safestore_modules_t *ss_modules; 44 kmutex_t safestore_mutex; 45 int ss_initialized; 46 47 /* the safestore module init/deinit functions */ 48 49 void ss_ram_init(); 50 void ss_ram_deinit(); 51 52 /* CSTYLED */ 53 /**# 54 * initialize the safestore subsystem and all safestore 55 * modules by calling all safestore modules' initialization functions 56 * 57 * NOTE: This function must be called with the _sdbc_config_lock held 58 * 59 * @param none 60 * @return void 61 * 62 */ 63 void 64 sst_init() 65 { 66 /* 67 * initialize the ss modules we know about 68 * this results in calls to sst_register_mod() 69 */ 70 if (ss_initialized != SS_INITTED) { 71 mutex_init(&safestore_mutex, NULL, MUTEX_DRIVER, NULL); 72 ss_ram_init(); 73 ss_initialized = SS_INITTED; 74 } 75 76 } 77 78 /* CSTYLED */ 79 /**# 80 * deinitialize the safestore subsystem and all safestore modules 81 * by calling all safestore modules' deinitialization functions 82 * 83 * NOTE: This function must be called with the _sdbc_config_lock held 84 * 85 * @param none 86 * @return void 87 * 88 */ 89 void 90 sst_deinit() 91 { 92 if (ss_initialized == SS_INITTED) { 93 ss_ram_deinit(); 94 mutex_destroy(&safestore_mutex); 95 ss_initialized = 0; 96 } 97 } 98 99 /* BEGIN CSTYLED */ 100 /**# 101 * called by a safestore module to register its ops table 102 * for use by clients 103 * 104 * @param ss_ops structure of safestore functions 105 * @return void 106 * 107 * @see safestore_ops_t{} 108 */ 109 void 110 sst_register_mod(safestore_ops_t *ss_ops) /* END CSTYLED */ 111 { 112 safestore_modules_t *new; 113 114 new = kmem_alloc(sizeof (*new), KM_SLEEP); 115 116 mutex_enter(&safestore_mutex); 117 new->ssm_module = ss_ops; 118 new->ssm_next = ss_modules; 119 120 ss_modules = new; 121 mutex_exit(&safestore_mutex); 122 } 123 124 /* BEGIN CSTYLED */ 125 /**# 126 * called by a safestore module to unregister its ops table 127 * @param ss_ops structure of safestore functions 128 * 129 * @return void 130 * 131 * @see safestore_ops_t{} 132 */ 133 void 134 sst_unregister_mod(safestore_ops_t *ss_ops) /* END CSTYLED */ 135 { 136 safestore_modules_t *ssm, *prev; 137 int found = 0; 138 139 mutex_enter(&safestore_mutex); 140 prev = NULL; 141 for (ssm = ss_modules; ssm; prev = ssm, ssm = ssm->ssm_next) { 142 if (ssm->ssm_module == ss_ops) { 143 if (!prev) 144 ss_modules = ssm->ssm_next; 145 else 146 prev->ssm_next = ssm->ssm_next; 147 148 kmem_free(ssm, sizeof (safestore_modules_t)); 149 ++found; 150 break; 151 } 152 } 153 mutex_exit(&safestore_mutex); 154 155 if (!found) 156 cmn_err(CE_WARN, "ss(sst_unregister_mod) " 157 "ss module %p not found", (void *)ss_ops); 158 } 159 160 /* BEGIN CSTYLED */ 161 /**# 162 * open a safestore module for use by a client 163 * @param ss_type specifies a valid media type and transport type. 164 * the first module found that supports these reqested type 165 * is used. may contain more than one media type or transport 166 * type if client has no preference among several types. 167 * more than one ss_type may be specified in the call if 168 * client has an ordered preference. 169 * 170 * @return safestore_ops_t * pointer to a valid safestore ops structure 171 * if the request is satisfied. 172 * NULL otherwise 173 * 174 * @see safestore_ops_t{} 175 * @see SS_M_RAM 176 * @see SS_M_NV_SINGLENODE 177 * @see SS_M_NV_DUALNODE_NOMIRROR 178 * @see SS_M_NV_DUALNODE_MIRROR 179 * @see SS_T_STE 180 * @see SS_T_RPC 181 * @see SS_T_NONE 182 */ 183 safestore_ops_t * 184 sst_open(uint_t ss_type, ...) /* END CSTYLED */ 185 { 186 va_list ap; 187 uint_t ssop_type; 188 safestore_modules_t *ssm; 189 190 if ((ss_modules == NULL) || !ss_type) 191 return (NULL); 192 193 va_start(ap, ss_type); 194 mutex_enter(&safestore_mutex); 195 do { 196 for (ssm = ss_modules; ssm; ssm = ssm->ssm_next) { 197 ssop_type = ssm->ssm_module->ssop_type; 198 if ((ssop_type & SS_MEDIA_MASK) & ss_type) 199 if ((ssop_type & SS_TRANSPORT_MASK) & ss_type) { 200 va_end(ap); 201 mutex_exit(&safestore_mutex); 202 return (ssm->ssm_module); 203 } 204 } 205 } while ((ss_type = va_arg(ap, uint_t)) != 0); 206 mutex_exit(&safestore_mutex); 207 208 va_end(ap); 209 return (NULL); 210 } 211 212 /* BEGIN CSTYLED */ 213 /**# 214 * close a safestore module. called when client no longer wishes to use 215 * a safestore module 216 * 217 * @param ssp points to a safestore_ops_t obtained from a previous call 218 * to sst_open() 219 * 220 * @return SS_OK if successful 221 * SS_ERR otherwise 222 */ 223 /*ARGSUSED*/ 224 int 225 sst_close(safestore_ops_t *ssp) /* END CSTYLED */ 226 { 227 return (SS_OK); 228 } 229 230 231 /* 232 * _sdbc_writeq_configure - configure the given writeq 233 * Allocate the lock and sv we need to maintain waiters 234 * 235 */ 236 int 237 _sdbc_writeq_configure(_sd_writeq_t *wrq) 238 { 239 int i; 240 241 wrq->wq_inq = 0; 242 mutex_init(&wrq->wq_qlock, NULL, MUTEX_DRIVER, NULL); 243 wrq->wq_qtop = NULL; 244 wrq->wq_slp_top = 0; 245 wrq->wq_slp_index = 0; 246 wrq->wq_slp_inq = 0; 247 248 for (i = 0; i < SD_WR_SLP_Q_MAX; i++) { 249 wrq->wq_slp[i].slp_wqneed = 0; 250 cv_init(&wrq->wq_slp[i].slp_wqcv, NULL, CV_DRIVER, NULL); 251 } 252 253 return (0); 254 } 255 256 /* 257 * _sdbc_writeq_deconfigure - deconfigure the given writeq 258 * Deallocate the lock and sv if present. 259 * 260 */ 261 void 262 _sdbc_writeq_deconfigure(_sd_writeq_t *wrq) 263 { 264 int i; 265 266 if (wrq) { 267 mutex_destroy(&wrq->wq_qlock); 268 for (i = 0; i < SD_WR_SLP_Q_MAX; i++) { 269 cv_destroy(&wrq->wq_slp[i].slp_wqcv); 270 } 271 wrq->wq_inq = 0; 272 wrq->wq_qtop = NULL; 273 } 274 275 } 276 277 278 int _sd_wblk_sync = 1; 279 280 ss_wr_cctl_t * 281 ss_alloc_write(int need, int *stall, _sd_writeq_t *q) 282 { 283 ss_wr_cctl_t *wctl; 284 ss_wr_cctl_t *ret; 285 int i; 286 int aged = 0; 287 288 if (_sd_wblk_sync && (q->wq_inq == 0)) 289 return (NULL); /* do sync write if queue empty */ 290 291 SDTRACE(ST_ENTER|SDF_WR_ALLOC, SDT_INV_CD, need, 292 SDT_INV_BL, q->wq_inq, _SD_NO_NET); 293 294 if (need <= 0) { 295 cmn_err(CE_WARN, "ss_alloc_write: bogus need value! %d", need); 296 return (NULL); 297 } 298 299 mutex_enter(&(q->wq_qlock)); 300 retry_wr_get: 301 if (q->wq_inq < need) { 302 if (!_sd_wblk_sync) { 303 unsigned stime; 304 stime = nsc_usec(); 305 306 /* 307 * Try to keep requests ordered so large requests 308 * are not starved. We can queue 255 write requests, 309 * After That go into write-through. 310 */ 311 if (q->wq_slp_inq < SD_WR_SLP_Q_MAX) { 312 q->wq_slp_inq++; 313 /* give preference to aged requests */ 314 if (aged) { 315 WQ_SVWAIT_TOP(q, need); 316 } else { 317 WQ_SVWAIT_BOTTOM(q, need); 318 } 319 aged++; 320 } else { 321 mutex_exit(&(q->wq_qlock)); 322 return (NULL); 323 } 324 325 SDTRACE(ST_INFO|SDF_WR_ALLOC, 326 SDT_INV_CD, need, SDT_INV_BL, q->wq_inq, 327 (nsc_usec()-stime)); 328 (void) (*stall)++; 329 goto retry_wr_get; 330 } 331 ret = NULL; 332 } else { 333 get_wctl: 334 wctl = q->wq_qtop; 335 ret = wctl; 336 DTRACE_PROBE1(alloc_write, 337 ss_wr_cctl_t *, wctl); 338 for (i = 1; i < need; ++i) { 339 wctl = wctl->wc_next; 340 DTRACE_PROBE1(alloc_write_cont, 341 ss_wr_cctl_t *, wctl); 342 } 343 344 q->wq_qtop = wctl->wc_next; 345 wctl->wc_next = NULL; 346 q->wq_inq -= need; 347 } 348 mutex_exit(&(q->wq_qlock)); 349 350 SDTRACE(ST_EXIT|SDF_WR_ALLOC, SDT_INV_CD, need, 351 SDT_INV_BL, q->wq_inq, _SD_NO_NET); 352 return (ret); 353 } 354 355 /* 356 * ss_release_write - put a write block back in the writeq. 357 * 358 * ARGUMENTS: 359 * wctl - Write control block to be release. 360 * q - write q to put the wctl 361 * 362 * RETURNS: NONE 363 */ 364 365 void 366 ss_release_write(ss_wr_cctl_t *wctl, _sd_writeq_t *q) 367 { 368 369 SDTRACE(ST_ENTER|SDF_WR_FREE, SDT_INV_CD, 0, SDT_INV_BL, q->wq_inq, 370 _SD_NO_NET); 371 372 DTRACE_PROBE1(release_write, 373 ss_wr_cctl_t *, wctl); 374 375 #if defined(_SD_DEBUG) 376 if (wctl->wc_gl_info->sci_dirty) { 377 SDALERT(SDF_WR_FREE, wctl->wc_gl_info->sci_cd, 378 0, wctl->wc_gl_info->sci_fpos, 379 wctl->wc_gl_info->sci_dirty, 0); 380 } 381 #endif 382 mutex_enter(&q->wq_qlock); 383 384 wctl->wc_next = q->wq_qtop; 385 q->wq_qtop = wctl; 386 q->wq_inq++; 387 if (WQ_NEED_SIG(q)) { 388 q->wq_slp_inq--; 389 WQ_SVSIG(q); 390 } 391 mutex_exit(&q->wq_qlock); 392 SDTRACE(ST_EXIT|SDF_WR_FREE, SDT_INV_CD, 0, SDT_INV_BL, q->wq_inq, 393 _SD_NO_NET); 394 }