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, uchar_t *buf_ptr, int buf_len, uchar_t pc, 612 uchar_t page_code) 613 { 614 struct uscsi_cmd ucmd; 615 /* 10 byte Mode Select cmd */ 616 union scsi_cdb cdb = {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 617 struct scsi_extended_sense sense; 618 int status; 619 static int uscsi_count; 620 621 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 622 return (-1); /* L_INVALID_ARG */ 623 } 624 625 (void) memset(buf_ptr, 0, buf_len); 626 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 627 /* Just for me - a sanity check */ 628 if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) || 629 (buf_len > MAX_MODE_SENSE_LEN)) { 630 return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */ 631 } 632 cdb.g1_addr3 = (pc << 6) + page_code; 633 cdb.g1_count1 = buf_len>>8; 634 cdb.g1_count0 = buf_len & 0xff; 635 ucmd.uscsi_cdb = (caddr_t)&cdb; 636 ucmd.uscsi_cdblen = CDB_GROUP1; 637 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 638 ucmd.uscsi_buflen = buf_len; 639 ucmd.uscsi_rqbuf = (caddr_t)&sense; 640 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 641 ucmd.uscsi_timeout = 120; 642 643 status = issue_uscsi_cmd(fd, &ucmd, USCSI_READ); 644 /* Bytes actually transfered */ 645 if (status == 0) { 646 uscsi_count = buf_len - ucmd.uscsi_resid; 647 S_DPRINTF(" Number of bytes read on " 648 "Mode Sense 0x%x\n", uscsi_count); 649 if (getenv("_LUX_D_DEBUG") != NULL) { 650 (void) dump_hex_data(" Mode Sense data: ", buf_ptr, 651 uscsi_count, HEX_ASCII); 652 } 653 } 654 return (status); 655 } 656 657 int 658 scsi_release(char *path) 659 { 660 struct uscsi_cmd ucmd; 661 union scsi_cdb cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0}; 662 struct scsi_extended_sense sense; 663 int fd, status; 664 665 P_DPRINTF(" scsi_release: Release: Path %s\n", path); 666 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) 667 return (1); 668 669 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 670 671 ucmd.uscsi_cdb = (caddr_t)&cdb; 672 ucmd.uscsi_cdblen = CDB_GROUP0; 673 ucmd.uscsi_bufaddr = NULL; 674 ucmd.uscsi_buflen = 0; 675 ucmd.uscsi_rqbuf = (caddr_t)&sense; 676 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 677 ucmd.uscsi_timeout = 60; 678 status = (issue_uscsi_cmd(fd, &ucmd, 0)); 679 680 (void) close(fd); 681 return (status); 682 } 683 684 int 685 scsi_reserve(char *path) 686 { 687 struct uscsi_cmd ucmd; 688 union scsi_cdb cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0}; 689 struct scsi_extended_sense sense; 690 int fd, status; 691 692 P_DPRINTF(" scsi_reserve: Reserve: Path %s\n", path); 693 if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) 694 return (1); 695 696 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 697 698 ucmd.uscsi_cdb = (caddr_t)&cdb; 699 ucmd.uscsi_cdblen = CDB_GROUP0; 700 ucmd.uscsi_bufaddr = NULL; 701 ucmd.uscsi_buflen = 0; 702 ucmd.uscsi_rqbuf = (caddr_t)&sense; 703 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 704 ucmd.uscsi_timeout = 60; 705 status = (issue_uscsi_cmd(fd, &ucmd, 0)); 706 707 (void) close(fd); 708 return (status); 709 } 710 711 /* 712 * Print out fabric dev dtype 713 */ 714 void 715 print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, 716 uchar_t dtype_prop) 717 { 718 if ((dtype_prop & DTYPE_MASK) < 0x10) { 719 (void) fprintf(stdout, " 0x%-2x (%s)\n", 720 (dtype_prop & DTYPE_MASK), 721 dtype[(dtype_prop & DTYPE_MASK)]); 722 } else if ((dtype_prop & DTYPE_MASK) < 0x1f) { 723 (void) fprintf(stdout, 724 MSGSTR(2096, " 0x%-2x (Reserved)\n"), 725 (dtype_prop & DTYPE_MASK)); 726 } else { 727 /* Check to see if this is the HBA */ 728 if (wwnConversion(hba_port_wwn) != wwnConversion(port_wwn)) { 729 (void) fprintf(stdout, MSGSTR(2097, 730 " 0x%-2x (Unknown Type)\n"), 731 (dtype_prop & DTYPE_MASK)); 732 } else { 733 /* MATCH */ 734 (void) fprintf(stdout, MSGSTR(2241, 735 " 0x%-2x (Unknown Type,Host Bus Adapter)\n"), 736 (dtype_prop & DTYPE_MASK)); 737 } 738 } 739 } 740 741 742 void 743 print_inq_data(char *arg_path, char *path, L_inquiry inq, uchar_t *serial, 744 size_t serial_len) 745 { 746 char **p; 747 uchar_t *v_parm; 748 int scsi_3, length; 749 char byte_number[MAXNAMELEN]; 750 static char *scsi_inquiry_labels_2[21]; 751 static char *scsi_inquiry_labels_3[22]; 752 #define MAX_ANSI_VERSION 6 753 static char *ansi_version[MAX_ANSI_VERSION]; 754 /* 755 * Intialize scsi_inquiry_labels_2 with i18n strings 756 */ 757 scsi_inquiry_labels_2[0] = MSGSTR(138, "Vendor: "); 758 scsi_inquiry_labels_2[1] = MSGSTR(149, "Product: "); 759 scsi_inquiry_labels_2[2] = MSGSTR(139, "Revision: "); 760 scsi_inquiry_labels_2[3] = MSGSTR(143, "Firmware Revision "); 761 scsi_inquiry_labels_2[4] = MSGSTR(144, "Serial Number "); 762 scsi_inquiry_labels_2[5] = MSGSTR(140, "Device type: "); 763 scsi_inquiry_labels_2[6] = MSGSTR(145, "Removable media: "); 764 scsi_inquiry_labels_2[7] = MSGSTR(146, "ISO version: "); 765 scsi_inquiry_labels_2[8] = MSGSTR(147, "ECMA version: "); 766 scsi_inquiry_labels_2[9] = MSGSTR(148, "ANSI version: "); 767 scsi_inquiry_labels_2[10] = 768 MSGSTR(2168, "Async event notification: "); 769 scsi_inquiry_labels_2[11] = 770 MSGSTR(2169, "Terminate i/o process msg: "); 771 scsi_inquiry_labels_2[12] = MSGSTR(150, "Response data format: "); 772 scsi_inquiry_labels_2[13] = MSGSTR(151, "Additional length: "); 773 scsi_inquiry_labels_2[14] = MSGSTR(152, "Relative addressing: "); 774 scsi_inquiry_labels_2[15] = 775 MSGSTR(2170, "32 bit transfers: "); 776 scsi_inquiry_labels_2[16] = 777 MSGSTR(2171, "16 bit transfers: "); 778 scsi_inquiry_labels_2[17] = 779 MSGSTR(2172, "Synchronous transfers: "); 780 scsi_inquiry_labels_2[18] = MSGSTR(153, "Linked commands: "); 781 scsi_inquiry_labels_2[19] = MSGSTR(154, "Command queueing: "); 782 scsi_inquiry_labels_2[20] = 783 MSGSTR(2173, "Soft reset option: "); 784 785 /* 786 * Intialize scsi_inquiry_labels_3 with i18n strings 787 */ 788 scsi_inquiry_labels_3[0] = MSGSTR(138, "Vendor: "); 789 scsi_inquiry_labels_3[1] = MSGSTR(149, "Product: "); 790 scsi_inquiry_labels_3[2] = MSGSTR(139, "Revision: "); 791 scsi_inquiry_labels_3[3] = MSGSTR(143, "Firmware Revision "); 792 scsi_inquiry_labels_3[4] = MSGSTR(144, "Serial Number "); 793 scsi_inquiry_labels_3[5] = MSGSTR(140, "Device type: "); 794 scsi_inquiry_labels_3[6] = MSGSTR(145, "Removable media: "); 795 scsi_inquiry_labels_3[7] = MSGSTR(2174, "Medium Changer Element: "); 796 scsi_inquiry_labels_3[8] = MSGSTR(146, "ISO version: "); 797 scsi_inquiry_labels_3[9] = MSGSTR(147, "ECMA version: "); 798 scsi_inquiry_labels_3[10] = MSGSTR(148, "ANSI version: "); 799 scsi_inquiry_labels_3[11] = 800 MSGSTR(2175, "Async event reporting: "); 801 scsi_inquiry_labels_3[12] = 802 MSGSTR(2176, "Terminate task: "); 803 scsi_inquiry_labels_3[13] = 804 MSGSTR(2177, "Normal ACA Supported: "); 805 scsi_inquiry_labels_3[14] = MSGSTR(150, "Response data format: "); 806 scsi_inquiry_labels_3[15] = MSGSTR(151, "Additional length: "); 807 scsi_inquiry_labels_3[16] = 808 MSGSTR(2178, "Cmd received on port: "); 809 scsi_inquiry_labels_3[17] = 810 MSGSTR(2179, "SIP Bits: "); 811 scsi_inquiry_labels_3[18] = MSGSTR(152, "Relative addressing: "); 812 scsi_inquiry_labels_3[19] = MSGSTR(153, "Linked commands: "); 813 scsi_inquiry_labels_3[20] = 814 MSGSTR(2180, "Transfer Disable: "); 815 scsi_inquiry_labels_3[21] = MSGSTR(154, "Command queueing: "); 816 817 /* 818 * Intialize scsi_inquiry_labels_3 with i18n strings 819 */ 820 ansi_version[0] = MSGSTR(2181, 821 " (Device might or might not comply to an ANSI version)"); 822 ansi_version[1] = MSGSTR(2182, 823 " (This code is reserved for historical uses)"); 824 ansi_version[2] = MSGSTR(2183, 825 " (Device complies to ANSI X3.131-1994 (SCSI-2))"); 826 ansi_version[3] = MSGSTR(2184, 827 " (Device complies to ANSI INCITS 301-1997 (SPC))"); 828 ansi_version[4] = MSGSTR(2226, 829 " (Device complies to ANSI INCITS 351-2001 (SPC-2))"); 830 ansi_version[5] = MSGSTR(2227, 831 " (Device complies to ANSI INCITS 408-2005 (SPC-3))"); 832 833 /* print inquiry information */ 834 835 (void) fprintf(stdout, MSGSTR(2185, "\nINQUIRY:\n")); 836 /* 837 * arg_path is the path sent to luxadm by the user. if arg_path 838 * is a /devices path, then we do not need to print out physical 839 * path info 840 */ 841 if (strcmp(arg_path, path) != 0 && 842 strstr(arg_path, "/devices/") == NULL) { 843 (void) fprintf(stdout, " "); 844 (void) fprintf(stdout, 845 MSGSTR(5, "Physical Path:")); 846 (void) fprintf(stdout, "\n %s\n", path); 847 } 848 if (inq.inq_ansi < 3) { 849 p = scsi_inquiry_labels_2; 850 scsi_3 = 0; 851 } else { 852 p = scsi_inquiry_labels_3; 853 scsi_3 = 1; 854 } 855 if (inq.inq_len < 11) { 856 p += 1; 857 } else { 858 /* */ 859 (void) fprintf(stdout, "%s", *p++); 860 print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); 861 (void) fprintf(stdout, "\n"); 862 } 863 if (inq.inq_len < 27) { 864 p += 1; 865 } else { 866 (void) fprintf(stdout, "%s", *p++); 867 print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); 868 (void) fprintf(stdout, "\n"); 869 } 870 if (inq.inq_len < 31) { 871 p += 1; 872 } else { 873 (void) fprintf(stdout, "%s", *p++); 874 print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); 875 (void) fprintf(stdout, "\n"); 876 } 877 if (inq.inq_len < 39) { 878 p += 2; 879 } else { 880 /* 881 * If Pluto then print 882 * firmware rev & serial #. 883 */ 884 if (strstr((char *)inq.inq_pid, "SSA") != 0) { 885 (void) fprintf(stdout, "%s", *p++); 886 print_chars(inq.inq_firmware_rev, 887 sizeof (inq.inq_firmware_rev), 0); 888 (void) fprintf(stdout, "\n"); 889 (void) fprintf(stdout, "%s", *p++); 890 print_chars(serial, serial_len, 0); 891 (void) fprintf(stdout, "\n"); 892 } else if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_ESI) { 893 p++; 894 (void) fprintf(stdout, "%s", *p++); 895 print_chars(serial, serial_len, 0); 896 (void) fprintf(stdout, "\n"); 897 } else { 898 /* if we miss both the above if's */ 899 p += 2; 900 } 901 } 902 903 (void) fprintf(stdout, "%s0x%x (", *p++, (inq.inq_dtype & DTYPE_MASK)); 904 if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { 905 (void) fprintf(stdout, "%s", dtype[inq.inq_dtype & DTYPE_MASK]); 906 } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { 907 (void) fprintf(stdout, MSGSTR(71, "Reserved")); 908 } else { 909 (void) fprintf(stdout, MSGSTR(2186, "Unknown device")); 910 } 911 (void) fprintf(stdout, ")\n"); 912 913 (void) fprintf(stdout, "%s", *p++); 914 if (inq.inq_rmb != 0) { 915 (void) fprintf(stdout, MSGSTR(40, "yes")); 916 } else { 917 (void) fprintf(stdout, MSGSTR(45, "no")); 918 } 919 (void) fprintf(stdout, "\n"); 920 921 if (scsi_3) { 922 (void) fprintf(stdout, "%s", *p++); 923 if (inq.inq_mchngr != 0) { 924 (void) fprintf(stdout, MSGSTR(40, "yes")); 925 } else { 926 (void) fprintf(stdout, MSGSTR(45, "no")); 927 } 928 (void) fprintf(stdout, "\n"); 929 } 930 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_iso); 931 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_ecma); 932 933 (void) fprintf(stdout, "%s%d", *p++, inq.inq_ansi); 934 if (inq.inq_ansi < MAX_ANSI_VERSION) { 935 (void) fprintf(stdout, "%s", ansi_version[inq.inq_ansi]); 936 } else 937 (void) fprintf(stdout, " (%s)", MSGSTR(71, "Reserved")); 938 939 (void) fprintf(stdout, "\n"); 940 941 if (inq.inq_aenc) { 942 (void) fprintf(stdout, "%s", *p++); 943 (void) fprintf(stdout, MSGSTR(40, "yes")); 944 (void) fprintf(stdout, "\n"); 945 } else { 946 p++; 947 } 948 if (scsi_3) { 949 (void) fprintf(stdout, "%s", *p++); 950 if (inq.inq_normaca != 0) { 951 (void) fprintf(stdout, MSGSTR(40, "yes")); 952 } else { 953 (void) fprintf(stdout, MSGSTR(45, "no")); 954 } 955 (void) fprintf(stdout, "\n"); 956 } 957 if (inq.inq_trmiop) { 958 (void) fprintf(stdout, "%s", *p++); 959 (void) fprintf(stdout, MSGSTR(40, "yes")); 960 (void) fprintf(stdout, "\n"); 961 } else { 962 p++; 963 } 964 (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_rdf); 965 (void) fprintf(stdout, "%s0x%x\n", *p++, inq.inq_len); 966 if (scsi_3) { 967 if (inq.inq_dual_p) { 968 if (inq.inq_port != 0) { 969 (void) fprintf(stdout, MSGSTR(2187, 970 "%sa\n"), *p++); 971 } else { 972 (void) fprintf(stdout, MSGSTR(2188, 973 "%sb\n"), *p++); 974 } 975 } else { 976 p++; 977 } 978 } 979 if (scsi_3) { 980 if (inq.inq_SIP_1 || inq.ui.inq_3.inq_SIP_2 || 981 inq.ui.inq_3.inq_SIP_3) { 982 (void) fprintf(stdout, "%s%d, %d, %d\n", *p, 983 inq.inq_SIP_1, inq.ui.inq_3.inq_SIP_2, 984 inq.ui.inq_3.inq_SIP_3); 985 } 986 p++; 987 988 } 989 990 if (inq.ui.inq_2.inq_2_reladdr) { 991 (void) fprintf(stdout, "%s", *p); 992 (void) fprintf(stdout, MSGSTR(40, "yes")); 993 (void) fprintf(stdout, "\n"); 994 } 995 p++; 996 997 if (!scsi_3) { 998 if (inq.ui.inq_2.inq_wbus32) { 999 (void) fprintf(stdout, "%s", *p); 1000 (void) fprintf(stdout, MSGSTR(40, "yes")); 1001 (void) fprintf(stdout, "\n"); 1002 } 1003 p++; 1004 1005 if (inq.ui.inq_2.inq_wbus16) { 1006 (void) fprintf(stdout, "%s", *p); 1007 (void) fprintf(stdout, MSGSTR(40, "yes")); 1008 (void) fprintf(stdout, "\n"); 1009 } 1010 p++; 1011 1012 if (inq.ui.inq_2.inq_sync) { 1013 (void) fprintf(stdout, "%s", *p); 1014 (void) fprintf(stdout, MSGSTR(40, "yes")); 1015 (void) fprintf(stdout, "\n"); 1016 } 1017 p++; 1018 1019 } 1020 if (inq.ui.inq_2.inq_linked) { 1021 (void) fprintf(stdout, "%s", *p); 1022 (void) fprintf(stdout, MSGSTR(40, "yes")); 1023 (void) fprintf(stdout, "\n"); 1024 } 1025 p++; 1026 1027 if (scsi_3) { 1028 (void) fprintf(stdout, "%s", *p++); 1029 if (inq.ui.inq_3.inq_trandis != 0) { 1030 (void) fprintf(stdout, MSGSTR(40, "yes")); 1031 } else { 1032 (void) fprintf(stdout, MSGSTR(45, "no")); 1033 } 1034 (void) fprintf(stdout, "\n"); 1035 } 1036 1037 if (inq.ui.inq_2.inq_cmdque) { 1038 (void) fprintf(stdout, "%s", *p); 1039 (void) fprintf(stdout, MSGSTR(40, "yes")); 1040 (void) fprintf(stdout, "\n"); 1041 } 1042 p++; 1043 1044 if (!scsi_3) { 1045 if (inq.ui.inq_2.inq_sftre) { 1046 (void) fprintf(stdout, "%s", *p); 1047 (void) fprintf(stdout, MSGSTR(40, "yes")); 1048 (void) fprintf(stdout, "\n"); 1049 } 1050 p++; 1051 1052 } 1053 1054 /* 1055 * Now print the vendor-specific data. 1056 */ 1057 v_parm = inq.inq_ven_specific_1; 1058 if (inq.inq_len >= 32) { 1059 length = inq.inq_len - 31; 1060 if (strstr((char *)inq.inq_pid, "SSA") != 0) { 1061 (void) fprintf(stdout, MSGSTR(2189, 1062 "Number of Ports, Targets: %d,%d\n"), 1063 inq.inq_ssa_ports, inq.inq_ssa_tgts); 1064 v_parm += 20; 1065 length -= 20; 1066 } else if ((strstr((char *)inq.inq_pid, "SUN") != 0) || 1067 (strncmp((char *)inq.inq_vid, "SUN ", 1068 sizeof (inq.inq_vid)) == 0)) { 1069 v_parm += 16; 1070 length -= 16; 1071 } 1072 /* 1073 * Do hex Dump of rest of the data. 1074 */ 1075 if (length > 0) { 1076 (void) fprintf(stdout, 1077 MSGSTR(2190, 1078 " VENDOR-SPECIFIC PARAMETERS\n")); 1079 (void) fprintf(stdout, 1080 MSGSTR(2191, 1081 "Byte# Hex Value " 1082 " ASCII\n")); 1083 (void) sprintf(byte_number, 1084 "%d ", inq.inq_len - length + 5); 1085 dump_hex_data(byte_number, v_parm, 1086 MIN(length, inq.inq_res3 - v_parm), HEX_ASCII); 1087 } 1088 /* 1089 * Skip reserved bytes 56-95. 1090 */ 1091 length -= (inq.inq_box_name - v_parm); 1092 if (length > 0) { 1093 (void) sprintf(byte_number, "%d ", 1094 inq.inq_len - length + 5); 1095 dump_hex_data(byte_number, inq.inq_box_name, 1096 MIN(length, sizeof (inq.inq_box_name) + 1097 sizeof (inq.inq_avu)), HEX_ASCII); 1098 } 1099 } 1100 if (getenv("_LUX_D_DEBUG") != NULL) { 1101 dump_hex_data("\nComplete Inquiry: ", 1102 (uchar_t *)&inq, 1103 MIN(inq.inq_len + 5, sizeof (inq)), HEX_ASCII); 1104 } 1105 } 1106 1107 /* 1108 * Internal routine to clean up ../'s in paths. 1109 * returns 0 if no "../" are left. 1110 * 1111 * Wouldn't it be nice if there was a standard system library 1112 * routine to do this...? 1113 */ 1114 static int 1115 cleanup_dotdot_path(char *path) 1116 { 1117 char holder[MAXPATHLEN]; 1118 char *dotdot; 1119 char *previous_slash; 1120 1121 /* Find the first "/../" in the string */ 1122 dotdot = strstr(path, "/../"); 1123 if (dotdot == NULL) { 1124 return (0); 1125 } 1126 1127 1128 /* 1129 * If the [0] character is '/' and "../" immediatly 1130 * follows it, then we can strip the ../ 1131 * 1132 * /../../foo/bar == /foo/bar 1133 * 1134 */ 1135 if (dotdot == path) { 1136 strcpy(holder, &path[3]); /* strip "/.." */ 1137 strcpy(path, holder); 1138 return (1); 1139 } 1140 1141 /* 1142 * Now look for the LAST "/" before the "/../" 1143 * as this is the parent dir we can get rid of. 1144 * We do this by temporarily truncating the string 1145 * at the '/' just before "../" using the dotdot pointer. 1146 */ 1147 *dotdot = '\0'; 1148 previous_slash = strrchr(path, '/'); 1149 if (previous_slash == NULL) { 1150 /* 1151 * hmm, somethings wrong. path looks something 1152 * like "foo/../bar/" so we can't really deal with it. 1153 */ 1154 return (0); 1155 } 1156 /* 1157 * Now truncate the path just after the previous '/' 1158 * and slam everything after the "../" back on 1159 */ 1160 *(previous_slash+1) = '\0'; 1161 (void) strcat(path, dotdot+4); 1162 return (1); /* We may have more "../"s */ 1163 } 1164 1165 /* 1166 * Follow symbolic links from the logical device name to 1167 * the /devfs physical device name. To be complete, we 1168 * handle the case of multiple links. This function 1169 * either returns NULL (no links, or some other error), 1170 * or the physical device name, alloc'ed on the heap. 1171 * 1172 * NOTE: If the path is relative, it will be forced into 1173 * an absolute path by pre-pending the pwd to it. 1174 */ 1175 char * 1176 get_slash_devices_from_osDevName(char *osDevName, int flag) 1177 { 1178 struct stat stbuf; 1179 char source[MAXPATHLEN]; 1180 char scratch[MAXPATHLEN]; 1181 char pwd[MAXPATHLEN]; 1182 char *tmp, *phys_path; 1183 int cnt; 1184 boolean_t is_lstat_failed = B_TRUE; 1185 1186 /* return NULL if path is NULL */ 1187 if (osDevName == NULL) { 1188 return (NULL); 1189 } 1190 1191 strcpy(source, osDevName); 1192 for (;;) { 1193 1194 /* 1195 * First make sure the path is absolute. If not, make it. 1196 * If it's already an absolute path, we have no need 1197 * to determine the cwd, so the program should still 1198 * function within security-by-obscurity directories. 1199 */ 1200 if (source[0] != '/') { 1201 tmp = getcwd(pwd, MAXPATHLEN); 1202 if (tmp == NULL) { 1203 return (NULL); 1204 } 1205 /* 1206 * Handle special case of "./foo/bar" 1207 */ 1208 if (source[0] == '.' && source[1] == '/') { 1209 strcpy(scratch, source+2); 1210 } else { /* no "./" so just take everything */ 1211 strcpy(scratch, source); 1212 } 1213 strcpy(source, pwd); 1214 (void) strcat(source, "/"); 1215 (void) strcat(source, scratch); 1216 } 1217 1218 /* 1219 * Clean up any "../"s that are in the path 1220 */ 1221 while (cleanup_dotdot_path(source)) 1222 ; 1223 1224 /* 1225 * source is now an absolute path to the link we're 1226 * concerned with 1227 */ 1228 if (flag == NOT_IGNORE_DANGLING_LINK) { 1229 /* 1230 * In order not to ingore dangling links, check 1231 * the lstat. If lstat succeeds, return the path 1232 * from readlink. 1233 * Note: osDevName input with /devices path from 1234 * a dangling /dev link doesn't pass lstat so 1235 * NULL is returned. 1236 */ 1237 if (stat(source, &stbuf) == -1) { 1238 if (!is_lstat_failed && 1239 strstr(source, "/devices")) { 1240 /* 1241 * lstat succeeded previously and source 1242 * contains "/devices" then it is 1243 * dangling node. 1244 */ 1245 phys_path = (char *)calloc(1, 1246 strlen(source) + 1); 1247 if (phys_path != NULL) { 1248 (void) strncpy(phys_path, 1249 source, strlen(source) + 1); 1250 } 1251 return (phys_path); 1252 } else if (is_lstat_failed) { 1253 /* check lstat result. */ 1254 if (lstat(source, &stbuf) == -1) { 1255 return (NULL); 1256 } else { 1257 /* and continue */ 1258 is_lstat_failed = B_FALSE; 1259 } 1260 } else { 1261 /* 1262 * With algorithm that resolves a link 1263 * and then issues readlink(), should 1264 * not be reached here. 1265 */ 1266 return (NULL); 1267 } 1268 } else { 1269 if (lstat(source, &stbuf) == -1) { 1270 /* 1271 * when stat succeeds it is not 1272 * a dangling node so it is not 1273 * a special case. 1274 */ 1275 return (NULL); 1276 } 1277 } 1278 } else if (flag == STANDARD_DEVNAME_HANDLING) { 1279 /* 1280 * See if there's a real file out there. If not, 1281 * we have a dangling link and we ignore it. 1282 */ 1283 if (stat(source, &stbuf) == -1) { 1284 return (NULL); 1285 } 1286 if (lstat(source, &stbuf) == -1) { 1287 return (NULL); 1288 } 1289 } else { 1290 /* invalid flag */ 1291 return (NULL); 1292 } 1293 1294 /* 1295 * If the file is not a link, we're done one 1296 * way or the other. If there were links, 1297 * return the full pathname of the resulting 1298 * file. 1299 * 1300 * Note: All of our temp's are on the stack, 1301 * so we have to copy the final result to the heap. 1302 */ 1303 if (!S_ISLNK(stbuf.st_mode)) { 1304 phys_path = (char *)calloc(1, strlen(source) + 1); 1305 if (phys_path != NULL) { 1306 (void) strncpy(phys_path, source, 1307 strlen(source) + 1); 1308 } 1309 return (phys_path); 1310 } 1311 cnt = readlink(source, scratch, sizeof (scratch)); 1312 if (cnt < 0) { 1313 return (NULL); 1314 } 1315 /* 1316 * scratch is on the heap, and for some reason readlink 1317 * doesn't always terminate things properly so we have 1318 * to make certain we're properly terminated 1319 */ 1320 scratch[cnt] = '\0'; 1321 1322 /* 1323 * Now check to see if the link is relative. If so, 1324 * then we have to append it to the directory 1325 * which the source was in. (This is non trivial) 1326 */ 1327 if (scratch[0] != '/') { 1328 tmp = strrchr(source, '/'); 1329 if (tmp == NULL) { /* Whoa! Something's hosed! */ 1330 O_DPRINTF("Internal error... corrupt path.\n"); 1331 return (NULL); 1332 } 1333 /* Now strip off just the directory path */ 1334 *(tmp+1) = '\0'; /* Keeping the last '/' */ 1335 /* and append the new link */ 1336 (void) strcat(source, scratch); 1337 /* 1338 * Note: At this point, source should have "../"s 1339 * but we'll clean it up in the next pass through 1340 * the loop. 1341 */ 1342 } else { 1343 /* It's an absolute link so no worries */ 1344 strcpy(source, scratch); 1345 } 1346 } 1347 /* Never reach here */ 1348 } 1349 1350 /* 1351 * Input - Space for client_path, phci_path and paddr fields of ioc structure 1352 * need to be allocated by the caller of this routine. 1353 */ 1354 int 1355 get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count) 1356 { 1357 char *physical_path, *physical_path_s; 1358 int retval; 1359 int fd; 1360 int initial_path_count; 1361 int current_path_count; 1362 int i; 1363 char *delimiter; 1364 int malloc_error = 0; 1365 int prop_buf_size; 1366 int pathlist_retry_count = 0; 1367 1368 if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) { 1369 if ((physical_path = get_slash_devices_from_osDevName( 1370 dev_path, STANDARD_DEVNAME_HANDLING)) == NULL) { 1371 return (L_INVALID_PATH); 1372 } 1373 if (strncmp(physical_path, SCSI_VHCI, 1374 strlen(SCSI_VHCI)) != 0) { 1375 free(physical_path); 1376 return (L_INVALID_PATH); 1377 } 1378 } else { 1379 if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) { 1380 return (L_MALLOC_FAILED); 1381 } 1382 (void) strcpy(physical_path, dev_path); 1383 } 1384 physical_path_s = physical_path; 1385 1386 /* move beyond "/devices" prefix */ 1387 physical_path += DEV_PREFIX_STRLEN-1; 1388 /* remove :c,raw suffix */ 1389 delimiter = strrchr(physical_path, ':'); 1390 /* if we didn't find the ':' fine, else truncate */ 1391 if (delimiter != NULL) { 1392 *delimiter = '\0'; 1393 } 1394 1395 /* 1396 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO 1397 * at least twice. The first time will get the path count 1398 * and the size of the ioctl propoerty buffer. The second 1399 * time will get the path_info for each path. 1400 * 1401 * It's possible that additional paths are added while this 1402 * code is running. If the path count increases between the 1403 * 2 ioctl's above, then we'll retry (and assume all is well). 1404 */ 1405 (void) strcpy(ioc->client, physical_path); 1406 ioc->buf_elem = 1; 1407 ioc->ret_elem = (uint_t *)&(initial_path_count); 1408 ioc->ret_buf = NULL; 1409 1410 /* free physical path */ 1411 free(physical_path_s); 1412 1413 /* 0 buf_size asks driver to return actual size needed */ 1414 /* open the ioctl file descriptor */ 1415 if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) { 1416 return (L_OPEN_PATH_FAIL); 1417 } 1418 1419 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); 1420 if (retval != 0) { 1421 close(fd); 1422 return (L_SCSI_VHCI_ERROR); 1423 } 1424 prop_buf_size = SV_PROP_MAX_BUF_SIZE; 1425 1426 1427 while (pathlist_retry_count <= RETRY_PATHLIST) { 1428 ioc->buf_elem = initial_path_count; 1429 /* Make driver put actual # paths in variable */ 1430 ioc->ret_elem = (uint_t *)&(current_path_count); 1431 1432 /* 1433 * Allocate space for array of path_info structures. 1434 * Allocate enough space for # paths from get_pathcount 1435 */ 1436 ioc->ret_buf = (sv_path_info_t *) 1437 calloc(initial_path_count, sizeof (sv_path_info_t)); 1438 if (ioc->ret_buf == NULL) { 1439 close(fd); 1440 return (L_MALLOC_FAILED); 1441 } 1442 1443 /* 1444 * Allocate space for path properties returned by driver 1445 */ 1446 malloc_error = 0; 1447 for (i = 0; i < initial_path_count; i++) { 1448 ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size; 1449 if ((ioc->ret_buf[i].ret_prop.buf = 1450 (caddr_t)malloc(prop_buf_size)) == NULL) { 1451 malloc_error = 1; 1452 break; 1453 } 1454 if ((ioc->ret_buf[i].ret_prop.ret_buf_size = 1455 (uint_t *)malloc(sizeof (uint_t))) == NULL) { 1456 malloc_error = 1; 1457 break; 1458 } 1459 } 1460 if (malloc_error == 1) { 1461 for (i = 0; i < initial_path_count; i++) { 1462 free(ioc->ret_buf[i].ret_prop.buf); 1463 free(ioc->ret_buf[i].ret_prop.ret_buf_size); 1464 } 1465 free(ioc->ret_buf); 1466 close(fd); 1467 return (L_MALLOC_FAILED); 1468 } 1469 1470 retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); 1471 if (retval != 0) { 1472 for (i = 0; i < initial_path_count; i++) { 1473 free(ioc->ret_buf[i].ret_prop.buf); 1474 free(ioc->ret_buf[i].ret_prop.ret_buf_size); 1475 } 1476 free(ioc->ret_buf); 1477 close(fd); 1478 return (L_SCSI_VHCI_ERROR); 1479 } 1480 if (initial_path_count < current_path_count) { 1481 /* then a new path was added */ 1482 pathlist_retry_count++; 1483 initial_path_count = current_path_count; 1484 } else { 1485 break; 1486 } 1487 } 1488 /* we are done with ioctl's, lose the fd */ 1489 close(fd); 1490 1491 /* 1492 * Compare the length num elements from the ioctl response 1493 * and the caller's request - use smaller value. 1494 * 1495 * pathlist_p->path_count now has count returned from ioctl. 1496 * ioc.buf_elem has the value the caller provided. 1497 */ 1498 if (initial_path_count < current_path_count) { 1499 /* More paths exist than we allocated space for */ 1500 *path_count = initial_path_count; 1501 } else { 1502 *path_count = current_path_count; 1503 } 1504 1505 return (0); 1506 } 1507 1508 int 1509 get_mode_page(char *path, uchar_t **pg_buf) 1510 { 1511 struct mode_header_g1 *mode_header_ptr; 1512 int status, size, fd; 1513 1514 /* open controller */ 1515 if ((fd = open(path, O_NDELAY | O_RDWR)) == -1) 1516 return (-1); /* L_OPEN_PATH_FAIL */ 1517 1518 /* 1519 * Read the first part of the page to get the page size 1520 */ 1521 size = 20; 1522 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { 1523 (void) close(fd); 1524 return (L_MALLOC_FAILED); 1525 } 1526 /* read page */ 1527 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 1528 0, MODEPAGE_ALLPAGES)) { 1529 (void) close(fd); 1530 (void) free(*pg_buf); 1531 return (status); 1532 } 1533 /* Now get the size for all pages */ 1534 mode_header_ptr = (struct mode_header_g1 *)(void *)*pg_buf; 1535 size = ntohs(mode_header_ptr->length) + 1536 sizeof (mode_header_ptr->length); 1537 (void) free(*pg_buf); 1538 if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { 1539 (void) close(fd); 1540 return (L_MALLOC_FAILED); 1541 } 1542 /* read all pages */ 1543 if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 1544 0, MODEPAGE_ALLPAGES)) { 1545 (void) close(fd); 1546 (void) free(*pg_buf); 1547 return (status); 1548 } 1549 (void) close(fd); 1550 return (0); 1551 } 1552 1553 /* 1554 * Dump a structure in hexadecimal. 1555 */ 1556 void 1557 dump_hex_data(char *hdr, uchar_t *src, int nbytes, int format) 1558 { 1559 int i; 1560 int n; 1561 char *p; 1562 char s[256]; 1563 1564 assert(format == HEX_ONLY || format == HEX_ASCII); 1565 1566 (void) strcpy(s, hdr); 1567 for (p = s; *p; p++) { 1568 *p = ' '; 1569 } 1570 1571 p = hdr; 1572 while (nbytes > 0) { 1573 (void) fprintf(stdout, "%s", p); 1574 p = s; 1575 n = MIN(nbytes, BYTES_PER_LINE); 1576 for (i = 0; i < n; i++) { 1577 (void) fprintf(stdout, "%02x ", src[i] & 0xff); 1578 } 1579 if (format == HEX_ASCII) { 1580 for (i = BYTES_PER_LINE-n; i > 0; i--) { 1581 (void) fprintf(stdout, " "); 1582 } 1583 (void) fprintf(stdout, " "); 1584 for (i = 0; i < n; i++) { 1585 (void) fprintf(stdout, "%c", 1586 isprint(src[i]) ? src[i] : '.'); 1587 } 1588 } 1589 (void) fprintf(stdout, "\n"); 1590 nbytes -= n; 1591 src += n; 1592 } 1593 } 1594