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/note.h> 27 28 /* 29 * Generic SCSI Host Bus Adapter interface implementation 30 */ 31 32 #include <sys/dada/dada.h> 33 34 extern int dcd_options; 35 36 static kmutex_t dcd_hba_mutex; 37 38 kmutex_t dcd_log_mutex; 39 40 struct dcd_hba_inst { 41 dev_info_t *inst_dip; 42 dcd_hba_tran_t *inst_hba_tran; 43 struct dcd_hba_inst *inst_next; 44 struct dcd_hba_inst *inst_prev; 45 }; 46 47 static struct dcd_hba_inst *dcd_hba_list = NULL; 48 static struct dcd_hba_inst *dcd_hba_list_tail = NULL; 49 50 51 _NOTE(READ_ONLY_DATA(dev_ops)) 52 53 kmutex_t dcd_flag_nointr_mutex; 54 kcondvar_t dcd_flag_nointr_cv; 55 56 57 /* 58 * Called from _init when loading the dcd module. 59 */ 60 void 61 dcd_initialize_hba_interface() 62 { 63 mutex_init(&dcd_hba_mutex, NULL, MUTEX_DRIVER, NULL); 64 mutex_init(&dcd_flag_nointr_mutex, NULL, MUTEX_DRIVER, NULL); 65 cv_init(&dcd_flag_nointr_cv, NULL, CV_DRIVER, NULL); 66 mutex_init(&dcd_log_mutex, NULL, MUTEX_DRIVER, NULL); 67 } 68 69 /* 70 * Called from fini() when unloading the dcd module. 71 */ 72 73 void 74 dcd_uninitialize_hba_interface() 75 { 76 mutex_destroy(&dcd_hba_mutex); 77 cv_destroy(&dcd_flag_nointr_cv); 78 mutex_destroy(&dcd_flag_nointr_mutex); 79 mutex_destroy(&dcd_log_mutex); 80 } 81 82 83 /* 84 * Called by an HBA from _init() 85 */ 86 /* ARGSUSED */ 87 int 88 dcd_hba_init(struct modlinkage *modlp) 89 { 90 91 return (0); 92 } 93 94 95 96 #ifdef NOTNEEDED 97 /* ARGSUSED */ 98 int 99 dcd_hba_attach(dev_info_t *dip, 100 ddi_dma_lim_t *hba_lim, 101 dcd_hba_tran_t *hba_tran, 102 int flags, 103 void *hba_options) 104 { 105 106 ddi_dma_attr_t hba_dma_attr; 107 108 bzero(&hba_dma_attr, sizeof (ddi_dma_attr_t)); 109 110 hba_dma_attr.dma_attr_burstsizes = hba_lim->dlim_burstsizes; 111 hba_dma_attr.dma_attr_minxfer = hba_lim->dlim_minxfer; 112 113 return (dcd_hba_attach_setup(dip, &hba_dma_attr, hba_tran, flags)); 114 } 115 #endif 116 117 118 int 119 dcd_hba_attach( 120 dev_info_t *dip, 121 ddi_dma_attr_t *hba_dma_attr, 122 dcd_hba_tran_t *hba_tran, 123 int flags) 124 { 125 126 struct dcd_hba_inst *elem; 127 int value; 128 int len; 129 char *prop_name; 130 char *errmsg = 131 "dcd_hba_attach: cannott create property '%s' for %s%d\n"; 132 133 /* 134 * Link this instance into the list 135 */ 136 elem = kmem_alloc(sizeof (struct dcd_hba_inst), KM_SLEEP); 137 138 elem->inst_dip = dip; 139 elem->inst_hba_tran = hba_tran; 140 141 mutex_enter(&dcd_hba_mutex); 142 elem->inst_next = NULL; 143 elem->inst_prev = dcd_hba_list_tail; 144 145 if (dcd_hba_list == NULL) { 146 dcd_hba_list = elem; 147 } 148 if (dcd_hba_list_tail) { 149 dcd_hba_list_tail->inst_next = elem; 150 } 151 dcd_hba_list_tail = elem; 152 mutex_exit(&dcd_hba_mutex); 153 154 155 /* 156 * Save all the improtant HBA information that must be accessed 157 * later. 158 */ 159 160 hba_tran->tran_hba_dip = dip; 161 hba_tran->tran_hba_flags = flags; 162 163 /* 164 * Note: We only need dma_attr_minxfer and dma_attr_burstsize 165 * from the DMA atrributes 166 */ 167 168 hba_tran->tran_min_xfer = hba_dma_attr->dma_attr_minxfer; 169 hba_tran->tran_min_burst_size = 170 (1<<(ddi_ffs(hba_dma_attr->dma_attr_burstsizes)-1)); 171 hba_tran->tran_max_burst_size = 172 (1<<(ddi_fls(hba_dma_attr->dma_attr_burstsizes)-1)); 173 174 175 176 prop_name = "dcd_options"; 177 len = 0; 178 if (ddi_prop_op(DDI_DEV_T_ANY, dip, PROP_LEN, 0, prop_name, 179 NULL, &len) == DDI_PROP_NOT_FOUND) { 180 value = dcd_options; 181 if (ddi_prop_update_int(DDI_MAJOR_T_UNKNOWN, dip, 182 prop_name, value) != DDI_PROP_SUCCESS) { 183 cmn_err(CE_CONT, errmsg, prop_name, 184 ddi_get_name(dip), ddi_get_instance(dip)); 185 } 186 } 187 188 189 /* 190 * XXX : This needs to be removed when code cleanup 191 * ddi_set_driver_private(dip, (caddr_t)hba_tran); 192 */ 193 #ifdef DEBUG1 194 printf("Called Set driver private with dip %x, tran %x\n", 195 dip, hba_tran); 196 #endif 197 198 return (DDI_SUCCESS); 199 } 200 201 202 /* 203 * called by an HBA to detach an instance of the driver 204 */ 205 206 int 207 dcd_hba_detach(dev_info_t *dip) 208 { 209 210 dcd_hba_tran_t *hba; 211 struct dcd_hba_inst *elem; 212 213 hba = ddi_get_driver_private(dip); 214 ddi_set_driver_private(dip, NULL); 215 ASSERT(hba != NULL); 216 217 hba->tran_hba_dip = (dev_info_t *)NULL; 218 hba->tran_hba_flags = 0; 219 hba->tran_min_burst_size = (uchar_t)0; 220 hba->tran_max_burst_size = (uchar_t)0; 221 222 223 /* 224 * Remove HBA instance from dcd_hba_list 225 */ 226 227 mutex_enter(&dcd_hba_mutex); 228 229 for (elem = dcd_hba_list; elem != (struct dcd_hba_inst *)NULL; 230 elem = elem->inst_next) { 231 if (elem->inst_dip == dip) 232 break; 233 } 234 235 if (elem == (struct dcd_hba_inst *)NULL) { 236 cmn_err(CE_NOTE, "dcd_hba_attach: Unknown HBA instance\n"); 237 mutex_exit(&dcd_hba_mutex); 238 } 239 240 if (elem == dcd_hba_list) { 241 dcd_hba_list = elem->inst_next; 242 dcd_hba_list->inst_prev = (struct dcd_hba_inst *)NULL; 243 } else if (elem == dcd_hba_list_tail) { 244 dcd_hba_list_tail = elem->inst_prev; 245 dcd_hba_list_tail->inst_next = (struct dcd_hba_inst *)NULL; 246 } else { 247 elem->inst_prev->inst_next = elem->inst_next; 248 elem->inst_next->inst_prev = elem->inst_prev; 249 } 250 mutex_exit(&dcd_hba_mutex); 251 252 kmem_free(elem, sizeof (struct dcd_hba_inst)); 253 254 return (DDI_SUCCESS); 255 } 256 257 void 258 dcd_hba_fini() 259 { 260 261 } 262 263 /* ARGSUSED */ 264 dcd_hba_tran_t * 265 dcd_hba_tran_alloc( 266 dev_info_t *dip, 267 int flags) 268 { 269 270 return (kmem_zalloc(sizeof (dcd_hba_tran_t), 271 (flags & DCD_HBA_CANSLEEP) ? KM_SLEEP: KM_NOSLEEP)); 272 } 273 274 275 void 276 dcd_hba_tran_free(dcd_hba_tran_t *hba_tran) 277 { 278 279 kmem_free(hba_tran, sizeof (dcd_hba_tran_t)); 280 } 281 282 283 /* 284 * XXX: Do we really need the following routines. 285 */ 286 287 /* 288 * private wrapper for dcd_pkt's allocated via scsi_hba_pkt_alloc 289 */ 290 291 struct dcd_pkt_wrapper { 292 struct dcd_pkt dcd_pkt; 293 int pkt_wrapper_len; 294 }; 295 296 _NOTE(SCHEME_PROTECTS_DATA("unique per thread", dcd_pkt_wrapper)) 297 298 /* 299 * Round up all allocations so that we can gurentee 300 * long-long alignment. This is the same alignment 301 * provided by kmem_alloc(). 302 */ 303 304 #define ROUNDUP(x) (((x) + 0x07) & ~0x07) 305 306 /* 307 * Called by an HBA to allocate a dcd_pkt 308 */ 309 310 /* ARGSUSED */ 311 struct dcd_pkt * 312 dcd_hba_pkt_alloc( 313 struct dcd_address *ap, 314 int cmdlen, 315 int statuslen, 316 int tgtlen, 317 int hbalen, 318 int (*callback)(caddr_t arg), 319 caddr_t arg) 320 { 321 322 struct dcd_pkt *pkt; 323 struct dcd_pkt_wrapper *hba_pkt; 324 caddr_t p; 325 int pktlen; 326 327 328 /* 329 * Sanity check 330 */ 331 if (callback != SLEEP_FUNC && callback != NULL_FUNC) { 332 cmn_err(CE_PANIC, " dcd_hba_pkt_alloc: callback must be" 333 " either SLEEP or NULL\n"); 334 } 335 336 337 /* 338 * Round up so everything gets allocated on long-word boundaries. 339 */ 340 341 cmdlen = ROUNDUP(cmdlen); 342 tgtlen = ROUNDUP(tgtlen); 343 hbalen = ROUNDUP(hbalen); 344 statuslen = ROUNDUP(statuslen); 345 pktlen = sizeof (struct dcd_pkt_wrapper) + 346 cmdlen + tgtlen +hbalen + statuslen; 347 348 hba_pkt = kmem_zalloc(pktlen, 349 (callback = SLEEP_FUNC) ? KM_SLEEP: KM_NOSLEEP); 350 351 if (hba_pkt == NULL) { 352 ASSERT(callback == NULL_FUNC); 353 return (NULL); 354 } 355 356 /* 357 * Set up or private info on this pkt 358 */ 359 hba_pkt->pkt_wrapper_len = pktlen; 360 pkt = &hba_pkt->dcd_pkt; 361 p = (caddr_t)(hba_pkt + 1); 362 363 /* 364 * set up pointers to private data areas, cdb and status. 365 */ 366 if (hbalen > 0) { 367 pkt->pkt_ha_private = (ataopaque_t)p; 368 p += hbalen; 369 } 370 371 if (tgtlen > 0) { 372 pkt->pkt_private = (ataopaque_t)p; 373 p += tgtlen; 374 } 375 376 if (statuslen > 0) { 377 pkt->pkt_scbp = (uchar_t *)p; 378 p += statuslen; 379 } 380 381 if (cmdlen > 0) { 382 pkt->pkt_cdbp = (void *)p; 383 } 384 385 /* 386 * Initialize the pkt's dcd_address 387 */ 388 pkt->pkt_address = *ap; 389 #ifdef DEBUG1 390 printf("da_target %x, da_lun %x, a_hba_tran %x\n", 391 pkt->pkt_address.da_target, pkt->pkt_address.da_lun, 392 pkt->pkt_address.a_hba_tran); 393 printf("From address : da_target %x, da_lun %x, a_hba_tran %x\n", 394 ap->da_target, ap->da_lun, ap->a_hba_tran); 395 printf("Pkt %x\n", pkt); 396 397 #endif 398 return (pkt); 399 } 400 401 402 /* ARGSUSED */ 403 void 404 dcd_hba_pkt_free( 405 struct dcd_address *ap, 406 struct dcd_pkt *pkt) 407 { 408 409 kmem_free((struct dcd_pkt_wrapper *)pkt, 410 ((struct dcd_pkt_wrapper *)pkt)->pkt_wrapper_len); 411 } 412 413 414 /* 415 * Called by an HBA to map strings to capability indices 416 */ 417 418 int 419 dcd_hba_lookup_capstr(char *capstr) 420 { 421 422 /* 423 * Capability strings, masking the '-' vs '_'. 424 */ 425 static struct cap_strings { 426 char *cap_string; 427 int cap_index; 428 } cap_string[] = { 429 { "dma-max", DCD_CAP_DMA_MAX }, 430 { "dma_max", DCD_CAP_DMA_MAX }, 431 { "ultraata", DCD_CAP_ULTRA_ATA }, 432 { "busmaster", DCD_CAP_BUS_MASTER }, 433 { "overlap", DCD_CAP_OVERLAP }, 434 { "parity", DCD_CAP_PARITY }, 435 { "sector-size", DCD_CAP_SECTOR_SIZE }, 436 { "total-sectors", DCD_CAP_TOTAL_SECTORS }, 437 { "geometry", DCD_CAP_GEOMETRY }, 438 { "block-mode", DCD_CAP_BLOCKMODE }, 439 { "block-factor", DCD_CAP_BLOCKFACTOR }, 440 { "dma-support", DCD_CAP_DMA_SUPPORT }, 441 { "pio-support", DCD_CAP_PIO_SUPPORT }, 442 { "lba-addressing", DCD_CAP_LBA_ADDRESSING }, 443 { NULL, 0 } 444 }; 445 struct cap_strings *cp; 446 447 for (cp = cap_string; cp->cap_string != NULL; cp++) { 448 if (strcmp(cp->cap_string, capstr) == 0) { 449 return (cp->cap_index); 450 } 451 } 452 453 return (-1); 454 } 455