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