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