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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <fcntl.h> 34 #include <sys/stat.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <ctype.h> 38 #include <errno.h> 39 #include <assert.h> 40 #include <sys/scsi/impl/uscsi.h> 41 #include <sys/scsi/generic/commands.h> 42 #include <sys/scsi/impl/commands.h> 43 #include <sys/scsi/generic/sense.h> 44 #include <sys/scsi/generic/mode.h> 45 #include <sys/scsi/generic/status.h> 46 #include <sys/scsi/generic/inquiry.h> 47 #include <sys/scsi/adapters/scsi_vhci.h> 48 #include <sys/byteorder.h> 49 #include "common.h" 50 #include "errorcodes.h" 51 52 #define MAX_MODE_SENSE_LEN 0xffff 53 #define MAXLEN 1000 54 55 #define RETRY_PATHLIST 1 56 #define BYTES_PER_LINE 16 57 #define SCMD_UNKNOWN 0xff 58 59 #define SCSI_VHCI "/devices/scsi_vhci/" 60 #define SLASH "/" 61 #define DEV_PREFIX "/devices/" 62 #define DEV_PREFIX_STRLEN strlen(DEV_PREFIX) 63 #define DEVICES_DIR "/devices" 64 65 extern char *dtype[]; /* from adm.c */ 66 extern int rand_r(unsigned int *); 67 68 static int cleanup_dotdot_path(char *path); 69 static int wait_random_time(void); 70 static char *scsi_find_command_name(int cmd); 71 static void scsi_printerr(struct uscsi_cmd *ucmd, 72 struct scsi_extended_sense *rq, int rqlen, 73 char msg_string[], char *err_string); 74 static void string_dump(char *hdr, uchar_t *src, int nbytes, int format, 75 char msg_string[]); 76 static int issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag); 77 78 79 static int 80 wait_random_time(void) 81 { 82 time_t timeval; 83 struct tm *tmbuf = NULL; 84 struct timeval tval; 85 unsigned int seed; 86 int random; 87 pid_t pid; 88 89 /* 90 * Get the system time and use "system seconds" 91 * as 'seed' to generate a random number. Then, 92 * wait between 1/10 - 1/2 seconds before retry. 93 * Get the current process id and ex-or it with 94 * the seed so that the random number is always 95 * different even in case of multiple processes 96 * generate a random number at the same time. 97 */ 98 if ((timeval = time(NULL)) == -1) { 99 return (errno); 100 } 101 if ((tmbuf = localtime(&timeval)) == NULL) { 102 return (-1); /* L_LOCALTIME_ERROR */ 103 } 104 105 pid = getpid(); 106 107 /* get a random number. */ 108 seed = (unsigned int) tmbuf->tm_sec; 109 seed ^= pid; 110 random = rand_r(&seed); 111 112 113 random = ((random % 500) + 100) * MILLISEC; 114 tval.tv_sec = random / MICROSEC; 115 tval.tv_usec = random % MICROSEC; 116 117 if (select(0, NULL, NULL, NULL, &tval) == -1) { 118 return (-1); /* L_SELECT_ERROR */ 119 } 120 return (0); 121 } 122 123 /* 124 * Special string dump for error message 125 */ 126 static void 127 string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[]) 128 { 129 int i; 130 int n; 131 char *p; 132 char s[256]; 133 134 assert(format == HEX_ONLY || format == HEX_ASCII); 135 136 (void) strcpy(s, hdr); 137 for (p = s; *p; p++) { 138 *p = ' '; 139 } 140 141 p = hdr; 142 while (nbytes > 0) { 143 (void) sprintf(&msg_string[strlen(msg_string)], "%s", p); 144 p = s; 145 n = MIN(nbytes, BYTES_PER_LINE); 146 for (i = 0; i < n; i++) { 147 (void) sprintf(&msg_string[strlen(msg_string)], 148 "%02x ", src[i] & 0xff); 149 } 150 if (format == HEX_ASCII) { 151 for (i = BYTES_PER_LINE-n; i > 0; i--) { 152 (void) sprintf(&msg_string[strlen(msg_string)], 153 " "); 154 } 155 (void) sprintf(&msg_string[strlen(msg_string)], 156 " "); 157 for (i = 0; i < n; i++) { 158 (void) sprintf(&msg_string[strlen(msg_string)], 159 "%c", isprint(src[i]) ? src[i] : '.'); 160 } 161 } 162 (void) sprintf(&msg_string[strlen(msg_string)], "\n"); 163 nbytes -= n; 164 src += n; 165 } 166 } 167 /* 168 * Return a pointer to a string telling us the name of the command. 169 */ 170 static char * 171 scsi_find_command_name(int cmd) 172 { 173 /* 174 * Names of commands. Must have SCMD_UNKNOWN at end of list. 175 */ 176 struct scsi_command_name { 177 int command; 178 char *name; 179 } scsi_command_names[29]; 180 181 register struct scsi_command_name *c; 182 183 scsi_command_names[0].command = SCMD_TEST_UNIT_READY; 184 scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready"); 185 186 scsi_command_names[1].command = SCMD_FORMAT; 187 scsi_command_names[1].name = MSGSTR(110, "Format"); 188 189 scsi_command_names[2].command = SCMD_REASSIGN_BLOCK; 190 scsi_command_names[2].name = MSGSTR(77, "Reassign Block"); 191 192 scsi_command_names[3].command = SCMD_READ; 193 scsi_command_names[3].name = MSGSTR(27, "Read"); 194 195 scsi_command_names[4].command = SCMD_WRITE; 196 scsi_command_names[4].name = MSGSTR(54, "Write"); 197 198 scsi_command_names[5].command = SCMD_READ_G1; 199 scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)"); 200 201 scsi_command_names[6].command = SCMD_WRITE_G1; 202 scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)"); 203 204 scsi_command_names[7].command = SCMD_MODE_SELECT; 205 scsi_command_names[7].name = MSGSTR(97, "Mode Select"); 206 207 scsi_command_names[8].command = SCMD_MODE_SENSE; 208 scsi_command_names[8].name = MSGSTR(95, "Mode Sense"); 209 210 scsi_command_names[9].command = SCMD_REASSIGN_BLOCK; 211 scsi_command_names[9].name = MSGSTR(77, "Reassign Block"); 212 213 scsi_command_names[10].command = SCMD_REQUEST_SENSE; 214 scsi_command_names[10].name = MSGSTR(74, "Request Sense"); 215 216 scsi_command_names[11].command = SCMD_READ_DEFECT_LIST; 217 scsi_command_names[11].name = MSGSTR(80, "Read Defect List"); 218 219 scsi_command_names[12].command = SCMD_INQUIRY; 220 scsi_command_names[12].name = MSGSTR(102, "Inquiry"); 221 222 scsi_command_names[13].command = SCMD_WRITE_BUFFER; 223 scsi_command_names[13].name = MSGSTR(53, "Write Buffer"); 224 225 scsi_command_names[14].command = SCMD_READ_BUFFER; 226 scsi_command_names[14].name = MSGSTR(82, "Read Buffer"); 227 228 scsi_command_names[15].command = SCMD_START_STOP; 229 scsi_command_names[15].name = MSGSTR(67, "Start/Stop"); 230 231 scsi_command_names[16].command = SCMD_RESERVE; 232 scsi_command_names[16].name = MSGSTR(72, "Reserve"); 233 234 scsi_command_names[17].command = SCMD_RELEASE; 235 scsi_command_names[17].name = MSGSTR(75, "Release"); 236 237 scsi_command_names[18].command = SCMD_MODE_SENSE_G1; 238 scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)"); 239 240 scsi_command_names[19].command = SCMD_MODE_SELECT_G1; 241 scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)"); 242 243 scsi_command_names[20].command = SCMD_READ_CAPACITY; 244 scsi_command_names[20].name = MSGSTR(81, "Read Capacity"); 245 246 scsi_command_names[21].command = SCMD_SYNC_CACHE; 247 scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache"); 248 249 scsi_command_names[22].command = SCMD_READ_DEFECT_LIST; 250 scsi_command_names[22].name = MSGSTR(80, "Read Defect List"); 251 252 scsi_command_names[23].command = SCMD_GDIAG; 253 scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic"); 254 255 scsi_command_names[24].command = SCMD_SDIAG; 256 scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic"); 257 258 scsi_command_names[25].command = SCMD_PERS_RESERV_IN; 259 scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In"); 260 261 scsi_command_names[26].command = SCMD_PERS_RESERV_OUT; 262 scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out"); 263 264 scsi_command_names[27].command = SCMD_LOG_SENSE; 265 scsi_command_names[27].name = MSGSTR(10502, "Log Sense"); 266 267 scsi_command_names[28].command = SCMD_UNKNOWN; 268 scsi_command_names[28].name = MSGSTR(25, "Unknown"); 269 270 271 for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++) 272 if (c->command == cmd) 273 break; 274 return (c->name); 275 } 276 277 278 /* 279 * Function to create error message containing 280 * scsi request sense information 281 */ 282 283 static void 284 scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, 285 int rqlen, char msg_string[], char *err_string) 286 { 287 int blkno; 288 289 switch (rq->es_key) { 290 case KEY_NO_SENSE: 291 (void) sprintf(msg_string, MSGSTR(91, "No sense error")); 292 break; 293 case KEY_RECOVERABLE_ERROR: 294 (void) sprintf(msg_string, MSGSTR(76, "Recoverable error")); 295 break; 296 case KEY_NOT_READY: 297 (void) sprintf(msg_string, 298 MSGSTR(10503, 299 "Device Not ready. Error: Random Retry Failed: %s\n."), 300 err_string); 301 break; 302 case KEY_MEDIUM_ERROR: 303 (void) sprintf(msg_string, MSGSTR(99, "Medium error")); 304 break; 305 case KEY_HARDWARE_ERROR: 306 (void) sprintf(msg_string, MSGSTR(106, "Hardware error")); 307 break; 308 case KEY_ILLEGAL_REQUEST: 309 (void) sprintf(msg_string, MSGSTR(103, "Illegal request")); 310 break; 311 case KEY_UNIT_ATTENTION: 312 (void) sprintf(msg_string, 313 MSGSTR(10504, 314 "Unit attention." 315 "Error: Random Retry Failed.\n")); 316 break; 317 case KEY_WRITE_PROTECT: 318 (void) sprintf(msg_string, MSGSTR(52, "Write protect error")); 319 break; 320 case KEY_BLANK_CHECK: 321 (void) sprintf(msg_string, MSGSTR(131, "Blank check error")); 322 break; 323 case KEY_VENDOR_UNIQUE: 324 (void) sprintf(msg_string, MSGSTR(58, "Vendor unique error")); 325 break; 326 case KEY_COPY_ABORTED: 327 (void) sprintf(msg_string, MSGSTR(123, "Copy aborted error")); 328 break; 329 case KEY_ABORTED_COMMAND: 330 (void) sprintf(msg_string, 331 MSGSTR(10505, 332 "Aborted command. Error: Random Retry Failed.\n")); 333 break; 334 case KEY_EQUAL: 335 (void) sprintf(msg_string, MSGSTR(117, "Equal error")); 336 break; 337 case KEY_VOLUME_OVERFLOW: 338 (void) sprintf(msg_string, MSGSTR(57, "Volume overflow")); 339 break; 340 case KEY_MISCOMPARE: 341 (void) sprintf(msg_string, MSGSTR(98, "Miscompare error")); 342 break; 343 case KEY_RESERVED: 344 (void) sprintf(msg_string, MSGSTR(10506, 345 "Reserved value found")); 346 break; 347 default: 348 (void) sprintf(msg_string, MSGSTR(59, "Unknown error")); 349 break; 350 } 351 352 (void) sprintf(&msg_string[strlen(msg_string)], 353 MSGSTR(10507, " during: %s"), 354 scsi_find_command_name(ucmd->uscsi_cdb[0])); 355 356 if (rq->es_valid) { 357 blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) | 358 (rq->es_info_3 << 8) | rq->es_info_4; 359 (void) sprintf(&msg_string[strlen(msg_string)], 360 MSGSTR(49, ": block %d (0x%x)"), blkno, blkno); 361 } 362 363 (void) sprintf(&msg_string[strlen(msg_string)], "\n"); 364 365 if (rq->es_add_len >= 6) { 366 (void) sprintf(&msg_string[strlen(msg_string)], 367 MSGSTR(132, " Additional sense: 0x%x " 368 "ASC Qualifier: 0x%x\n"), 369 rq->es_add_code, rq->es_qual_code); 370 /* 371 * rq->es_add_info[ADD_SENSE_CODE], 372 * rq->es_add_info[ADD_SENSE_QUAL_CODE]); 373 */ 374 } 375 if (rq->es_key == KEY_ILLEGAL_REQUEST) { 376 string_dump(MSGSTR(47, " cmd: "), (uchar_t *)ucmd, 377 sizeof (struct uscsi_cmd), HEX_ONLY, msg_string); 378 string_dump(MSGSTR(48, " cdb: "), 379 (uchar_t *)ucmd->uscsi_cdb, 380 ucmd->uscsi_cdblen, HEX_ONLY, msg_string); 381 } 382 string_dump(MSGSTR(43, " sense: "), 383 (uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY, msg_string); 384 rqlen = rqlen; /* not used */ 385 } 386 387 388 /* 389 * Execute a command and determine the result. 390 */ 391 static int 392 issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag) 393 { 394 struct scsi_extended_sense *rqbuf; 395 int status, i, retry_cnt = 0, err; 396 char errorMsg[MAXLEN]; 397 398 /* 399 * Set function flags for driver. 400 * 401 * Set Automatic request sense enable 402 * 403 */ 404 command->uscsi_flags = USCSI_RQENABLE; 405 command->uscsi_flags |= flag; 406 407 /* intialize error message array */ 408 errorMsg[0] = '\0'; 409 410 /* print command for debug */ 411 if (getenv("_LUX_S_DEBUG") != NULL) { 412 if ((command->uscsi_cdb == NULL) || 413 (flag & USCSI_RESET) || 414 (flag & USCSI_RESET_ALL)) { 415 if (flag & USCSI_RESET) { 416 (void) printf(" Issuing a SCSI Reset.\n"); 417 } 418 if (flag & USCSI_RESET_ALL) { 419 (void) printf(" Issuing a SCSI Reset All.\n"); 420 } 421 422 } else { 423 (void) printf(" Issuing the following " 424 "SCSI command: %s\n", 425 scsi_find_command_name(command->uscsi_cdb[0])); 426 (void) printf(" fd=0x%x cdb=", file); 427 for (i = 0; i < (int)command->uscsi_cdblen; i++) { 428 (void) printf("%x ", *(command->uscsi_cdb + i)); 429 } 430 (void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x" 431 " flags=0x%x\n", 432 command->uscsi_cdblen, 433 command->uscsi_bufaddr, 434 command->uscsi_buflen, command->uscsi_flags); 435 436 if ((command->uscsi_buflen > 0) && 437 ((flag & USCSI_READ) == 0)) { 438 (void) dump_hex_data(" Buffer data: ", 439 (uchar_t *)command->uscsi_bufaddr, 440 MIN(command->uscsi_buflen, 512), HEX_ASCII); 441 } 442 } 443 (void) fflush(stdout); 444 } 445 446 447 /* 448 * Default command timeout in case command left it 0 449 */ 450 if (command->uscsi_timeout == 0) { 451 command->uscsi_timeout = 60; 452 } 453 /* Issue command - finally */ 454 455 retry: 456 status = ioctl(file, USCSICMD, command); 457 if (status == 0 && command->uscsi_status == 0) { 458 if (getenv("_LUX_S_DEBUG") != NULL) { 459 if ((command->uscsi_buflen > 0) && 460 (flag & USCSI_READ)) { 461 (void) dump_hex_data("\tData read:", 462 (uchar_t *)command->uscsi_bufaddr, 463 MIN(command->uscsi_buflen, 512), HEX_ASCII); 464 } 465 } 466 return (status); 467 } 468 if ((status != 0) && (command->uscsi_status == 0)) { 469 if ((getenv("_LUX_S_DEBUG") != NULL) || 470 (getenv("_LUX_ER_DEBUG") != NULL)) { 471 (void) printf("Unexpected USCSICMD ioctl error: %s\n", 472 strerror(errno)); 473 } 474 return (status); 475 } 476 477 /* 478 * Just a SCSI error, create error message 479 * Retry once for Unit Attention, 480 * Not Ready, and Aborted Command 481 */ 482 if ((command->uscsi_rqbuf != NULL) && 483 (((char)command->uscsi_rqlen - (char)command->uscsi_rqresid) > 0)) { 484 485 rqbuf = (struct scsi_extended_sense *)command->uscsi_rqbuf; 486 487 switch (rqbuf->es_key) { 488 case KEY_NOT_READY: 489 if (retry_cnt++ < 1) { 490 ER_DPRINTF("Note: Device Not Ready." 491 " Retrying...\n"); 492 493 if ((err = wait_random_time()) == 0) { 494 goto retry; 495 } else { 496 return (err); 497 } 498 } 499 break; 500 501 case KEY_UNIT_ATTENTION: 502 if (retry_cnt++ < 1) { 503 ER_DPRINTF(" cmd():" 504 " UNIT_ATTENTION: Retrying...\n"); 505 506 goto retry; 507 } 508 break; 509 510 case KEY_ABORTED_COMMAND: 511 if (retry_cnt++ < 1) { 512 ER_DPRINTF("Note: Command is aborted." 513 " Retrying...\n"); 514 515 goto retry; 516 } 517 break; 518 } 519 if ((getenv("_LUX_S_DEBUG") != NULL) || 520 (getenv("_LUX_ER_DEBUG") != NULL)) { 521 scsi_printerr(command, 522 (struct scsi_extended_sense *)command->uscsi_rqbuf, 523 (command->uscsi_rqlen - command->uscsi_rqresid), 524 errorMsg, strerror(errno)); 525 } 526 527 } else { 528 529 /* 530 * Retry 5 times in case of BUSY, and only 531 * once for Reservation-conflict, Command 532 * Termination and Queue Full. Wait for 533 * random amount of time (between 1/10 - 1/2 secs.) 534 * between each retry. This random wait is to avoid 535 * the multiple threads being executed at the same time 536 * and also the constraint in Photon IB, where the 537 * command queue has a depth of one command. 538 */ 539 switch ((uchar_t)command->uscsi_status & STATUS_MASK) { 540 case STATUS_BUSY: 541 if (retry_cnt++ < 5) { 542 if ((err = wait_random_time()) == 0) { 543 R_DPRINTF(" cmd(): No. of retries %d." 544 " STATUS_BUSY: Retrying...\n", 545 retry_cnt); 546 goto retry; 547 548 } else { 549 return (err); 550 } 551 } 552 break; 553 554 case STATUS_RESERVATION_CONFLICT: 555 if (retry_cnt++ < 1) { 556 if ((err = wait_random_time()) == 0) { 557 R_DPRINTF(" cmd():" 558 " RESERVATION_CONFLICT:" 559 " Retrying...\n"); 560 goto retry; 561 562 } else { 563 return (err); 564 } 565 } 566 break; 567 568 case STATUS_TERMINATED: 569 if (retry_cnt++ < 1) { 570 R_DPRINTF("Note: Command Terminated." 571 " Retrying...\n"); 572 573 if ((err = wait_random_time()) == 0) { 574 goto retry; 575 } else { 576 return (err); 577 } 578 } 579 break; 580 581 case STATUS_QFULL: 582 if (retry_cnt++ < 1) { 583 R_DPRINTF("Note: Command Queue is full." 584 " Retrying...\n"); 585 586 if ((err = wait_random_time()) == 0) { 587 goto retry; 588 } else { 589 return (err); 590 } 591 } 592 break; 593 } 594 595 } 596 if (((getenv("_LUX_S_DEBUG") != NULL) || 597 (getenv("_LUX_ER_DEBUG") != NULL)) && 598 (errorMsg[0] != '\0')) { 599 (void) fprintf(stdout, " %s\n", errorMsg); 600 } 601 return (L_SCSI_ERROR | command->uscsi_status); 602 } 603 604 /* 605 * MODE SENSE USCSI command 606 * 607 * 608 * pc = page control field 609 * page_code = Pages to return 610 */ 611 int 612 scsi_mode_sense_cmd(int fd, 613 uchar_t *buf_ptr, 614 int buf_len, 615 uchar_t pc, 616 uchar_t page_code) 617 { 618 struct uscsi_cmd ucmd; 619 /* 10 byte Mode Select cmd */ 620 union scsi_cdb cdb = {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 621 struct scsi_extended_sense sense; 622 int status; 623 static int uscsi_count; 624 625 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 626 return (-1); /* L_INVALID_ARG */ 627 } 628 629 (void) memset(buf_ptr, 0, buf_len); 630 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 631 /* Just for me - a sanity check */ 632 if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) || 633 (buf_len > MAX_MODE_SENSE_LEN)) { 634 return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */ 635 } 636 cdb.g1_addr3 = (pc << 6) + page_code; 637 cdb.g1_count1 = buf_len>>8; 638 cdb.g1_count0 = buf_len & 0xff; 639 ucmd.uscsi_cdb = (caddr_t)&cdb; 640 ucmd.uscsi_cdblen = CDB_GROUP1; 641 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 642 ucmd.uscsi_buflen = buf_len; 643 ucmd.uscsi_rqbuf = (caddr_t)&sense; 644 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 645 ucmd.uscsi_timeout = 120; 646 647 status = issue_uscsi_cmd(fd, &ucmd, USCSI_READ); 648 /* Bytes actually transfered */ 649 if (status == 0) { 650 uscsi_count = buf_len - ucmd.uscsi_resid; 651 S_DPRINTF(" Number of bytes read on " 652 "Mode Sense 0x%x\n", uscsi_count); 653 if (getenv("_LUX_D_DEBUG") != NULL) { 654 (void) dump_hex_data(" Mode Sense data: ", buf_ptr, 655 uscsi_count, HEX_ASCII); 656 } 657 } 658 return (status); 659 } 660 661 int 662 scsi_release(char *path) 663 { 664 struct uscsi_cmd ucmd; 665 union scsi_cdb cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0}; 666 struct scsi_extended_sense sense; 667 int fd, status; 668 669 P_DPRINTF(" scsi_release: Release: Path %s\n", path); 670 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) 671 return (1); 672 673 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 674 675 ucmd.uscsi_cdb = (caddr_t)&cdb; 676 ucmd.uscsi_cdblen = CDB_GROUP0; 677 ucmd.uscsi_bufaddr = NULL; 678 ucmd.uscsi_buflen = 0; 679 ucmd.uscsi_rqbuf = (caddr_t)&sense; 680 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 681 ucmd.uscsi_timeout = 60; 682 status = (issue_uscsi_cmd(fd, &ucmd, 0)); 683 684 (void) close(fd); 685 return (status); 686 } 687 688 int 689 scsi_reserve(char *path) 690 { 691 struct uscsi_cmd ucmd; 692 union scsi_cdb cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0}; 693 struct scsi_extended_sense sense; 694 int fd, status; 695 696 P_DPRINTF(" scsi_reserve: Reserve: Path %s\n", path); 697 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) 698 return (1); 699 700 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 701 702 ucmd.uscsi_cdb = (caddr_t)&cdb; 703 ucmd.uscsi_cdblen = CDB_GROUP0; 704 ucmd.uscsi_bufaddr = NULL; 705 ucmd.uscsi_buflen = 0; 706 ucmd.uscsi_rqbuf = (caddr_t)&sense; 707 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 708 ucmd.uscsi_timeout = 60; 709 status = (issue_uscsi_cmd(fd, &ucmd, 0)); 710 711 (void) close(fd); 712 return (status); 713 } 714 715 /* 716 * Print out fabric dev dtype 717 */ 718 void 719 print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, 720 uchar_t dtype_prop) 721 { 722 if ((dtype_prop & DTYPE_MASK) < 0x10) { 723 (void) fprintf(stdout, " 0x%-2x (%s)\n", 724 (dtype_prop & DTYPE_MASK), 725 dtype[(dtype_prop & DTYPE_MASK)]); 726 } else if ((dtype_prop & DTYPE_MASK) < 0x1f) { 727 (void) fprintf(stdout, 728 MSGSTR(2096, " 0x%-2x (Reserved)\n"), 729 (dtype_prop & DTYPE_MASK)); 730 } else { 731 /* Check to see if this is the HBA */ 732 if (wwnConversion(hba_port_wwn) != wwnConversion(port_wwn)) { 733 (void) fprintf(stdout, MSGSTR(2097, 734 " 0x%-2x (Unknown Type)\n"), 735 (dtype_prop & DTYPE_MASK)); 736 } else { 737 /* MATCH */ 738 (void) fprintf(stdout, MSGSTR(2241, 739 " 0x%-2x (Unknown Type,Host Bus Adapter)\n"), 740 (dtype_prop & DTYPE_MASK)); 741 } 742 } 743 } 744 745 746 void 747 print_inq_data(char *arg_path, char *path, L_inquiry inq, uchar_t *serial, 748 size_t serial_len) 749 { 750 char **p; 751 uchar_t *v_parm; 752 int scsi_3, length; 753 char byte_number[MAXNAMELEN]; 754 static char *scsi_inquiry_labels_2[21]; 755 static char *scsi_inquiry_labels_3[22]; 756 #define MAX_ANSI_VERSION 6 757 static char *ansi_version[MAX_ANSI_VERSION]; 758 /* 759 * Intialize scsi_inquiry_labels_2 with i18n strings 760 */ 761 scsi_inquiry_labels_2[0] = MSGSTR(138, "Vendor: "); 762 scsi_inquiry_labels_2[1] = MSGSTR(149, "Product: "); 763 scsi_inquiry_labels_2[2] = MSGSTR(139, "Revision: "); 764 scsi_inquiry_labels_2[3] = MSGSTR(143, "Firmware Revision "); 765 scsi_inquiry_labels_2[4] = MSGSTR(144, "Serial Number "); 766 scsi_inquiry_labels_2[5] = MSGSTR(140, "Device type: "); 767 scsi_inquiry_labels_2[6] = MSGSTR(145, "Removable media: "); 768 scsi_inquiry_labels_2[7] = MSGSTR(146, "ISO version: "); 769 scsi_inquiry_labels_2[8] = MSGSTR(147, "ECMA version: "); 770 scsi_inquiry_labels_2[9] = MSGSTR(148, "ANSI version: "); 771 scsi_inquiry_labels_2[10] = 772 MSGSTR(2168, "Async event notification: "); 773 scsi_inquiry_labels_2[11] = 774 MSGSTR(2169, "Terminate i/o process msg: "); 775 scsi_inquiry_labels_2[12] = MSGSTR(150, "Response data format: "); 776 scsi_inquiry_labels_2[13] = MSGSTR(151, "Additional length: "); 777 scsi_inquiry_labels_2[14] = MSGSTR(152, "Relative addressing: "); 778 scsi_inquiry_labels_2[15] = 779 MSGSTR(2170, "32 bit transfers: "); 780 scsi_inquiry_labels_2[16] = 781 MSGSTR(2171, "16 bit transfers: "); 782 scsi_inquiry_labels_2[17] = 783 MSGSTR(2172, "Synchronous transfers: "); 784 scsi_inquiry_labels_2[18] = MSGSTR(153, "Linked commands: "); 785 scsi_inquiry_labels_2[19] = MSGSTR(154, "Command queueing: "); 786 scsi_inquiry_labels_2[20] = 787 MSGSTR(2173, "Soft reset option: "); 788 789 /* 790 * Intialize scsi_inquiry_labels_3 with i18n strings 791 */ 792 scsi_inquiry_labels_3[0] = MSGSTR(138, "Vendor: "); 793 scsi_inquiry_labels_3[1] = MSGSTR(149, "Product: "); 794 scsi_inquiry_labels_3[2] = MSGSTR(139, "Revision: "); 795 scsi_inquiry_labels_3[3] = MSGSTR(143, "Firmware Revision "); 796 scsi_inquiry_labels_3[4] = MSGSTR(144, "Serial Number "); 797 scsi_inquiry_labels_3[5] = MSGSTR(140, "Device type: "); 798 scsi_inquiry_labels_3[6] = MSGSTR(145, "Removable media: "); 799 scsi_inquiry_labels_3[7] = MSGSTR(2174, "Medium Changer Element: "); 800 scsi_inquiry_labels_3[8] = MSGSTR(146, "ISO version: "); 801 scsi_inquiry_labels_3[9] = MSGSTR(147, "ECMA version: "); 802 scsi_inquiry_labels_3[10] = MSGSTR(148, "ANSI version: "); 803 scsi_inquiry_labels_3[11] = 804 MSGSTR(2175, "Async event reporting: "); 805 scsi_inquiry_labels_3[12] = 806 MSGSTR(2176, "Terminate task: "); 807 scsi_inquiry_labels_3[13] = 808 MSGSTR(2177, "Normal ACA Supported: "); 809 scsi_inquiry_labels_3[14] = MSGSTR(150, "Response data format: "); 810 scsi_inquiry_labels_3[15] = MSGSTR(151, "Additional length: "); 811 scsi_inquiry_labels_3[16] = 812 MSGSTR(2178, "Cmd received on port: "); 813 scsi_inquiry_labels_3[17] = 814 MSGSTR(2179, "SIP Bits: "); 815 scsi_inquiry_labels_3[18] = MSGSTR(152, "Relative addressing: "); 816 scsi_inquiry_labels_3[19] = MSGSTR(153, "Linked commands: "); 817 scsi_inquiry_labels_3[20] = 818 MSGSTR(2180, "Transfer Disable: "); 819 scsi_inquiry_labels_3[21] = MSGSTR(154, "Command queueing: "); 820 821 /* 822 * Intialize scsi_inquiry_labels_3 with i18n strings 823 */ 824 ansi_version[0] = MSGSTR(2181, 825 " (Device might or might not comply to an ANSI version)"); 826 ansi_version[1] = MSGSTR(2182, 827 " (This code is reserved for historical uses)"); 828 ansi_version[2] = MSGSTR(2183, 829 " (Device complies to ANSI X3.131-1994 (SCSI-2))"); 830 ansi_version[3] = MSGSTR(2184, 831 " (Device complies to ANSI INCITS 301-1997 (SPC))"); 832 ansi_version[4] = MSGSTR(2226, 833 " (Device complies to ANSI INCITS 351-2001 (SPC-2))"); 834 ansi_version[5] = MSGSTR(2227, 835 " (Device complies to ANSI INCITS 408-2005 (SPC-3))"); 836 837 /* print inquiry information */ 838 839 (void) fprintf(stdout, MSGSTR(2185, "\nINQUIRY:\n")); 840 /* 841 * arg_path is the path sent to luxadm by the user. if arg_path 842 * is a /devices path, then we do not need to print out physical 843 * path info 844 */ 845 if (strcmp(arg_path, path) != 0 && 846 strstr(arg_path, "/devices/") == NULL) { 847 (void) fprintf(stdout, " "); 848 (void) fprintf(stdout, 849 MSGSTR(5, "Physical Path:")); 850 (void) fprintf(stdout, "\n %s\n", path); 851 } 852 if (inq.inq_ansi < 3) { 853 p = scsi_inquiry_labels_2; 854 scsi_3 = 0; 855 } else { 856 p = scsi_inquiry_labels_3; 857 scsi_3 = 1; 858 } 859 if (inq.inq_len < 11) { 860 p += 1; 861 } else { 862 /* */ 863 (void) fprintf(stdout, "%s", *p++); 864 print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); 865 (void) fprintf(stdout, "\n"); 866 } 867 if (inq.inq_len < 27) { 868 p += 1; 869 } else { 870 (void) fprintf(stdout, "%s", *p++); 871 print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); 872 (void) fprintf(stdout, "\n"); 873 } 874 if (inq.inq_len < 31) { 875 p += 1; 876 } else { 877 (void) fprintf(stdout, "%s", *p++); 878 print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); 879 (void) fprintf(stdout, "\n"); 880 } 881 if (inq.inq_len < 39) { 882 p += 2; 883 } else { 884 /* 885 * If Pluto then print 886 * firmware rev & serial #. 887 */ 888 if (strstr((char *)inq.inq_pid, "SSA") != 0) { 889 (void) fprintf(stdout, "%s", *p++); 890 print_chars(inq.inq_firmware_rev, 891 sizeof (inq.inq_firmware_rev), 0); 892 (void) fprintf(stdout, "\n"); 893 (void) fprintf(stdout, "%s", *p++); 894 print_chars(serial, serial_len, 0); 895 (void) fprintf(stdout, "\n"); 896 } else if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_ESI) { 897 p++; 898 (void) fprintf(stdout, "%s", *p++); 899 print_chars(serial, serial_len, 0); 900 (void) fprintf(stdout, "\n"); 901 } else { 902 /* if we miss both the above if's */ 903 p += 2; 904 } 905 } 906 907 (void) fprintf(stdout, "%s0x%x (", *p++, (inq.inq_dtype & DTYPE_MASK)); 908 if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { 909 (void) fprintf(stdout, "%s", dtype[inq.inq_dtype & DTYPE_MASK]); 910 } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { 911 (void) fprintf(stdout, MSGSTR(71, "Reserved")); 912 } else { 913 (void) fprintf(stdout, MSGSTR(2186, "Unknown device")); 914 } 915 (void) fprintf(stdout, ")\n"); 916 917 (void) fprintf(stdout, "%s", *p++); 918 if (inq.inq_rmb != NULL) { 919 (void) fprintf(stdout, MSGSTR(40, "yes")); 920 } else { 921 (void) fprintf(stdout, MSGSTR(45, "no")); 922 } 923 (void) fprintf(stdout, "\n"); 924 925 if (scsi_3) { 926 (void) fprintf(stdout, "%s", *p++); 927 if (inq.inq_mchngr != NULL) { 928 (void) fprintf(stdout, MSGSTR(40, "yes")); 929 } else { 930 (void) fprintf(stdout, MSGSTR(45, "no")); 931 } 932 (void) fprintf(stdout, "\n"); 933 } 934 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_iso); 935 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_ecma); 936 937 (void) fprintf(stdout, "%s%d", *p++, inq.inq_ansi); 938 if (inq.inq_ansi < MAX_ANSI_VERSION) { 939 (void) fprintf(stdout, "%s", ansi_version[inq.inq_ansi]); 940 } else 941 (void) fprintf(stdout, MSGSTR(71, " (Reserved)")); 942 943 (void) fprintf(stdout, "\n"); 944 945 if (inq.inq_aenc) { 946 (void) fprintf(stdout, "%s", *p++); 947 (void) fprintf(stdout, MSGSTR(40, "yes")); 948 (void) fprintf(stdout, "\n"); 949 } else { 950 p++; 951 } 952 if (scsi_3) { 953 (void) fprintf(stdout, "%s", *p++); 954 if (inq.inq_normaca != NULL) { 955 (void) fprintf(stdout, MSGSTR(40, "yes")); 956 } else { 957 (void) fprintf(stdout, MSGSTR(45, "no")); 958 } 959 (void) fprintf(stdout, "\n"); 960 } 961 if (inq.inq_trmiop) { 962 (void) fprintf(stdout, "%s", *p++); 963 (void) fprintf(stdout, MSGSTR(40, "yes")); 964 (void) fprintf(stdout, "\n"); 965 } else { 966 p++; 967 } 968 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_rdf); 969 (void) fprintf(stdout, "%s0x%x\n", *p++, inq.inq_len); 970 if (scsi_3) { 971 if (inq.inq_dual_p) { 972 if (inq.inq_port != NULL) { 973 (void) fprintf(stdout, MSGSTR(2187, 974 "%sa\n"), *p++); 975 } else { 976 (void) fprintf(stdout, MSGSTR(2188, 977 "%sb\n"), *p++); 978 } 979 } else { 980 p++; 981 } 982 } 983 if (scsi_3) { 984 if (inq.inq_SIP_1 || inq.ui.inq_3.inq_SIP_2 || 985 inq.ui.inq_3.inq_SIP_3) { 986 (void) fprintf(stdout, "%s%d, %d, %d\n", *p, 987 inq.inq_SIP_1, inq.ui.inq_3.inq_SIP_2, 988 inq.ui.inq_3.inq_SIP_3); 989 } 990 p++; 991 992 } 993 994 if (inq.ui.inq_2.inq_2_reladdr) { 995 (void) fprintf(stdout, "%s", *p); 996 (void) fprintf(stdout, MSGSTR(40, "yes")); 997 (void) fprintf(stdout, "\n"); 998 } 999 p++; 1000 1001 if (!scsi_3) { 1002 if (inq.ui.inq_2.inq_wbus32) { 1003 (void) fprintf(stdout, "%s", *p); 1004 (void) fprintf(stdout, MSGSTR(40, "yes")); 1005 (void) fprintf(stdout, "\n"); 1006 } 1007 p++; 1008 1009 if (inq.ui.inq_2.inq_wbus16) { 1010 (void) fprintf(stdout, "%s", *p); 1011 (void) fprintf(stdout, MSGSTR(40, "yes")); 1012 (void) fprintf(stdout, "\n"); 1013 } 1014 p++; 1015 1016 if (inq.ui.inq_2.inq_sync) { 1017 (void) fprintf(stdout, "%s", *p); 1018 (void) fprintf(stdout, MSGSTR(40, "yes")); 1019 (void) fprintf(stdout, "\n"); 1020 } 1021 p++; 1022 1023 } 1024 if (inq.ui.inq_2.inq_linked) { 1025 (void) fprintf(stdout, "%s", *p); 1026 (void) fprintf(stdout, MSGSTR(40, "yes")); 1027 (void) fprintf(stdout, "\n"); 1028 } 1029 p++; 1030 1031 if (scsi_3) { 1032 (void) fprintf(stdout, "%s", *p++); 1033 if (inq.ui.inq_3.inq_trandis != NULL) { 1034 (void) fprintf(stdout, MSGSTR(40, "yes")); 1035 } else { 1036 (void) fprintf(stdout, MSGSTR(45, "no")); 1037 } 1038 (void) fprintf(stdout, "\n"); 1039 } 1040 1041 if (inq.ui.inq_2.inq_cmdque) { 1042 (void) fprintf(stdout, "%s", *p); 1043 (void) fprintf(stdout, MSGSTR(40, "yes")); 1044 (void) fprintf(stdout, "\n"); 1045 } 1046 p++; 1047 1048 if (!scsi_3) { 1049 if (inq.ui.inq_2.inq_sftre) { 1050 (void) fprintf(stdout, "%s", *p); 1051 (void) fprintf(stdout, MSGSTR(40, "yes")); 1052 (void) fprintf(stdout, "\n"); 1053 } 1054 p++; 1055 1056 } 1057 1058 /* 1059 * Now print the vendor-specific data. 1060 */ 1061 v_parm = inq.inq_ven_specific_1; 1062 if (inq.inq_len >= 32) { 1063 length = inq.inq_len - 31; 1064 if (strstr((char *)inq.inq_pid, "SSA") != 0) { 1065 (void) fprintf(stdout, MSGSTR(2189, 1066 "Number of Ports, Targets: %d,%d\n"), 1067 inq.inq_ssa_ports, inq.inq_ssa_tgts); 1068 v_parm += 20; 1069 length -= 20; 1070 } else if ((strstr((char *)inq.inq_pid, "SUN") != 0) || 1071 (strncmp((char *)inq.inq_vid, "SUN ", 1072 sizeof (inq.inq_vid)) == 0)) { 1073 v_parm += 16; 1074 length -= 16; 1075 } 1076 /* 1077 * Do hex Dump of rest of the data. 1078 */ 1079 if (length > 0) { 1080 (void) fprintf(stdout, 1081 MSGSTR(2190, 1082 " VENDOR-SPECIFIC PARAMETERS\n")); 1083 (void) fprintf(stdout, 1084 MSGSTR(2191, 1085 "Byte# Hex Value " 1086 " ASCII\n")); 1087 (void) sprintf(byte_number, 1088 "%d ", inq.inq_len - length + 5); 1089 dump_hex_data(byte_number, v_parm, 1090 MIN(length, inq.inq_res3 - v_parm), HEX_ASCII); 1091 } 1092 /* 1093 * Skip reserved bytes 56-95. 1094 */ 1095 length -= (inq.inq_box_name - v_parm); 1096 if (length > 0) { 1097 (void) sprintf(byte_number, "%d ", 1098 inq.inq_len - length + 5); 1099 dump_hex_data(byte_number, inq.inq_box_name, 1100 MIN(length, sizeof (inq.inq_box_name) + 1101 sizeof (inq.inq_avu)), HEX_ASCII); 1102 } 1103 } 1104 if (getenv("_LUX_D_DEBUG") != NULL) { 1105 dump_hex_data("\nComplete Inquiry: ", 1106 (uchar_t *)&inq, 1107 MIN(inq.inq_len + 5, sizeof (inq)), HEX_ASCII); 1108 } 1109 } 1110 1111 /* 1112 * Internal routine to clean up ../'s in paths. 1113 * returns 0 if no "../" are left. 1114 * 1115 * Wouldn't it be nice if there was a standard system library 1116 * routine to do this...? 1117 */ 1118 static int 1119 cleanup_dotdot_path(char *path) 1120 { 1121 char holder[MAXPATHLEN]; 1122 char *dotdot; 1123 char *previous_slash; 1124 1125 /* Find the first "/../" in the string */ 1126 dotdot = strstr(path, "/../"); 1127 if (dotdot == NULL) { 1128 return (0); 1129 } 1130 1131 1132 /* 1133 * If the [0] character is '/' and "../" immediatly 1134 * follows it, then we can strip the ../ 1135 * 1136 * /../../foo/bar == /foo/bar 1137 * 1138 */ 1139 if (dotdot == path) { 1140 strcpy(holder, &path[3]); /* strip "/.." */ 1141 strcpy(path, holder); 1142 return (1); 1143 } 1144 1145 /* 1146 * Now look for the LAST "/" before the "/../" 1147 * as this is the parent dir we can get rid of. 1148 * We do this by temporarily truncating the string 1149 * at the '/' just before "../" using the dotdot pointer. 1150 */ 1151 *dotdot = '\0'; 1152 previous_slash = strrchr(path, '/'); 1153 if (previous_slash == NULL) { 1154 /* 1155 * hmm, somethings wrong. path looks something 1156 * like "foo/../bar/" so we can't really deal with it. 1157 */ 1158 return (0); 1159 } 1160 /* 1161 * Now truncate the path just after the previous '/' 1162 * and slam everything after the "../" back on 1163 */ 1164 *(previous_slash+1) = '\0'; 1165 (void) strcat(path, dotdot+4); 1166 return (1); /* We may have more "../"s */ 1167 } 1168 1169 /* 1170 * Follow symbolic links from the logical device name to 1171 * the /devfs physical device name. To be complete, we 1172 * handle the case of multiple links. This function 1173 * either returns NULL (no links, or some other error), 1174 * or the physical device name, alloc'ed on the heap. 1175 * 1176 * NOTE: If the path is relative, it will be forced into 1177 * an absolute path by pre-pending the pwd to it. 1178 */ 1179 char * 1180 get_slash_devices_from_osDevName(char *osDevName, int flag) 1181 { 1182 struct stat stbuf; 1183 char source[MAXPATHLEN]; 1184 char scratch[MAXPATHLEN]; 1185 char pwd[MAXPATHLEN]; 1186 char *tmp, *phys_path; 1187 int cnt; 1188 boolean_t is_lstat_failed = B_TRUE; 1189 1190 /* return NULL if path is NULL */ 1191 if (osDevName == NULL) { 1192 return (NULL); 1193 } 1194 1195 strcpy(source, osDevName); 1196 for (;;) { 1197 1198 /* 1199 * First make sure the path is absolute. If not, make it. 1200 * If it's already an absolute path, we have no need 1201 * to determine the cwd, so the program should still 1202 * function within security-by-obscurity directories. 1203 */ 1204 if (source[0] != '/') { 1205 tmp = getcwd(pwd, MAXPATHLEN); 1206 if (tmp == NULL) { 1207 return (NULL); 1208 } 1209 /* 1210 * Handle special case of "./foo/bar" 1211 */ 1212 if (source[0] == '.' && source[1] == '/') { 1213 strcpy(scratch, source+2); 1214 } else { /* no "./" so just take everything */ 1215 strcpy(scratch, source); 1216 } 1217 strcpy(source, pwd); 1218 (void) strcat(source, "/"); 1219 (void) strcat(source, scratch); 1220 } 1221 1222 /* 1223 * Clean up any "../"s that are in the path 1224 */ 1225 while (cleanup_dotdot_path(source)) 1226 ; 1227 1228 /* 1229 * source is now an absolute path to the link we're 1230 * concerned with 1231 */ 1232 if (flag == NOT_IGNORE_DANGLING_LINK) { 1233 /* 1234 * In order not to ingore dangling links, check 1235 * the lstat. If lstat succeeds, return the path 1236 * from readlink. 1237 * Note: osDevName input with /devices path from 1238 * a dangling /dev link doesn't pass lstat so 1239 * NULL is returned. 1240 */ 1241 if (stat(source, &stbuf) == -1) { 1242 if (!is_lstat_failed && 1243 strstr(source, "/devices")) { 1244 /* 1245 * lstat succeeded previously and source 1246 * contains "/devices" then it is 1247 * dangling node. 1248 */ 1249 phys_path = (char *)calloc(1, 1250 strlen(source) + 1); 1251 if (phys_path != NULL) { 1252 (void) strncpy(phys_path, 1253 source, strlen(source) + 1); 1254 } 1255 return (phys_path); 1256 } else if (is_lstat_failed) { 1257 /* check lstat result. */ 1258 if (lstat(source, &stbuf) == -1) { 1259 return (NULL); 1260 } else { 1261 /* and continue */ 1262 is_lstat_failed = B_FALSE; 1263 } 1264 } else { 1265 /* 1266 * With algorithm that resolves a link 1267 * and then issues readlink(), should 1268 * not be reached here. 1269 */ 1270 return (NULL); 1271 } 1272 } else { 1273 if (lstat(source, &stbuf) == -1) { 1274 /* 1275 * when stat succeeds it is not 1276 * a dangling node so it is not 1277 * a special case. 1278 */ 1279 return (NULL); 1280 } 1281 } 1282 } else if (flag == STANDARD_DEVNAME_HANDLING) { 1283 /* 1284 * See if there's a real file out there. If not, 1285 * we have a dangling link and we ignore it. 1286 */ 1287 if (stat(source, &stbuf) == -1) { 1288 return (NULL); 1289 } 1290 if (lstat(source, &stbuf) == -1) { 1291 return (NULL); 1292 } 1293 } else { 1294 /* invalid flag */ 1295 return (NULL); 1296 } 1297 1298 /* 1299 * If the file is not a link, we're done one 1300 * way or the other. If there were links, 1301 * return the full pathname of the resulting 1302 * file. 1303 * 1304 * Note: All of our temp's are on the stack, 1305 * so we have to copy the final result to the heap. 1306 */ 1307 if (!S_ISLNK(stbuf.st_mode)) { 1308 phys_path = (char *)calloc(1, strlen(source) + 1); 1309 if (phys_path != NULL) { 1310 (void) strncpy(phys_path, source, 1311 strlen(source) + 1); 1312 } 1313 return (phys_path); 1314 } 1315 cnt = readlink(source, scratch, sizeof (scratch)); 1316 if (cnt < 0) { 1317 return (NULL); 1318 } 1319 /* 1320 * scratch is on the heap, and for some reason readlink 1321 * doesn't always terminate things properly so we have 1322 * to make certain we're properly terminated 1323 */ 1324 scratch[cnt] = '\0'; 1325 1326 /* 1327 * Now check to see if the link is relative. If so, 1328 * then we have to append it to the directory 1329 * which the source was in. (This is non trivial) 1330 */ 1331 if (scratch[0] != '/') { 1332 tmp = strrchr(source, '/'); 1333 if (tmp == NULL) { /* Whoa! Something's hosed! */ 1334 O_DPRINTF("Internal error... corrupt path.\n"); 1335 return (NULL); 1336 } 1337 /* Now strip off just the directory path */ 1338 *(tmp+1) = '\0'; /* Keeping the last '/' */ 1339 /* and append the new link */ 1340 (void) strcat(source, scratch); 1341 /* 1342 * Note: At this point, source should have "../"s 1343 * but we'll clean it up in the next pass through 1344 * the loop. 1345 */ 1346 } else { 1347 /* It's an absolute link so no worries */ 1348 strcpy(source, scratch); 1349 } 1350 } 1351 /* Never reach here */ 1352 } 1353 1354 /* 1355 * Input - Space for client_path, phci_path and paddr fields of ioc structure 1356 * need to be allocated by the caller of this routine. 1357 */ 1358 int 1359 get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count) 1360 { 1361 char *physical_path, *physical_path_s; 1362 int retval; 1363 int fd; 1364 int initial_path_count; 1365 int current_path_count; 1366 int i; 1367 char *delimiter; 1368 int malloc_error = 0; 1369 int prop_buf_size; 1370 int pathlist_retry_count = 0; 1371 1372 if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != NULL) { 1373 if ((physical_path = get_slash_devices_from_osDevName( 1374 dev_path, STANDARD_DEVNAME_HANDLING)) == NULL) { 1375 return (L_INVALID_PATH); 1376 } 1377 if (strncmp(physical_path, SCSI_VHCI, 1378 strlen(SCSI_VHCI)) != NULL) { 1379 free(physical_path); 1380 return (L_INVALID_PATH); 1381 } 1382 } else { 1383 if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) { 1384 return (L_MALLOC_FAILED); 1385 } 1386 (void) strcpy(physical_path, dev_path); 1387 } 1388 physical_path_s = physical_path; 1389 1390 /* move beyond "/devices" prefix */ 1391 physical_path += DEV_PREFIX_STRLEN-1; 1392 /* remove :c,raw suffix */ 1393 delimiter = strrchr(physical_path, ':'); 1394 /* if we didn't find the ':' fine, else truncate */ 1395 if (delimiter != NULL) { 1396 *delimiter = NULL; 1397 } 1398 1399 /* 1400 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO 1401 * at least twice. The first time will get the path count 1402 * and the size of the ioctl propoerty buffer. The second 1403 * time will get the path_info for each path. 1404 * 1405 * It's possible that additional paths are added while this 1406 * code is running. If the path count increases between the 1407 * 2 ioctl's above, then we'll retry (and assume all is well). 1408 */ 1409 (void) strcpy(ioc->client, physical_path); 1410 ioc->buf_elem = 1; 1411 ioc->ret_elem = (uint_t *)&(initial_path_count); 1412 ioc->ret_buf = NULL; 1413 1414 /* free physical path */ 1415 free(physical_path_s); 1416 1417 /* 0 buf_size asks driver to return actual size needed */ 1418 /* open the ioctl file descriptor */ 1419 if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) { 1420 return (L_OPEN_PATH_FAIL); 1421 } 1422 1423 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); 1424 if (retval != 0) { 1425 close(fd); 1426 return (L_SCSI_VHCI_ERROR); 1427 } 1428 prop_buf_size = SV_PROP_MAX_BUF_SIZE; 1429 1430 1431 while (pathlist_retry_count <= RETRY_PATHLIST) { 1432 ioc->buf_elem = initial_path_count; 1433 /* Make driver put actual # paths in variable */ 1434 ioc->ret_elem = (uint_t *)&(current_path_count); 1435 1436 /* 1437 * Allocate space for array of path_info structures. 1438 * Allocate enough space for # paths from get_pathcount 1439 */ 1440 ioc->ret_buf = (sv_path_info_t *) 1441 calloc(initial_path_count, sizeof (sv_path_info_t)); 1442 if (ioc->ret_buf == NULL) { 1443 close(fd); 1444 return (L_MALLOC_FAILED); 1445 } 1446 1447 /* 1448 * Allocate space for path properties returned by driver 1449 */ 1450 malloc_error = 0; 1451 for (i = 0; i < initial_path_count; i++) { 1452 ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size; 1453 if ((ioc->ret_buf[i].ret_prop.buf = 1454 (caddr_t)malloc(prop_buf_size)) == NULL) { 1455 malloc_error = 1; 1456 break; 1457 } 1458 if ((ioc->ret_buf[i].ret_prop.ret_buf_size = 1459 (uint_t *)malloc(sizeof (uint_t))) == NULL) { 1460 malloc_error = 1; 1461 break; 1462 } 1463 } 1464 if (malloc_error == 1) { 1465 for (i = 0; i < initial_path_count; i++) { 1466 free(ioc->ret_buf[i].ret_prop.buf); 1467 free(ioc->ret_buf[i].ret_prop.ret_buf_size); 1468 } 1469 free(ioc->ret_buf); 1470 close(fd); 1471 return (L_MALLOC_FAILED); 1472 } 1473 1474 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); 1475 if (retval != 0) { 1476 for (i = 0; i < initial_path_count; i++) { 1477 free(ioc->ret_buf[i].ret_prop.buf); 1478 free(ioc->ret_buf[i].ret_prop.ret_buf_size); 1479 } 1480 free(ioc->ret_buf); 1481 close(fd); 1482 return (L_SCSI_VHCI_ERROR); 1483 } 1484 if (initial_path_count < current_path_count) { 1485 /* then a new path was added */ 1486 pathlist_retry_count++; 1487 initial_path_count = current_path_count; 1488 } else { 1489 break; 1490 } 1491 } 1492 /* we are done with ioctl's, lose the fd */ 1493 close(fd); 1494 1495 /* 1496 * Compare the length num elements from the ioctl response 1497 * and the caller's request - use smaller value. 1498 * 1499 * pathlist_p->path_count now has count returned from ioctl. 1500 * ioc.buf_elem has the value the caller provided. 1501 */ 1502 if (initial_path_count < current_path_count) { 1503 /* More paths exist than we allocated space for */ 1504 *path_count = initial_path_count; 1505 } else { 1506 *path_count = current_path_count; 1507 } 1508 1509 return (0); 1510 } 1511 1512 int 1513 get_mode_page(char *path, uchar_t **pg_buf) 1514 { 1515 struct mode_header_g1 *mode_header_ptr; 1516 int status, size, fd; 1517 1518 /* open controller */ 1519 if ((fd = open(path, O_NDELAY | O_RDWR)) == -1) 1520 return (-1); /* L_OPEN_PATH_FAIL */ 1521 1522 /* 1523 * Read the first part of the page to get the page size 1524 */ 1525 size = 20; 1526 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { 1527 (void) close(fd); 1528 return (L_MALLOC_FAILED); 1529 } 1530 /* read page */ 1531 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 1532 0, MODEPAGE_ALLPAGES)) { 1533 (void) close(fd); 1534 (void) free(*pg_buf); 1535 return (status); 1536 } 1537 /* Now get the size for all pages */ 1538 mode_header_ptr = (struct mode_header_g1 *)(void *)*pg_buf; 1539 size = ntohs(mode_header_ptr->length) + 1540 sizeof (mode_header_ptr->length); 1541 (void) free(*pg_buf); 1542 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { 1543 (void) close(fd); 1544 return (L_MALLOC_FAILED); 1545 } 1546 /* read all pages */ 1547 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 1548 0, MODEPAGE_ALLPAGES)) { 1549 (void) close(fd); 1550 (void) free(*pg_buf); 1551 return (status); 1552 } 1553 (void) close(fd); 1554 return (0); 1555 } 1556 1557 /* 1558 * Dump a structure in hexadecimal. 1559 */ 1560 void 1561 dump_hex_data(char *hdr, uchar_t *src, int nbytes, int format) 1562 { 1563 int i; 1564 int n; 1565 char *p; 1566 char s[256]; 1567 1568 assert(format == HEX_ONLY || format == HEX_ASCII); 1569 1570 (void) strcpy(s, hdr); 1571 for (p = s; *p; p++) { 1572 *p = ' '; 1573 } 1574 1575 p = hdr; 1576 while (nbytes > 0) { 1577 (void) fprintf(stdout, "%s", p); 1578 p = s; 1579 n = MIN(nbytes, BYTES_PER_LINE); 1580 for (i = 0; i < n; i++) { 1581 (void) fprintf(stdout, "%02x ", src[i] & 0xff); 1582 } 1583 if (format == HEX_ASCII) { 1584 for (i = BYTES_PER_LINE-n; i > 0; i--) { 1585 (void) fprintf(stdout, " "); 1586 } 1587 (void) fprintf(stdout, " "); 1588 for (i = 0; i < n; i++) { 1589 (void) fprintf(stdout, "%c", 1590 isprint(src[i]) ? src[i] : '.'); 1591 } 1592 } 1593 (void) fprintf(stdout, "\n"); 1594 nbytes -= n; 1595 src += n; 1596 } 1597 } 1598