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 * Copyright (c) 2016 by Delphix. All rights reserved. 15 */ 16 17 #include <sys/sdt.h> 18 #include "cpqary3.h" 19 20 /* 21 * Local Functions Definitions 22 */ 23 24 uint8_t cpqary3_format_unit(cpqary3_cmdpvt_t *); 25 26 static uint8_t cpqary3_probe4LVs(cpqary3_t *); 27 static uint8_t cpqary3_probe4Tapes(cpqary3_t *); 28 29 30 /* 31 * Function : cpqary3_probe4targets 32 * Description : This routine detects all existing logical drives 33 * and updates per target structure. 34 * Called By : cpqary3_tgt_init() 35 * Parameters : per-controller 36 * Calls : cpqary3_probe4LVs(), cpqary3_probe4Tapes() 37 * Return Values: SUCCESS/ FAILURE 38 * [Shall fail only if Memory Constraints exist, the 39 * controller is defective/does not respond] 40 */ 41 uint8_t 42 cpqary3_probe4targets(cpqary3_t *cpqary3p) 43 { 44 uint8_t rv; 45 46 rv = cpqary3_probe4LVs(cpqary3p); 47 48 if (CPQARY3_FAILURE == rv) { 49 return (rv); 50 } 51 52 rv = cpqary3_probe4Tapes(cpqary3p); 53 54 if (CPQARY3_FAILURE == rv) { 55 return (rv); 56 } 57 58 return (CPQARY3_SUCCESS); 59 60 } 61 62 /* 63 * Function : cpqary3_build_cmdlist 64 * Description : This routine builds the command list for the specific 65 * opcode. 66 * Called By : cpqary3_transport() 67 * Parameters : cmdlist pvt struct, target id as received by SA. 68 * Calls : None 69 * Return Values: SUCCESS : Build is successful 70 * FAILURE : Build has Failed 71 */ 72 uint8_t 73 cpqary3_build_cmdlist(cpqary3_cmdpvt_t *cpqary3_cmdpvtp, uint32_t tid) 74 { 75 int cntr; 76 cpqary3_t *cpqary3p; 77 struct buf *bfp; 78 cpqary3_tgt_t *tgtp; 79 CommandList_t *cmdlistp; 80 81 RETURN_FAILURE_IF_NULL(cpqary3_cmdpvtp); 82 83 if (NULL == (cpqary3p = cpqary3_cmdpvtp->ctlr)) 84 return (CPQARY3_FAILURE); 85 86 bfp = (struct buf *)cpqary3_cmdpvtp->pvt_pkt->bf; 87 88 tgtp = cpqary3p->cpqary3_tgtp[tid]; 89 90 if (!tgtp) { 91 return (CPQARY3_FAILURE); 92 } 93 94 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 95 96 /* Update Cmd Header */ 97 cmdlistp->Header.SGList = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt; 98 cmdlistp->Header.SGTotal = cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt; 99 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_OSCMD_SUCCESS; 100 101 if (tgtp->type == CPQARY3_TARGET_CTLR) { 102 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 103 cmdlistp->Header.LUN.PhysDev.Bus = 0; 104 cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR; 105 } else if (tgtp->type == CPQARY3_TARGET_LOG_VOL) { 106 cmdlistp->Header.LUN.LogDev.VolId = tgtp->logical_id; 107 cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR; 108 } else if (tgtp->type == CPQARY3_TARGET_TAPE) { 109 bcopy(&(tgtp->PhysID), &(cmdlistp->Header.LUN.PhysDev), 110 sizeof (PhysDevAddr_t)); 111 112 DTRACE_PROBE1(build_cmdlist_tape, CommandList_t *, cmdlistp); 113 } 114 115 /* Cmd Request */ 116 cmdlistp->Request.CDBLen = cpqary3_cmdpvtp->pvt_pkt->cdb_len; 117 118 bcopy((caddr_t)cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_cdbp, 119 (caddr_t)cmdlistp->Request.CDB, cpqary3_cmdpvtp->pvt_pkt->cdb_len); 120 121 122 cmdlistp->Request.Type.Type = CISS_TYPE_CMD; 123 cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED; 124 125 DTRACE_PROBE2(build_cmdlist_buf, struct buf *, bfp, 126 CommandList_t *, cmdlistp); 127 128 if (bfp && (bfp->b_flags & B_READ)) 129 cmdlistp->Request.Type.Direction = CISS_XFER_READ; 130 else if (bfp && (bfp->b_flags & B_WRITE)) 131 cmdlistp->Request.Type.Direction = CISS_XFER_WRITE; 132 else 133 cmdlistp->Request.Type.Direction = CISS_XFER_NONE; 134 /* 135 * Looks like the above Direction is going for a toss in case of 136 * MSA20(perticularly for 0x0a-write) connected to SMART Array. 137 * If the above check fails, the below switch should take care. 138 */ 139 140 switch (cmdlistp->Request.CDB[0]) { 141 case 0x08: 142 case 0x28: 143 cmdlistp->Request.Type.Direction = CISS_XFER_READ; 144 break; 145 case 0x0A: 146 case 0x2A: 147 cmdlistp->Request.Type.Direction = CISS_XFER_WRITE; 148 break; 149 } 150 /* 151 * NEED to increase this TimeOut value when the concerned 152 * targets are tape devices(i.e., we need to do it here manually). 153 */ 154 cmdlistp->Request.Timeout = 2 * 155 (cpqary3_cmdpvtp->pvt_pkt->scsi_cmd_pkt->pkt_time); 156 157 for (cntr = 0; cntr < cpqary3_cmdpvtp->pvt_pkt->cmd_cookiecnt; cntr++) { 158 cmdlistp->SG[cntr].Addr = 159 cpqary3_cmdpvtp->pvt_pkt-> 160 cmd_dmacookies[cntr].dmac_laddress; 161 cmdlistp->SG[cntr].Len = (uint32_t) 162 cpqary3_cmdpvtp->pvt_pkt->cmd_dmacookies[cntr].dmac_size; 163 } 164 165 return (CPQARY3_SUCCESS); 166 } 167 168 169 /* 170 * Function : cpqary3_send_abortcmd 171 * Description : Sends the Abort command to abort 172 * a set of cmds(on a target) or a cmdlist. 173 * Called By : cpqary3_abort 174 * Parameters : per controller, target_id, cmdlist to abort 175 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send(), 176 * cpqary3_synccmd_free() 177 * Return Values: SUCCESS - abort cmd submit is successful. 178 * FAILURE - Could not submit the abort cmd. 179 */ 180 uint8_t 181 cpqary3_send_abortcmd(cpqary3_t *cpqary3p, uint16_t target_id, 182 CommandList_t *cmdlist2abortp) 183 { 184 CommandList_t *cmdlistp; 185 cpqary3_tgt_t *cpqtgtp; 186 cpqary3_tag_t *cpqary3_tagp; 187 cpqary3_cmdpvt_t *cpqary3_cmdpvtp; 188 189 /* 190 * NOTE : DO NOT perform this operation for cmdlist2abortp. 191 * It may be NULL 192 */ 193 RETURN_FAILURE_IF_NULL(cpqary3p); 194 195 if (target_id == CTLR_SCSI_ID) 196 return (CPQARY3_FAILURE); 197 198 cpqtgtp = cpqary3p->cpqary3_tgtp[target_id]; 199 200 if (!cpqtgtp) { 201 return (CPQARY3_FAILURE); 202 } 203 204 /* 205 * Occupy the Command List 206 * Update the Command List accordingly 207 * Submit the command and wait for a signal 208 */ 209 210 /* BGB: CVFIX -> Introduced the call to cpqary3_synccmd_alloc */ 211 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, 0); 212 if (cpqary3_cmdpvtp == NULL) 213 return (CPQARY3_FAILURE); 214 215 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 216 217 cmdlistp->Header.SGList = 0; 218 cmdlistp->Header.SGTotal = 0; 219 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS; 220 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 221 cmdlistp->Header.LUN.PhysDev.Bus = 0; 222 cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR; 223 224 cmdlistp->Request.Type.Type = CISS_TYPE_MSG; 225 cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 226 cmdlistp->Request.Type.Direction = CISS_XFER_NONE; 227 cmdlistp->Request.Timeout = CISS_NO_TIMEOUT; 228 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16; 229 cmdlistp->Request.CDB[0] = CISS_MSG_ABORT; 230 231 if (cmdlist2abortp) { /* Abort this Particular Task */ 232 cmdlistp->Request.CDB[1] = CISS_ABORT_TASK; 233 cpqary3_tagp = (cpqary3_tag_t *)&cmdlistp->Request.CDB[4]; 234 cpqary3_tagp->drvinfo_n_err = 235 cmdlist2abortp->Header.Tag.drvinfo_n_err; 236 cpqary3_tagp->tag_value = cmdlist2abortp->Header.Tag.tag_value; 237 } else { /* Abort all tasks for this Target */ 238 cmdlistp->Request.CDB[1] = CISS_ABORT_TASKSET; 239 240 switch (cpqtgtp->type) { 241 case CPQARY3_TARGET_LOG_VOL: 242 cmdlistp->Header.LUN.LogDev.Mode = LOGICAL_VOL_ADDR; 243 cmdlistp->Header.LUN.LogDev.VolId = cpqtgtp->logical_id; 244 break; 245 case CPQARY3_TARGET_TAPE: 246 bcopy(&(cpqtgtp->PhysID), 247 &(cmdlistp->Header.LUN.PhysDev), 248 sizeof (PhysDevAddr_t)); 249 } 250 } 251 252 /* PERF */ 253 254 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 255 256 /* PERF */ 257 258 /* BGB: CVFIX -> Introduced a call to cpqary3_synccmd_send */ 259 if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 30000, 260 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 261 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 262 return (CPQARY3_FAILURE); 263 } 264 265 if (cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err == 266 CPQARY3_SYNCCMD_FAILURE) { 267 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 268 return (CPQARY3_FAILURE); 269 } 270 271 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 272 273 return (CPQARY3_SUCCESS); 274 275 } 276 277 278 /* 279 * Function : cpqary3_fulsh_cache 280 * Description : This routine flushes the controller cache. 281 * Called By : cpqary3_detach(), cpqary3_additional_cmd() 282 * Parameters : per controller 283 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send() 284 * cpqary3_synccmd_free() 285 * Return Values: None 286 */ 287 void 288 cpqary3_flush_cache(cpqary3_t *cpqary3p) 289 { 290 CommandList_t *cmdlistp; 291 cpqary3_cmdpvt_t *cpqary3_cmdpvtp; 292 293 /* 294 * Occupy the Command List 295 * Allocate Physically Contigous Memory for the FLUSH CACHE buffer 296 * Update the Command List accordingly 297 * Submit the command and wait for a signal 298 */ 299 300 ASSERT(cpqary3p != NULL); 301 302 /* grab a command and allocate a dma buffer */ 303 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, 304 sizeof (flushcache_buf_t)); 305 if (cpqary3_cmdpvtp == NULL) 306 return; 307 308 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 309 cmdlistp->Header.SGList = 1; 310 cmdlistp->Header.SGTotal = 1; 311 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS; 312 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 313 cmdlistp->Header.LUN.PhysDev.Bus = 0; 314 cmdlistp->Header.LUN.PhysDev.Mode = PERIPHERIAL_DEV_ADDR; 315 316 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_16; 317 cmdlistp->Request.Type.Type = CISS_TYPE_CMD; 318 cmdlistp->Request.Type.Attribute = CISS_ATTR_HEADOFQUEUE; 319 cmdlistp->Request.Type.Direction = CISS_XFER_WRITE; 320 cmdlistp->Request.Timeout = CISS_NO_TIMEOUT; 321 cmdlistp->Request.CDB[0] = ARRAY_WRITE; 322 cmdlistp->Request.CDB[6] = CISS_FLUSH_CACHE; /* 0xC2 */ 323 cmdlistp->Request.CDB[8] = 0x02; 324 325 /* PERF */ 326 327 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 328 329 /* PERF */ 330 331 if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000, 332 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 333 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 334 cmn_err(CE_WARN, "CPQary3 %s : Flush Cache Operation" 335 "Failed, Timeout", cpqary3p->hba_name); 336 return; 337 } 338 339 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 340 } 341 342 /* 343 * Function : cpqary3_probe4LVs 344 * Description : This routine probes for the logical drives 345 * configured on the HP Smart Array controllers 346 * Called By : cpqary3_probe4targets() 347 * Parameters : per controller 348 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send() 349 * cpqary3_synccmd_free() 350 * Return Values: None 351 */ 352 uint8_t 353 cpqary3_probe4LVs(cpqary3_t *cpqary3p) 354 { 355 ulong_t log_lun_no = 0; 356 ulong_t lun_id = 0; 357 ulong_t ld_count = 0; 358 ulong_t i = 0; 359 ulong_t cntr = 0; 360 uint32_t data_addr_len; 361 rll_data_t *rllp; 362 CommandList_t *cmdlistp; 363 cpqary3_cmdpvt_t *cpqary3_cmdpvtp; 364 365 /* 366 * Occupy the Command List 367 * Allocate Physically Contigous Memory 368 * Update the Command List for Report Logical LUNS (rll) Command 369 * This command detects all existing logical drives. 370 * Submit and Poll for completion 371 */ 372 373 RETURN_FAILURE_IF_NULL(cpqary3p); 374 375 /* Sync Changes */ 376 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rll_data_t)); 377 if (cpqary3_cmdpvtp == NULL) 378 return (CPQARY3_FAILURE); 379 380 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 381 rllp = (rll_data_t *)cpqary3_cmdpvtp->driverdata->sg; 382 383 cmdlistp->Header.SGList = 1; 384 cmdlistp->Header.SGTotal = 1; 385 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS; 386 cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR; 387 388 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12; 389 cmdlistp->Request.Timeout = CISS_NO_TIMEOUT; 390 cmdlistp->Request.Type.Type = CISS_TYPE_CMD; 391 cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED; 392 cmdlistp->Request.Type.Direction = CISS_XFER_READ; 393 cmdlistp->Request.CDB[0] = CISS_OPCODE_RLL; 394 395 data_addr_len = sizeof (rll_data_t); 396 397 cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff; 398 cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff; 399 cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff; 400 cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff; 401 402 DTRACE_PROBE2(rll_cmd_send, CommandList_t *, cmdlistp, 403 cpqary3_cmdpvt_t *, cpqary3_cmdpvtp); 404 405 /* PERF */ 406 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 407 /* PERF */ 408 409 if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000, 410 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 411 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 412 return (CPQARY3_FAILURE); 413 } 414 415 if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err == 416 CPQARY3_SYNCCMD_FAILURE) && 417 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 418 CISS_CMD_DATA_UNDERRUN)) { 419 cmn_err(CE_WARN, "CPQary3 : Probe for logical targets " 420 "returned ERROR !"); 421 DTRACE_PROBE1(rll_cmd_fail, 422 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop); 423 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 424 return (CPQARY3_FAILURE); 425 } 426 /* Sync Changes */ 427 428 log_lun_no = ((rllp->lunlist_byte0 + (rllp->lunlist_byte1 << 8) + 429 (rllp->lunlist_byte2 << 16) + (rllp->lunlist_byte3 << 24)) / 8); 430 431 DTRACE_PROBE2(rll_cmd_result, rll_data_t *, rllp, ulong_t, log_lun_no); 432 433 /* 434 * The following is to restrict the maximum number of supported logical 435 * volumes to 32. This is very important as controller support upto 128 436 * logical volumes and this driver implementation supports only 32. 437 */ 438 439 if (log_lun_no > MAX_LOGDRV) { 440 log_lun_no = MAX_LOGDRV; 441 } 442 443 cpqary3p->num_of_targets = log_lun_no; 444 DTRACE_PROBE1(update_lvlun_count, ulong_t, log_lun_no); 445 446 /* 447 * Update per target structure with relevant information 448 * CPQARY#_TGT_ALLIGNMENT is 1 because of the following mapping: 449 * Target IDs 0-6 in the OS = Logical Drives 0 - 6 in the HBA 450 * Target ID 7 in the OS = none in the HBA 451 * Target IDs 8-32 in the OS = Logical Drives 7 - 31 in the HBA 452 * Everytime we reference a logical drive with ID > 6, we shall use 453 * the alignment. 454 */ 455 456 457 /* 458 * Depending upon the value of the variable legacy_mapping set in 459 * cpqary3_attach(), 460 * the target mapping algorithm to be used by the driver is decided. 461 * 462 * If the value of legacy_mapping is set to one, in the case of 463 * Logical Drives with holes, 464 * Targets will be renumbered by the driver as shown below 465 * Below example makes the mapping logic clear. 466 * 467 * Logical Drive 0 in the HBA -> Target ID 0 i.e., cXt0dXsx 468 * Logical Drive 2 in the HBA -> Target ID 1 i.e., cXt1dXsX 469 * Logical Drive 3 in the HBA -> Target ID 2 i.e., cXt2dXsX 470 * 471 * If the value of legacy_mapping is not one, then the Logical 472 * Drive numbers will 473 * not be renumbered in the case of holes, and the mapping 474 * will be done as shown below 475 * This will be the default mapping from 1.80 cpqary3 driver. 476 * 477 * Logical Drive 0 in the HBA -> Target ID 0 i.e. cXt0dXsx 478 * Logical Drive 2 in the HBA -> Target ID 2 i.e. cXt2dXsX 479 * Logical Drive 3 in the HBA -> Target ID 3 i.e. cXt3dXsX 480 */ 481 482 483 if (cpqary3p->legacy_mapping == 1) { 484 for (cntr = 0; cntr < log_lun_no; cntr++) { 485 i = ((cntr < CTLR_SCSI_ID) ? 486 cntr : cntr + CPQARY3_TGT_ALIGNMENT); 487 if (!(cpqary3p->cpqary3_tgtp[i] = (cpqary3_tgt_t *) 488 MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) { 489 cmn_err(CE_WARN, "CPQary3 : Failed to Detect " 490 "targets, Memory Allocation Failure"); 491 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 492 return (CPQARY3_FAILURE); 493 } 494 495 cpqary3p->cpqary3_tgtp[i]->logical_id = 496 rllp->ll_data[cntr].logical_id; 497 498 cpqary3p->cpqary3_tgtp[i]->type = 499 CPQARY3_TARGET_LOG_VOL; 500 501 DTRACE_PROBE2(lvlun_remapped, 502 cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[i], 503 rpl_data_t *, &rllp->ll_data[cntr]); 504 } 505 } else { 506 /* 507 * Fix for QXCR1000446657: Logical drives are re numbered after 508 * deleting a Logical drive. 509 * We are using new indexing mechanism to fill the 510 * cpqary3_tgtp[], 511 * Check given during memory allocation of cpqary3_tgtp 512 * elements, so that memory is not re-allocated each time the 513 * cpqary3_probe4LVs() is called. 514 * Check given while freeing the memory of the cpqary3_tgtp[] 515 * elements, when a hole is found in the Logical Drives 516 * configured. 517 */ 518 519 /* ensure that the loop will break for cntr = 32 in any case */ 520 for (cntr = 0; ((ld_count < log_lun_no) && (cntr < MAX_LOGDRV)); 521 cntr++) { 522 i = ((cntr < CTLR_SCSI_ID) ? 523 cntr : cntr + CPQARY3_TGT_ALIGNMENT); 524 lun_id = (rllp->ll_data[ld_count].logical_id & 0xFFFF); 525 if (cntr != lun_id) { 526 if (cpqary3p->cpqary3_tgtp[i]) { 527 MEM_SFREE(cpqary3p->cpqary3_tgtp[i], 528 sizeof (cpqary3_tgt_t)); 529 cpqary3p->cpqary3_tgtp[i] = NULL; 530 } 531 } else { 532 if (cpqary3p->cpqary3_tgtp[i] == NULL && 533 !(cpqary3p->cpqary3_tgtp[i] = 534 (cpqary3_tgt_t *)MEM_ZALLOC( 535 sizeof (cpqary3_tgt_t)))) { 536 cmn_err(CE_WARN, 537 "CPQary3 : Failed to Detect " 538 "targets, Memory Allocation " 539 "Failure"); 540 /* Sync Changes */ 541 cpqary3_synccmd_free(cpqary3p, 542 cpqary3_cmdpvtp); 543 /* Sync Changes */ 544 return (CPQARY3_FAILURE); 545 } 546 cpqary3p->cpqary3_tgtp[i]->logical_id = 547 rllp->ll_data[ld_count].logical_id; 548 cpqary3p->cpqary3_tgtp[i]->type = 549 CPQARY3_TARGET_LOG_VOL; 550 551 /* 552 * Send "BMIC sense logical drive status 553 * command to set the target type to 554 * CPQARY3_TARGET_NONE in case of logical 555 * drive failure 556 */ 557 558 ld_count++; 559 } 560 } 561 562 } 563 564 /* HPQacucli Changes */ 565 for (; cntr < MAX_LOGDRV; cntr++) { 566 cpqary3_tgt_t *t; 567 i = ((cntr < CTLR_SCSI_ID) ? 568 cntr : cntr + CPQARY3_TGT_ALIGNMENT); 569 t = cpqary3p->cpqary3_tgtp[i]; 570 cpqary3p->cpqary3_tgtp[i] = NULL; 571 if (t) { 572 MEM_SFREE(t, sizeof (*t)); 573 } 574 } 575 /* HPQacucli Changes */ 576 577 /* Sync Changes */ 578 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 579 /* Sync Changes */ 580 581 return (CPQARY3_SUCCESS); 582 } 583 584 /* 585 * Function : cpqary3_probe4Tapes 586 * Description : This routine probes for the logical drives 587 * configured on the HP Smart Array controllers 588 * Called By : cpqary3_probe4targets() 589 * Parameters : per controller 590 * Calls : cpqary3_synccmd_alloc(), cpqary3_synccmd_send() 591 * cpqary3_synccmd_free() 592 * Return Values: None 593 */ 594 uint8_t 595 cpqary3_probe4Tapes(cpqary3_t *cpqary3p) 596 { 597 uint8_t phy_lun_no; 598 uint32_t ii = 0; 599 uint8_t cntr = 0; 600 uint32_t data_addr_len; 601 rpl_data_t *rplp; 602 CommandList_t *cmdlistp; 603 cpqary3_cmdpvt_t *cpqary3_cmdpvtp; 604 605 /* 606 * Occupy the Command List 607 * Allocate Physically Contigous Memory 608 * Update the Command List for Report Logical LUNS (rll) Command 609 * This command detects all existing logical drives. 610 * Submit and Poll for completion 611 */ 612 613 RETURN_FAILURE_IF_NULL(cpqary3p); 614 615 /* Sync Changes */ 616 cpqary3_cmdpvtp = cpqary3_synccmd_alloc(cpqary3p, sizeof (rpl_data_t)); 617 if (cpqary3_cmdpvtp == NULL) 618 return (CPQARY3_FAILURE); 619 620 cmdlistp = cpqary3_cmdpvtp->cmdlist_memaddr; 621 rplp = (rpl_data_t *)cpqary3_cmdpvtp->driverdata->sg; 622 623 /* Sync Changes */ 624 625 cmdlistp->Header.SGList = 1; 626 cmdlistp->Header.SGTotal = 1; 627 cmdlistp->Header.Tag.drvinfo_n_err = CPQARY3_SYNCCMD_SUCCESS; 628 cmdlistp->Header.LUN.PhysDev.TargetId = 0; 629 cmdlistp->Header.LUN.PhysDev.Bus = 0; 630 cmdlistp->Header.LUN.PhysDev.Mode = MASK_PERIPHERIAL_DEV_ADDR; 631 632 cmdlistp->Request.CDBLen = CPQARY3_CDBLEN_12; 633 cmdlistp->Request.Timeout = CISS_NO_TIMEOUT; 634 cmdlistp->Request.Type.Type = CISS_TYPE_CMD; 635 cmdlistp->Request.Type.Attribute = CISS_ATTR_ORDERED; 636 cmdlistp->Request.Type.Direction = CISS_XFER_READ; 637 cmdlistp->Request.CDB[0] = CISS_OPCODE_RPL; 638 639 data_addr_len = sizeof (rpl_data_t); 640 641 cmdlistp->Request.CDB[6] = (data_addr_len >> 24) & 0xff; 642 cmdlistp->Request.CDB[7] = (data_addr_len >> 16) & 0xff; 643 cmdlistp->Request.CDB[8] = (data_addr_len >> 8) & 0xff; 644 cmdlistp->Request.CDB[9] = (data_addr_len) & 0xff; 645 646 DTRACE_PROBE2(tape_probe_cmd_send, 647 CommandList_t *, cmdlistp, cpqary3_cmdpvt_t *, cpqary3_cmdpvtp); 648 649 /* PERF */ 650 cpqary3_cmdpvtp->complete = cpqary3_synccmd_complete; 651 /* PERF */ 652 653 /* Sync Changes */ 654 655 if (cpqary3_synccmd_send(cpqary3p, cpqary3_cmdpvtp, 90000, 656 CPQARY3_SYNCCMD_SEND_WAITSIG) != 0) { 657 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 658 return (CPQARY3_FAILURE); 659 } 660 661 if ((cpqary3_cmdpvtp->cmdlist_memaddr->Header.Tag.drvinfo_n_err == 662 CPQARY3_SYNCCMD_FAILURE) && 663 (cpqary3_cmdpvtp->errorinfop->CommandStatus != 664 CISS_CMD_DATA_UNDERRUN)) { 665 cmn_err(CE_WARN, "CPQary3 : Probe for physical targets " 666 "returned ERROR !"); 667 DTRACE_PROBE1(tape_probe_cmdfail, 668 ErrorInfo_t *, cpqary3_cmdpvtp->errorinfop); 669 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 670 return (CPQARY3_FAILURE); 671 } 672 /* Sync Changes */ 673 674 phy_lun_no = ((rplp->lunlist_byte0 + 675 (rplp->lunlist_byte1 << 8) + 676 (rplp->lunlist_byte2 << 16) + 677 (rplp->lunlist_byte3 << 24)) / 8); 678 679 /* 680 * Update per target structure with relevant information 681 * CPQARY3_TAPE_BASE is 33 because of the following mapping: 682 * Target IDs 0-6 in the OS = Logical Drives 0 - 6 in the HBA 683 * Target ID 7 in the OS = none in the HBA 684 * Target IDs 8-32 in the OS = Logical Drives 7 - 31 in the HBA 685 * Target IDs 33 and above are reserved for Tapes and hence we need 686 * the alignment. 687 */ 688 689 690 /* 691 * HP Smart Array SAS controllers with Firmware revsion 5.14 or 692 * later support 693 * 64 Logical drives. So we are checking 694 * if the controller is SAS or CISS and then assigning the value of the 695 * TAPE BASE accordingly 696 */ 697 698 if (cpqary3p->bddef->bd_flags & SA_BD_SAS) { 699 ii = 0x41; /* MAX_LOGDRV + 1 - 64 + 1 */ 700 } else { 701 ii = 0x21; /* MAX_LOGDRV + 1 - 32 + 1 */ 702 } 703 704 for (cntr = 0; cntr < phy_lun_no; cntr++) { 705 if (rplp->pl_data[cntr].Mode == CISS_PHYS_MODE) { 706 if (cpqary3p->cpqary3_tgtp[ii] == NULL && 707 !(cpqary3p->cpqary3_tgtp[ii] = 708 (cpqary3_tgt_t *) 709 MEM_ZALLOC(sizeof (cpqary3_tgt_t)))) { 710 cmn_err(CE_WARN, "CPQary3 : Failed to Detect " 711 "targets, Memory Allocation Failure"); 712 cpqary3_synccmd_free(cpqary3p, 713 cpqary3_cmdpvtp); 714 return (CPQARY3_FAILURE); 715 } 716 717 bcopy(&(rplp->pl_data[cntr]), 718 &(cpqary3p->cpqary3_tgtp[ii]->PhysID), 719 sizeof (PhysDevAddr_t)); 720 721 cpqary3p->cpqary3_tgtp[ii]->type = CPQARY3_TARGET_TAPE; 722 723 DTRACE_PROBE1(tape_discovered, 724 cpqary3_tgt_t *, cpqary3p->cpqary3_tgtp[ii]); 725 726 ii++; 727 } 728 } 729 730 /* Sync Changes */ 731 cpqary3_synccmd_free(cpqary3p, cpqary3_cmdpvtp); 732 /* Sync Changes */ 733 734 return (CPQARY3_SUCCESS); 735 736 } 737 738 /* 739 * Function : cpqary3_synccmd_complete 740 * Description : This routine processes the completed commands 741 * using the sync interface and 742 * initiates any callback that is needed. 743 * Called By : cpqary3_transport 744 * Parameters : per-command 745 * Calls : cpqary3_cmdlist_release, cpqary3_synccmd_cleanup 746 * Return Values: None 747 */ 748 void 749 cpqary3_synccmd_complete(cpqary3_cmdpvt_t *cpqary3_cmdpvtp) 750 { 751 cpqary3_t *cpqary3p; 752 753 ASSERT(cpqary3_cmdpvtp != NULL); 754 755 if (CPQARY3_TIMEOUT == cpqary3_cmdpvtp->cmdpvt_flag) { 756 cpqary3_cmdlist_release(cpqary3_cmdpvtp, CPQARY3_NO_MUTEX); 757 return; 758 } 759 760 cpqary3p = cpqary3_cmdpvtp->ctlr; 761 762 if (cpqary3_cmdpvtp->cmdpvt_flag == CPQARY3_SYNC_TIMEOUT) { 763 /* 764 * The submitter has abandoned this command, so we 765 * have to free the resources here. 766 */ 767 mutex_exit(&(cpqary3p->sw_mutex)); 768 cpqary3_synccmd_cleanup(cpqary3_cmdpvtp); 769 mutex_enter(&(cpqary3p->sw_mutex)); 770 } else { 771 /* submitter is waiting; wake it up */ 772 cpqary3_cmdpvtp->cmdpvt_flag = 0; 773 774 /* 775 * Fix for Flush Cache Operation Timed out issue: 776 * cv_signal() wakes up only one blocked thread. 777 * We need to use cv_broadcast which unblocks 778 * all the blocked threads() 779 */ 780 cv_broadcast(&(cpqary3p->cv_ioctl_wait)); 781 } 782 } 783