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