1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. 14 */ 15 16 #include <sys/sdt.h> 17 #include "cpqary3.h" 18 19 /* 20 * Local Functions Definitions 21 */ 22 23 int cpqary3_target_geometry(struct scsi_address *); 24 int8_t cpqary3_detect_target_geometry(cpqary3_t *); 25 26 /* 27 * Function : cpqary3_read_conf_file 28 * Description : This routine reads the driver configuration file. 29 * Called By : cpqary3_attach() 30 * Parameters : device-information pointer, per_controller 31 * Calls : None 32 * Return Values: None 33 */ 34 void 35 cpqary3_read_conf_file(dev_info_t *dip, cpqary3_t *cpqary3p) 36 { 37 char *ptr; 38 39 cpqary3p->noe_support = 0; 40 41 /* 42 * Plugin the code necessary to read from driver's conf file. 43 * As of now, we are not interested in reading the onf file 44 * for any purpose. 45 * 46 * eg. : 47 * 48 * retvalue = ddi_getprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 49 * "cpqary3_online_debug", -1); 50 */ 51 52 /* 53 * We are calling ddi_prop_lookup_string 54 * which gets the property value, which is passed at 55 * the grub menu. If the user wants to use the older 56 * target mapping algorithm,(prior to 1.80)at the grub menu 57 * "cpqary3_tgtmap=off" should be entered. if this 58 * string is entered, then we will set the 59 * value of the variable legacy_mapping to one, which 60 * will be used in 61 * cpqary3_detect_target_geometry() 62 * and cpqary3_probe4LVs(), to decide on the 63 * mapping algorithm 64 */ 65 66 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 67 "cpqary3_tgtmap", &ptr) == DDI_PROP_SUCCESS) { 68 if (strcmp("off", ptr) == 0) { 69 cpqary3p->legacy_mapping = 1; 70 } 71 ddi_prop_free(ptr); 72 } 73 74 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 75 "cpqary3_noesupport", &ptr) == DDI_PROP_SUCCESS) { 76 if (strcmp("on", ptr) == 0) { 77 cpqary3p->noe_support = 1; 78 } 79 if (strcmp("off", ptr) == 0) { 80 cpqary3p->noe_support = 0; 81 } 82 ddi_prop_free(ptr); 83 } 84 } 85 86 /* 87 * Function : cpqary3_tick_hdlr 88 * Description : This routine is called once in 60 seconds to detect any 89 * command that is pending with the controller and has 90 * timed out. 91 * Once invoked, it re-initializes itself such that it is 92 * invoked after an interval of 60 seconds. 93 * Called By : kernel 94 * Parameters : per_controller 95 * Calls : None 96 * Return Values: None 97 */ 98 void 99 cpqary3_tick_hdlr(void *arg) 100 { 101 clock_t cpqary3_lbolt; 102 clock_t cpqary3_ticks; 103 cpqary3_t *ctlr; 104 cpqary3_pkt_t *pktp; 105 struct scsi_pkt *scsi_pktp; 106 cpqary3_cmdpvt_t *local; 107 volatile CfgTable_t *ctp; 108 uint32_t i; 109 uint32_t no_cmds = 0; 110 111 /* 112 * The per-controller shall be passed as argument. 113 * Read the HeartBeat of the controller. 114 * if the current heartbeat is the same as the one recorded earlier, 115 * the f/w has locked up!!! 116 */ 117 118 if (NULL == (ctlr = (cpqary3_t *)arg)) 119 return; 120 121 ctp = (CfgTable_t *)ctlr->ct; 122 123 /* CONTROLLER_LOCKUP */ 124 if (ctlr->heartbeat == DDI_GET32(ctlr, &ctp->HeartBeat)) { 125 if (ctlr->lockup_logged == CPQARY3_FALSE) { 126 cmn_err(CE_WARN, "CPQary3 : " 127 "%s HBA firmware Locked !!!", ctlr->hba_name); 128 cmn_err(CE_WARN, "CPQary3 : " 129 "Please reboot the system"); 130 cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE); 131 if (ctlr->host_support & 0x4) 132 cpqary3_lockup_intr_onoff(ctlr, 133 CPQARY3_LOCKUP_INTR_DISABLE); 134 ctlr->controller_lockup = CPQARY3_TRUE; 135 ctlr->lockup_logged = CPQARY3_TRUE; 136 } 137 } 138 /* CONTROLLER_LOCKUP */ 139 no_cmds = (uint32_t)((ctlr->ctlr_maxcmds / 3) * 140 NO_OF_CMDLIST_IN_A_BLK); 141 mutex_enter(&ctlr->sw_mutex); 142 143 for (i = 0; i < no_cmds; i++) { 144 local = &ctlr->cmdmemlistp->pool[i]; 145 ASSERT(local != NULL); 146 pktp = MEM2PVTPKT(local); 147 148 if (!pktp) 149 continue; 150 151 if ((local->cmdpvt_flag == CPQARY3_TIMEOUT) || 152 (local->cmdpvt_flag == CPQARY3_RESET)) { 153 continue; 154 } 155 156 if (local->occupied == CPQARY3_OCCUPIED) { 157 scsi_pktp = pktp->scsi_cmd_pkt; 158 cpqary3_lbolt = ddi_get_lbolt(); 159 if ((scsi_pktp) && (scsi_pktp->pkt_time)) { 160 cpqary3_ticks = cpqary3_lbolt - 161 pktp->cmd_start_time; 162 163 if ((drv_hztousec(cpqary3_ticks)/1000000) > 164 scsi_pktp->pkt_time) { 165 scsi_pktp->pkt_reason = CMD_TIMEOUT; 166 scsi_pktp->pkt_statistics = 167 STAT_TIMEOUT; 168 scsi_pktp->pkt_state = STATE_GOT_BUS | 169 STATE_GOT_TARGET | STATE_SENT_CMD; 170 local->cmdpvt_flag = CPQARY3_TIMEOUT; 171 172 /* This should always be the case */ 173 if (scsi_pktp->pkt_comp) { 174 mutex_exit(&ctlr->sw_mutex); 175 (*scsi_pktp->pkt_comp) 176 (scsi_pktp); 177 mutex_enter(&ctlr->sw_mutex); 178 continue; 179 } 180 } 181 } 182 } 183 } 184 185 ctlr->heartbeat = DDI_GET32(ctlr, &ctp->HeartBeat); 186 mutex_exit(&ctlr->sw_mutex); 187 ctlr->tick_tmout_id = timeout(cpqary3_tick_hdlr, 188 (caddr_t)ctlr, drv_usectohz(CPQARY3_TICKTMOUT_VALUE)); 189 } 190 191 /* 192 * Function : cpqary3_init_ctlr_resource 193 * Description : This routine initializes the command list, initializes 194 * the controller, enables the interrupt. 195 * Called By : cpqary3_attach() 196 * Parameters : per_controller 197 * Calls : cpqary3_init_ctlr(), cpqary3_meminit(), 198 * cpqary3_intr_onoff(), 199 * Return Values: SUCCESS / FAILURE 200 * [ Shall return failure if any of the mandatory 201 * initializations / setup of resources fail ] 202 */ 203 uint16_t 204 cpqary3_init_ctlr_resource(cpqary3_t *ctlr) 205 { 206 #ifdef CPQARY3_DEBUG_MEM 207 int8_t i = 0; 208 #endif 209 210 /* 211 * Initialize the Controller 212 * Alocate Memory Pool for driver supported number of Commands 213 * return if not successful 214 * Allocate target structure for controller and initialize the same 215 * Detect all existing targets and allocate target structure for each 216 * Determine geometry for all existing targets 217 * Initialize the condition variables 218 */ 219 220 RETURN_FAILURE_IF_NULL(ctlr); 221 222 if (CPQARY3_FAILURE == cpqary3_init_ctlr(ctlr)) 223 return ((CPQARY3_FAILURE)); 224 225 if (CPQARY3_FAILURE == cpqary3_meminit(ctlr)) 226 return ((CPQARY3_FAILURE)); 227 228 229 #ifdef CPQARY3_DEBUG_MEM 230 /* 231 * This code is in place to test the memory management of this driver. 232 * This block of code allocates and de-allocates memory as many number 233 * of times as given in the for loop. 234 * After the for loop is executed, it returns a failure, which in turn 235 * would result in attach being failed. 236 */ 237 cmn_err(CE_CONT, "CPQary3 : _init_ctlr_resource : Testing memory \n"); 238 for (i = 0; i < 15; i++) { 239 if (CPQARY3_SUCCESS != cpqary3_meminit(ctlr)) { 240 cmn_err(CE_CONT, "CPQary3 : meminit failed : " 241 "attempt %d \n", i); 242 return (CPQARY3_FAILURE); 243 } 244 cmn_err(CE_CONT, 245 "CPQary3 : INIT successful : attempt %d \n", i); 246 cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE | 247 CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE); 248 cmn_err(CE_CONT, 249 "CPQary3 : FINI successful : attempt %d \n", i); 250 } 251 return (CPQARY3_FAILURE); 252 #endif 253 254 ctlr->cpqary3_tgtp[CTLR_SCSI_ID] = MEM_ZALLOC(sizeof (cpqary3_tgt_t)); 255 if (!(ctlr->cpqary3_tgtp[CTLR_SCSI_ID])) { 256 cmn_err(CE_WARN, "CPQary3: Target Initialization Failed"); 257 cpqary3_memfini(ctlr, CPQARY3_MEMLIST_DONE | 258 CPQARY3_PHYCTGS_DONE | CPQARY3_CMDMEM_DONE); 259 return (CPQARY3_FAILURE); 260 } 261 ctlr->cpqary3_tgtp[CTLR_SCSI_ID]->type = CPQARY3_TARGET_CTLR; 262 263 cpqary3_intr_onoff(ctlr, CPQARY3_INTR_DISABLE); 264 265 /* 266 * Initialize all condition variables : 267 * for the immediate call back 268 * for the disable noe 269 * for fulsh cache 270 * for probe device 271 */ 272 273 cv_init(&ctlr->cv_immediate_wait, NULL, CV_DRIVER, NULL); 274 cv_init(&ctlr->cv_noe_wait, NULL, CV_DRIVER, NULL); 275 cv_init(&ctlr->cv_flushcache_wait, NULL, CV_DRIVER, NULL); 276 cv_init(&ctlr->cv_abort_wait, NULL, CV_DRIVER, NULL); 277 cv_init(&ctlr->cv_ioctl_wait, NULL, CV_DRIVER, NULL); 278 279 return (CPQARY3_SUCCESS); 280 } 281 282 /* 283 * Function : cpqary3_target_geometry 284 * Description : This function returns the geometry for the target. 285 * Called By : cpqary3_getcap() 286 * Parameters : Target SCSI address 287 * Calls : None 288 * Return Values: Device Geometry 289 */ 290 int 291 cpqary3_target_geometry(struct scsi_address *sa) 292 { 293 cpqary3_t *ctlr = SA2CTLR(sa); 294 cpqary3_tgt_t *tgtp = ctlr->cpqary3_tgtp[SA2TGT(sa)]; 295 296 /* 297 * The target CHS are stored in the per-target structure 298 * during attach time. Use these values 299 */ 300 return ((tgtp->properties.drive.heads << 16) | 301 tgtp->properties.drive.sectors); 302 } 303 304 /* 305 * Function : cpqary3_synccmd_alloc 306 * Description : This function allocates the DMA buffer for the commands 307 * Called By : cpqary3_ioctl_send_bmiccmd(), 308 * cpqary3_ioctl_send_scsicmd() 309 * cpqary3_send_abortcmd(), cpqary3_flush_cache(), 310 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(), 311 * cpqary3_detect_target_geometry() 312 * Parameters : per_controller, buffer size 313 * Calls : cpqary3_alloc_phyctgs_mem(), cpqary3_cmdlist_occupy() 314 * Return Values: memp 315 */ 316 cpqary3_cmdpvt_t * 317 cpqary3_synccmd_alloc(cpqary3_t *cpqary3p, size_t bufsz) 318 { 319 cpqary3_private_t *cmddmah = NULL; 320 uint32_t dmabufpa = 0; /* XXX 32-bit pa? */ 321 cpqary3_cmdpvt_t *memp = NULL; 322 323 /* first, allocate any necessary dma buffers */ 324 if (bufsz > 0) { 325 cpqary3_phyctg_t *dmah = NULL; 326 caddr_t dmabufva = NULL; 327 328 /* first, allocate the command's dma handle */ 329 cmddmah = (cpqary3_private_t *)MEM_ZALLOC(sizeof (*cmddmah)); 330 if (cmddmah == NULL) { 331 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: " 332 "no memory for cmddmah"); 333 return (NULL); 334 } 335 336 /* next, allocate dma handle */ 337 dmah = (cpqary3_phyctg_t *)MEM_ZALLOC(sizeof (*dmah)); 338 if (dmah == NULL) { 339 MEM_SFREE(cmddmah, sizeof (*cmddmah)); 340 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: " 341 "no memory for dmah"); 342 return (NULL); 343 } 344 /* now, allocate dma buffer */ 345 dmabufva = cpqary3_alloc_phyctgs_mem(cpqary3p, bufsz, 346 &dmabufpa, dmah); 347 if (dmabufva == NULL) { 348 MEM_SFREE(cmddmah, sizeof (*cmddmah)); 349 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: " 350 "no memory for dma buf"); 351 return (NULL); 352 } 353 bzero(dmabufva, bufsz); 354 355 /* attach dma buffer to command dma handle */ 356 cmddmah->sg = dmabufva; 357 cmddmah->phyctgp = dmah; 358 } 359 360 /* next, allocate a command packet */ 361 memp = cpqary3_cmdlist_occupy(cpqary3p); 362 if (memp == NULL) { 363 if (cmddmah != NULL) { 364 cpqary3_free_phyctgs_mem(cmddmah->phyctgp, 365 CPQARY3_FREE_PHYCTG_MEM); 366 MEM_SFREE(cmddmah, sizeof (*cmddmah)); 367 } 368 cmn_err(CE_WARN, "cpqary3_synccmd_alloc: " 369 "cannot get free command"); 370 return (NULL); 371 } 372 memp->cmdpvt_flag = 0; 373 memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err = 374 CPQARY3_SYNCCMD_SUCCESS; 375 376 /* attach dma resources to command */ 377 memp->driverdata = cmddmah; 378 memp->cmdlist_memaddr->SG[0].Addr = dmabufpa; 379 memp->cmdlist_memaddr->SG[0].Len = (uint32_t)bufsz; 380 381 /* done */ 382 return (memp); 383 } 384 385 /* 386 * Function : cpqary3_synccmd_cleanup 387 * Description : This routine cleans up the command 388 * Called By : cpqary3_process_pkt(), cpqary3_synccmd_free() 389 * Parameters : per_command_memory 390 * Calls : cpqary3_free_phyctgs_mem(), cpqary3_cmdlist_release() 391 * Return Values: none 392 */ 393 void 394 cpqary3_synccmd_cleanup(cpqary3_cmdpvt_t *memp) 395 { 396 /* 397 * ordinary users should not call this routine 398 * (use cpqary3_synccmd_free() instead). this is 399 * for use ONLY by cpqary3_synccmd_free() and 400 * cpqary3_process_pkt(). 401 */ 402 403 if (memp->driverdata != NULL) { 404 /* free dma resources */ 405 cpqary3_free_phyctgs_mem(memp->driverdata->phyctgp, 406 CPQARY3_FREE_PHYCTG_MEM); 407 MEM_SFREE(memp->driverdata, sizeof (cpqary3_private_t)); 408 memp->driverdata = NULL; 409 } 410 /* release command */ 411 memp->cmdpvt_flag = 0; 412 cpqary3_cmdlist_release(memp, CPQARY3_HOLD_SW_MUTEX); 413 } 414 415 /* 416 * Function : cpqary3_synccmd_free 417 * Description : This routine frees the command and the 418 * associated resources. 419 * Called By : cpqary3_ioctl_send_bmiccmd(), 420 * cpqary3_ioctl_send_scsicmd() 421 * cpqary3_send_abortcmd(), cpqary3_flush_cache(), 422 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(), 423 * cpqary3_detect_target_geometry() 424 * Parameters : per_controller, per_command_memory 425 * Calls : cpqary3_synccmd_cleanup() 426 * Return Values: NONE 427 */ 428 void 429 cpqary3_synccmd_free(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp) 430 { 431 /* 432 * so, the user is done with this command packet. 433 * we have three possible scenarios here: 434 * 435 * 1) the command was never submitted to the controller 436 * 437 * or 438 * 439 * 2) the command has completed at the controller and has 440 * been fully processed by the interrupt processing 441 * mechanism and is no longer on the submitted or 442 * retrieve queues. 443 * 444 * or 445 * 446 * 3) the command is not yet complete at the controller, 447 * and/or hasn't made it through cpqary3_process_pkt() 448 * yet. 449 * 450 * For cases (1) and (2), we can go ahead and free the 451 * command and the associated resources. For case (3), we 452 * must mark the command as no longer needed, and let 453 * cpqary3_process_pkt() clean it up instead. 454 */ 455 456 mutex_enter(&(cpqary3p->sw_mutex)); 457 if (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) { 458 /* 459 * command is still pending (case #3 above). 460 * mark the command as abandoned and let 461 * cpqary3_process_pkt() clean it up. 462 */ 463 memp->cmdpvt_flag = CPQARY3_SYNC_TIMEOUT; 464 mutex_exit(&(cpqary3p->sw_mutex)); 465 return; 466 } 467 memp->cmdpvt_flag = 0; 468 mutex_exit(&(cpqary3p->sw_mutex)); 469 470 /* 471 * command was either never submitted or has completed 472 * (cases #1 and #2 above). so, clean it up. 473 */ 474 cpqary3_synccmd_cleanup(memp); 475 476 /* done */ 477 return; 478 479 } /* cpqary3_synccmd_free() */ 480 481 /* 482 * Function : cpqary3_synccmd_send 483 * Description : This routine sends the command to the controller 484 * Called By : cpqary3_ioctl_send_bmiccmd(), 485 * cpqary3_ioctl_send_scsicmd() 486 * cpqary3_send_abortcmd(), cpqary3_flush_cache(), 487 * cpqary3_probe4LVs(), cpqary3_probe4Tapes(), 488 * cpqary3_detect_target_geometry() 489 * Parameters : per_controller, per_command_memory, timeout value, 490 * flag(wait for reply) 491 * Calls : cpqary3_submit(), cpqary3_add2submitted_cmdq() 492 * Return Values: SUCCESS / FAILURE 493 */ 494 int 495 cpqary3_synccmd_send(cpqary3_t *cpqary3p, cpqary3_cmdpvt_t *memp, 496 clock_t timeoutms, int flags) 497 { 498 clock_t absto = 0; /* absolute timeout */ 499 int waitsig = 0; 500 int rc = 0; 501 kcondvar_t *cv = 0; 502 503 /* compute absolute timeout, if necessary */ 504 if (timeoutms > 0) 505 absto = ddi_get_lbolt() + drv_usectohz(timeoutms * 1000); 506 507 /* heed signals during wait? */ 508 if (flags & CPQARY3_SYNCCMD_SEND_WAITSIG) 509 waitsig = 1; 510 511 /* acquire the sw mutex for our wait */ 512 mutex_enter(&(cpqary3p->sw_mutex)); 513 514 /* submit command to controller */ 515 mutex_enter(&(cpqary3p->hw_mutex)); 516 517 memp->cmdpvt_flag = CPQARY3_SYNC_SUBMITTED; 518 memp->cmdlist_memaddr->Header.Tag.drvinfo_n_err = 519 CPQARY3_SYNCCMD_SUCCESS; 520 if (EIO == cpqary3_submit(cpqary3p, memp->cmdlist_phyaddr)) { 521 mutex_exit(&(cpqary3p->hw_mutex)); 522 mutex_exit(&(cpqary3p->sw_mutex)); 523 rc = -1; 524 return (rc); 525 } 526 mutex_exit(&(cpqary3p->hw_mutex)); 527 528 /* wait for command completion, timeout, or signal */ 529 while (memp->cmdpvt_flag == CPQARY3_SYNC_SUBMITTED) { 530 kmutex_t *mt = &(cpqary3p->sw_mutex); 531 532 cv = &(cpqary3p->cv_ioctl_wait); 533 /* wait with the request behavior */ 534 if (absto) { 535 clock_t crc; 536 if (waitsig) { 537 crc = cv_timedwait_sig(cv, mt, absto); 538 } else { 539 crc = cv_timedwait(cv, mt, absto); 540 } 541 if (crc > 0) 542 rc = 0; 543 else 544 rc = (-1); 545 } else { 546 if (waitsig) { 547 rc = cv_wait_sig(cv, mt); 548 if (rc > 0) 549 rc = 0; 550 else 551 rc = (-1); 552 } else { 553 cv_wait(cv, mt); 554 rc = 0; 555 } 556 } 557 558 559 /* 560 * if our wait was interrupted (timeout), 561 * then break here 562 */ 563 if (rc) { 564 break; 565 } 566 } 567 568 /* our wait is done, so release the sw mutex */ 569 mutex_exit(&(cpqary3p->sw_mutex)); 570 571 /* return the results */ 572 return (rc); 573 } 574 575 /* 576 * Function : cpqary3_detect_target_geometry 577 * Description : This function determines the geometry for all 578 * the existing targets for the controller. 579 * Called By : cpqary3_tgt_init() 580 * Parameters : per controller 581 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send() 582 * cpqary3_synccmd_free() 583 * Return Values: SUCCESS / FAILURE 584 * [ Shall return failure only if Memory constraints exist 585 * or controller does not respond ] 586 */ 587 int8_t 588 cpqary3_detect_target_geometry(cpqary3_t *ctlr) 589 { 590 int i; 591 int8_t ld_count = 0; 592 int8_t loop_cnt = 0; 593 IdLogDrive *idlogdrive; 594 CommandList_t *cmdlistp; 595 cpqary3_cmdpvt_t *cpqary3_cmdpvtp; 596 597 RETURN_FAILURE_IF_NULL(ctlr); 598 599 /* 600 * Occupy a Command List 601 * Allocate Memory for return data 602 * If error, RETURN 0. 603 * get the Request Block from the CommandList 604 * Fill in the Request Packet with the corresponding values 605 * Submit the Command and Poll for its completion 606 * If success, continue else RETURN 0 607 */ 608 609 /* Sync Changes */ 610 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(ctlr, sizeof (IdLogDrive)); 611 if (cpqary3_cmdpvtp == NULL) 612 return (CPQARY3_FAILURE); 613 614 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 615 idlogdrive = (IdLogDrive *)cpqary3_cmdpvtp->driverdata->sg; 616 /* Sync Changes */ 617 618 619 /* Update Cmd Header */ 620 cmdlistp->Header.SGList = 1; 621 cmdlistp->Header.SGTotal = 1; 622 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS; 623 624 /* Cmd Reques */ 625 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16; 626 cmdlistp->Request.CDB[0] = 0x26; 627 cmdlistp->Request.CDB[6] = BMIC_IDENTIFY_LOGICAL_DRIVE; 628 cmdlistp->Request.CDB[7] = (sizeof (IdLogDrive) >> 8) & 0xff; 629 cmdlistp->Request.CDB[8] = sizeof (IdLogDrive) & 0xff; 630 cmdlistp->Request.Type.Type = CISS_TYPE_CMD; 631 cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 632 cmdlistp->Request.Type.Direction = CISS_XFER_READ; 633 634 /* 635 * For all the Targets that exist, issue an IDENTIFY LOGICAL DRIVE. 636 * That returns values which includes the dsired Geometry also. 637 * Update the Geometry in the per-target structure. 638 * NOTE : When the loop is executed for i=controller's SCSI ID, just 639 * increament by one so that we are talking to the next logical 640 * drive in our per-target structure. 641 */ 642 643 /* 644 * Depending upon the value of the variable legacy_mapping 645 * set in cpqary3_attach(), 646 * the target mapping algorithm to be used by the driver is decided. 647 */ 648 649 if (ctlr->legacy_mapping == 1) { 650 loop_cnt = ((ctlr->num_of_targets > CTLR_SCSI_ID) ? 651 (ctlr->num_of_targets + 1) : (ctlr->num_of_targets)); 652 653 for (i = 0; i < loop_cnt; i++) { 654 if (i == CTLR_SCSI_ID) /* Go to Next logical target */ 655 i++; 656 657 bzero(idlogdrive, sizeof (IdLogDrive)); 658 cmdlistp->Request.CDB[1] = 659 ctlr->cpqary3_tgtp[i]->logical_id; 660 661 /* Always zero */ 662 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 663 664 /* 665 * Logical volume Id numbering scheme is as follows 666 * 0x00000, 0x00001, ... - for Direct Attached 667 * 0x10000, 0x10001, ... - If 1st Port of HBA is 668 * connected to MSA20 / MSA500 669 * 0x20000, 0x20001, ... - If 2nd Port of HBA is 670 * connected to MSA20 / MSA500 671 */ 672 cmdlistp->Header.LUN.PhysDev.Bus = 673 (ctlr->cpqary3_tgtp[i]->logical_id) >> 16; 674 cmdlistp->Header.LUN.PhysDev.Mode = 675 (cmdlistp->Header.LUN.PhysDev.Bus > 0) ? 676 MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR; 677 678 /* 679 * Submit the command 680 * Poll for its completion 681 * If polling is not successful, something is wrong 682 * with the controler 683 * Return FAILURE (No point in continuing if h/w is 684 * faulty !!!) 685 */ 686 687 /* PERF */ 688 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 689 /* PERF */ 690 691 /* Sync Changes */ 692 if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000, 693 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 694 /* Timed out */ 695 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp); 696 return (CPQARY3_FAILURE); 697 } 698 if ((cpqary3_cmdpvtp-> 699 cmdlist_memaddr->Header.Tag.drvinfo_n_err == 700 CPQARY3_SYNCCMD_FAILURE) && 701 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) { 702 DTRACE_PROBE1(id_logdrv_fail, 703 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop); 704 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp); 705 return (CPQARY3_FAILURE); 706 } 707 /* Sync Changes */ 708 709 ctlr->cpqary3_tgtp[i]->properties.drive.heads = 710 idlogdrive->heads; 711 ctlr->cpqary3_tgtp[i]->properties.drive.sectors = 712 idlogdrive->sectors; 713 714 DTRACE_PROBE2(tgt_geometry_detect, 715 int, i, IdLogDrive *, idlogdrive); 716 } 717 } else { 718 719 /* 720 * Fix for QXCR1000446657: Logical drives are re numbered 721 * after deleting a Logical drive. 722 * introduced, new variable ld_count, which gets 723 * incremented when the Target ID is found. 724 * And for i=controller's SCSI ID and LDs with holes are found, 725 * we continue talking to 726 * the next logical drive in the per-target structure 727 */ 728 729 for (i = 0; ld_count < ctlr->num_of_targets; i++) { 730 if (i == CTLR_SCSI_ID || 731 ctlr->cpqary3_tgtp[i] == NULL) 732 /* Go to the Next logical target */ 733 continue; 734 bzero(idlogdrive, sizeof (IdLogDrive)); 735 cmdlistp->Request.CDB[1] = 736 ctlr->cpqary3_tgtp[i]->logical_id; 737 /* Always zero */ 738 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 739 /* 740 * Logical volume Id numbering scheme is as follows 741 * 0x00000, 0x00001, ... - for Direct Attached 742 * 0x10000, 0x10001, ... - If 1st Port of HBA is 743 * connected to MSA20 / MSA500 744 * 0x20000, 0x20001, ... - If 2nd Port of HBA is 745 * connected to MSA20 / MSA500 746 */ 747 cmdlistp->Header.LUN.PhysDev.Bus = 748 (ctlr->cpqary3_tgtp[i]->logical_id) >> 16; 749 cmdlistp->Header.LUN.PhysDev.Mode = 750 (cmdlistp->Header.LUN.PhysDev.Bus > 0) ? 751 MASK_PERIPHERIAL_DEV_ADDR : PERIPHERIAL_DEV_ADDR; 752 /* PERF */ 753 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 754 /* PERF */ 755 756 /* 757 * Submit the command 758 * Poll for its completion 759 * If polling is not successful, something is wrong 760 * with the controler 761 * Return FAILURE (No point in continuing if h/w is 762 * faulty !!!) 763 */ 764 765 /* Sync Changes */ 766 if (cpqary3_synccmd_send(ctlr, cpqary3_cmdpvtp, 90000, 767 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 768 /* Timed out */ 769 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp); 770 return (CPQARY3_FAILURE); 771 } 772 if ((cpqary3_cmdpvtp-> 773 cmdlist_memaddr->Header.Tag.drvinfo_n_err == 774 CPQARY3_SYNCCMD_FAILURE) && 775 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 2)) { 776 DTRACE_PROBE1(id_logdrv_fail, 777 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop); 778 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp); 779 return (CPQARY3_FAILURE); 780 } 781 /* Sync Changes */ 782 783 ctlr->cpqary3_tgtp[i]->properties.drive.heads = 784 idlogdrive->heads; 785 ctlr->cpqary3_tgtp[i]->properties.drive.sectors = 786 idlogdrive->sectors; 787 788 DTRACE_PROBE2(tgt_geometry_detect, 789 int, i, IdLogDrive *, idlogdrive); 790 791 ld_count++; 792 } 793 } 794 795 /* Sync Changes */ 796 cpqary3_synccmd_free(ctlr, cpqary3_cmdpvtp); 797 /* Sync Changes */ 798 799 return (CPQARY3_SUCCESS); 800 } 801