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 /*LINTLIBRARY*/ 28 29 /* 30 * 31 * This module is part of the photon Command Line 32 * Interface program. 33 * 34 */ 35 36 /* 37 * I18N message number ranges 38 * This file: 11500 - 11999 39 * Shared common messages: 1 - 1999 40 */ 41 42 /* #define _POSIX_SOURCE 1 */ 43 44 /* Includes */ 45 #include <stdlib.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <sys/file.h> 49 #include <sys/types.h> 50 #include <fcntl.h> 51 #include <sys/sunddi.h> 52 #include <sys/systm.h> 53 #include <sys/scsi/scsi.h> 54 #include <nl_types.h> 55 #include <unistd.h> 56 #include <l_common.h> 57 #include <stgcom.h> 58 #include <l_error.h> 59 #include <g_state.h> 60 #include <errno.h> 61 #include <devid.h> 62 #include <libdevinfo.h> 63 64 65 /* Defines */ 66 /* Because of a bug in Unisys Envsen card, Bug ID:1266986. */ 67 #define SCSI_ESI_PCV 0x01 /* Page Code Valid */ 68 #define SCSI_ESI_PF 0x10 /* Page Format */ 69 #define ACTION_MASK 0x1f /* Persistent Reserve In command */ 70 #define IMMED 1 /* make the stop immediate */ 71 #define DAK_PROD_STR "SUNWGS INT FCBPL" 72 #define DAK_BOXNAME_LEN 16 /* The length of the daktari boxname */ 73 #define DAK_BOXNAME_OFF 36 /* The offset of the daktari boxname */ 74 75 76 77 /* Global variables */ 78 extern nl_catd l_catd; 79 80 81 /* Forward declarations */ 82 static int scsi_read_capacity_16_cmd(int, struct scsi_capacity_16 *, int); 83 84 85 /* External functions */ 86 87 88 int 89 g_scsi_persistent_reserve_in_cmd(int fd, uchar_t *buf_ptr, 90 int buf_len, uchar_t action) 91 { 92 struct uscsi_cmd ucmd; 93 my_cdb_g1 cdb = {SCMD_PERS_RESERV_IN, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 94 struct scsi_extended_sense sense; 95 96 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 97 return (L_INVALID_ARG); 98 } 99 100 (void) memset(buf_ptr, 0, buf_len); 101 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 102 cdb.byte1 = action & ACTION_MASK; 103 cdb.byte7 = (buf_len>>8) & 0xff; 104 cdb.byte8 = buf_len & 0xff; 105 ucmd.uscsi_cdb = (caddr_t)&cdb; 106 ucmd.uscsi_cdblen = CDB_GROUP1; 107 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 108 ucmd.uscsi_buflen = buf_len; 109 ucmd.uscsi_rqbuf = (caddr_t)&sense; 110 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 111 ucmd.uscsi_timeout = 60; 112 113 if (buf_len & 0x03) { 114 return (L_PR_INVLD_TRNSFR_LEN); 115 } 116 /* Do in SILENT mode as cmd may not be supported. */ 117 return (cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT)); 118 } 119 /* 120 * Send Diagnostic command 121 * 122 * NOTE: This function includes a delay. 123 */ 124 int 125 g_scsi_send_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len) 126 { 127 struct uscsi_cmd ucmd; 128 uchar_t cdb[] = {SCMD_SDIAG, SCSI_ESI_PF, 0, 0, 0, 0}; 129 struct scsi_extended_sense sense; 130 int err; 131 132 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 133 return (L_INVALID_ARG); 134 } 135 136 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 137 cdb[3] = (buf_len>>8) & 0xff; 138 cdb[4] = buf_len & 0xff; 139 ucmd.uscsi_cdb = (caddr_t)cdb; 140 ucmd.uscsi_cdblen = CDB_GROUP0; 141 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 142 ucmd.uscsi_buflen = buf_len; 143 ucmd.uscsi_rqbuf = (caddr_t)&sense; 144 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 145 ucmd.uscsi_timeout = 60; 146 147 if (err = cmd(fd, &ucmd, USCSI_WRITE)) { 148 return (err); 149 } 150 /* 151 * Allow time for things to stabilize. 152 */ 153 sleep(5); 154 return (0); 155 } 156 157 /* 158 * Internal routine to allow manipulation of the cdb[1] byte 159 * in receive diag. 160 */ 161 static int 162 rec_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code, 163 uchar_t cdb_one) 164 { 165 struct uscsi_cmd ucmd; 166 uchar_t cdb[] = {SCMD_GDIAG, 0, 0, 0, 0, 0}; 167 struct scsi_extended_sense sense; 168 169 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 170 return (L_INVALID_ARG); 171 } 172 173 (void) memset(buf_ptr, 0, buf_len); 174 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 175 cdb[1] = cdb_one; 176 cdb[2] = page_code; 177 cdb[3] = (buf_len>>8) & 0xff; 178 cdb[4] = buf_len & 0xff; 179 ucmd.uscsi_cdb = (caddr_t)cdb; 180 ucmd.uscsi_cdblen = CDB_GROUP0; 181 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 182 ucmd.uscsi_buflen = buf_len; 183 ucmd.uscsi_rqbuf = (caddr_t)&sense; 184 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 185 ucmd.uscsi_timeout = 60; 186 return (cmd(fd, &ucmd, USCSI_READ)); 187 } 188 189 190 /* 191 * Receive Diagnostic command 192 */ 193 int 194 g_scsi_rec_diag_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code) 195 { 196 int status; 197 198 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 199 return (L_INVALID_ARG); 200 } 201 202 if (buf_len & 0x03) { 203 return (L_RD_INVLD_TRNSFR_LEN); 204 } 205 206 /* 207 * The a5k and newer enclosures abide by the SCSI spec 208 * (SPC-2: 7.15) but the SSA does not. It requires 209 * 0x10 to be present in cdb[1]. 210 * 211 * For enclosures that abide by the spec, the first call 212 * will work. For SSAs the first call will fail, at which 213 * point we try again with the SSA specific value. 214 */ 215 status = rec_diag_cmd(fd, buf_ptr, buf_len, page_code, SCSI_ESI_PCV); 216 if (status != 0) { 217 status = rec_diag_cmd(fd, buf_ptr, buf_len, page_code, SCSI_ESI_PF); 218 } 219 return (status); 220 } 221 222 /* 223 * Write buffer command set up to download firmware 224 */ 225 int 226 g_scsi_writebuffer_cmd(int fd, int off, uchar_t *buf_ptr, int buf_len, 227 int sp, int bid) 228 { 229 struct uscsi_cmd ucmd; 230 my_cdb_g1 cdb = {SCMD_WRITE_BUFFER, 0x4, 0, 0, 0, 0, 0, 0, 0, 0}; 231 struct scsi_extended_sense sense; 232 233 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 234 return (L_INVALID_ARG); 235 } 236 237 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 238 cdb.byte1 |= sp; /* set the save bit */ 239 cdb.byte2 = (char)(bid & 0xff); 240 cdb.byte3 = off>>16; /* bytes 3-5 contain file offset */ 241 cdb.byte4 = (off>>8) & 0xff; 242 cdb.byte5 = off & 0xff; 243 cdb.byte6 = buf_len>>16; /* bytes 6-8 contain file length */ 244 cdb.byte7 = (buf_len>>8) & 0xff; 245 cdb.byte8 = buf_len & 0xff; 246 ucmd.uscsi_cdb = (caddr_t)&cdb; 247 ucmd.uscsi_cdblen = CDB_GROUP1; 248 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 249 ucmd.uscsi_buflen = buf_len; 250 ucmd.uscsi_rqbuf = (caddr_t)&sense; 251 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 252 ucmd.uscsi_timeout = 240; /* long timeout required */ 253 254 return (cmd(fd, &ucmd, USCSI_WRITE)); 255 } 256 257 /* 258 * Read buffer command set up to upload firmware 259 * Reads from code image starting at offset 260 * "code_off" for "buf_len" bytes. 261 */ 262 int 263 g_scsi_readbuffer_cmd(int fd, uchar_t *buf_ptr, int buf_len, int code_off) 264 { 265 struct uscsi_cmd ucmd; 266 my_cdb_g1 cdb = {SCMD_READ_BUFFER, 0x5, 0, 0, 0, 0, 0, 0, 0, 0}; 267 struct scsi_extended_sense sense; 268 269 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 270 return (L_INVALID_ARG); 271 } 272 273 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 274 cdb.byte3 = (code_off >> 16) & 0xff; 275 cdb.byte4 = (code_off >> 8) & 0xff; 276 cdb.byte5 = code_off & 0xff; 277 cdb.byte6 = buf_len>>16; /* bytes 6-8 contain file length */ 278 cdb.byte7 = (buf_len>>8) & 0xff; 279 cdb.byte8 = buf_len & 0xff; 280 ucmd.uscsi_cdb = (caddr_t)&cdb; 281 ucmd.uscsi_cdblen = CDB_GROUP1; 282 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 283 ucmd.uscsi_buflen = buf_len; 284 ucmd.uscsi_rqbuf = (caddr_t)&sense; 285 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 286 ucmd.uscsi_timeout = 120; 287 288 return (cmd(fd, &ucmd, USCSI_READ)); 289 } 290 291 int 292 g_scsi_inquiry_cmd(int fd, uchar_t *buf_ptr, int buf_len) 293 { 294 struct uscsi_cmd ucmd; 295 my_cdb_g0 cdb = {SCMD_INQUIRY, 0, 0, 0, 0, 0}; 296 struct scsi_extended_sense sense; 297 int myreturn; 298 299 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 300 return (L_INVALID_ARG); 301 } 302 303 (void) memset(buf_ptr, 0, buf_len); 304 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 305 cdb.count = (uchar_t)buf_len; 306 ucmd.uscsi_cdb = (caddr_t)&cdb; 307 ucmd.uscsi_cdblen = CDB_GROUP0; 308 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 309 ucmd.uscsi_buflen = buf_len; 310 ucmd.uscsi_rqbuf = (caddr_t)&sense; 311 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 312 ucmd.uscsi_timeout = 60; 313 314 myreturn = cmd(fd, &ucmd, USCSI_READ | USCSI_SILENT); 315 if (myreturn) { 316 return (myreturn); /* != 0, error just return */ 317 } 318 319 /* 320 * This is a work around for the format of Daktari's 321 * SCSI inquiry page information. The name of the enclosure 322 * is not in the same place that products like the a5000 place it 323 * so we have to copy the string to the expected location. 324 */ 325 if (strncmp((char *)&buf_ptr[16], DAK_PROD_STR, 326 strlen(DAK_PROD_STR)) == 0) { 327 strncpy((char *)&buf_ptr[96], (char *)&buf_ptr[DAK_BOXNAME_OFF], 328 DAK_BOXNAME_LEN); 329 } 330 331 return (myreturn); 332 } 333 334 int 335 g_scsi_log_sense_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t page_code) 336 { 337 struct uscsi_cmd ucmd; 338 my_cdb_g1 cdb = {SCMD_LOG_SENSE, 0, 0x40, 0, 0, 0, 0, 0, 0, 0}; 339 struct scsi_extended_sense sense; 340 341 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 342 return (L_INVALID_ARG); 343 } 344 345 /* clear buffers on cmds that read data */ 346 (void) memset(buf_ptr, 0, buf_len); 347 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 348 cdb.byte2 |= page_code; /* requested page */ 349 cdb.byte7 = buf_len>>8; 350 cdb.byte8 = buf_len & 0xff; 351 ucmd.uscsi_cdb = (caddr_t)&cdb; 352 ucmd.uscsi_cdblen = CDB_GROUP1; 353 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 354 ucmd.uscsi_buflen = buf_len; 355 ucmd.uscsi_rqbuf = (caddr_t)&sense; 356 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 357 ucmd.uscsi_timeout = 120; 358 return (cmd(fd, &ucmd, USCSI_READ)); 359 } 360 361 /* 362 * MODE SELECT 363 * 364 * MODE SELECT USCSI command 365 * 366 * sp is the save pages bit - Must be bit 0 - 367 * 368 */ 369 int 370 g_scsi_mode_select_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t sp) 371 { 372 struct uscsi_cmd ucmd; 373 /* 10 byte Mode Select cmd */ 374 my_cdb_g1 cdb = {SCMD_MODE_SELECT_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 375 struct scsi_extended_sense sense; 376 377 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 378 return (L_INVALID_ARG); 379 } 380 381 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 382 cdb.byte1 = (sp & 1) | 0x10; /* 0x10 is the PF bit */ 383 cdb.byte7 = buf_len>>8; 384 cdb.byte8 = buf_len & 0xff; 385 386 ucmd.uscsi_cdb = (caddr_t)&cdb; 387 ucmd.uscsi_cdblen = CDB_GROUP1; 388 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 389 ucmd.uscsi_buflen = buf_len; 390 ucmd.uscsi_rqbuf = (caddr_t)&sense; 391 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 392 ucmd.uscsi_timeout = 120; 393 394 return (cmd(fd, &ucmd, USCSI_WRITE)); 395 } 396 397 398 /* 399 * MODE SENSE USCSI command 400 * 401 * 402 * pc = page control field 403 * page_code = Pages to return 404 */ 405 int 406 g_scsi_mode_sense_cmd(int fd, 407 uchar_t *buf_ptr, 408 int buf_len, 409 uchar_t pc, 410 uchar_t page_code) 411 { 412 struct uscsi_cmd ucmd; 413 /* 10 byte Mode Select cmd */ 414 my_cdb_g1 cdb = {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 415 struct scsi_extended_sense sense; 416 int status; 417 static int uscsi_count; 418 419 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 420 return (L_INVALID_ARG); 421 } 422 423 (void) memset(buf_ptr, 0, buf_len); 424 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 425 /* Just for me - a sanity check */ 426 if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) || 427 (buf_len > MAX_MODE_SENSE_LEN)) { 428 return (L_ILLEGAL_MODE_SENSE_PAGE); 429 } 430 cdb.byte2 = (pc << 6) + page_code; 431 cdb.byte7 = buf_len>>8; 432 cdb.byte8 = buf_len & 0xff; 433 ucmd.uscsi_cdb = (caddr_t)&cdb; 434 ucmd.uscsi_cdblen = CDB_GROUP1; 435 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 436 ucmd.uscsi_buflen = buf_len; 437 ucmd.uscsi_rqbuf = (caddr_t)&sense; 438 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 439 ucmd.uscsi_timeout = 120; 440 441 status = cmd(fd, &ucmd, USCSI_READ); 442 /* Bytes actually transfered */ 443 if (status == 0) { 444 uscsi_count = buf_len - ucmd.uscsi_resid; 445 S_DPRINTF(" Number of bytes read on " 446 "Mode Sense 0x%x\n", uscsi_count); 447 if (getenv("_LUX_D_DEBUG") != NULL) { 448 (void) g_dump(" Mode Sense data: ", buf_ptr, 449 uscsi_count, HEX_ASCII); 450 } 451 } 452 return (status); 453 } 454 455 int 456 g_scsi_read_capacity_cmd(int fd, uchar_t *buf_ptr, int buf_len) 457 { 458 struct uscsi_cmd ucmd; 459 my_cdb_g1 cdb = {SCMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 460 struct scsi_extended_sense sense; 461 462 if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { 463 return (L_INVALID_ARG); 464 } 465 466 /* clear buffers on on cmds that read data */ 467 (void) memset(buf_ptr, 0, buf_len); 468 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 469 470 ucmd.uscsi_cdb = (caddr_t)&cdb; 471 ucmd.uscsi_cdblen = CDB_GROUP1; 472 ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; 473 ucmd.uscsi_buflen = buf_len; 474 ucmd.uscsi_rqbuf = (caddr_t)&sense; 475 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 476 ucmd.uscsi_timeout = 60; 477 return (cmd(fd, &ucmd, USCSI_READ)); 478 } 479 480 int 481 g_scsi_read_capacity_1016_cmd(int fd, 482 struct scsi_capacity_16 *cap_ptr, int buf_len) 483 { 484 struct uscsi_cmd ucmd; 485 my_cdb_g1 cdb = {SCMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 486 struct scsi_extended_sense sense; 487 struct scsi_capacity cap_old; 488 int ret; 489 490 if ((fd < 0) || (cap_ptr == NULL) || 491 (buf_len < sizeof (struct scsi_capacity_16))) { 492 return (L_INVALID_ARG); 493 } 494 495 /* clear buffers on on cmds that read data */ 496 (void) memset((char *)&cap_old, 0, sizeof (cap_old)); 497 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 498 499 ucmd.uscsi_cdb = (caddr_t)&cdb; 500 ucmd.uscsi_cdblen = CDB_GROUP1; 501 ucmd.uscsi_bufaddr = (caddr_t)&cap_old; 502 ucmd.uscsi_buflen = sizeof (cap_old); 503 ucmd.uscsi_rqbuf = (caddr_t)&sense; 504 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 505 ucmd.uscsi_timeout = 60; 506 507 ret = cmd(fd, &ucmd, USCSI_READ); 508 if (cap_old.capacity == 0xffffffff) { 509 /* 510 * A capacity of 0xffffffff in response to a 511 * READ CAPACITY 10 indicates that the lun 512 * is too large to report the size in a 32 bit 513 * value, and a READ CAPACITY 16 is required 514 * to get the correct size. 515 */ 516 ret = scsi_read_capacity_16_cmd(fd, cap_ptr, buf_len); 517 } else { 518 cap_ptr->sc_capacity = cap_old.capacity; 519 cap_ptr->sc_lbasize = cap_old.lbasize; 520 } 521 return (ret); 522 } 523 524 static int 525 scsi_read_capacity_16_cmd(int fd, 526 struct scsi_capacity_16 *cap_ptr, int buf_len) 527 { 528 struct uscsi_cmd ucmd; 529 union scsi_cdb cdb; 530 struct scsi_extended_sense sense; 531 532 if ((fd < 0) || (cap_ptr == NULL) || 533 (buf_len < sizeof (struct scsi_capacity_16))) { 534 return (L_INVALID_ARG); 535 } 536 /* clear buffers on on cmds that read data */ 537 (void) memset((char *)cap_ptr, 0, buf_len); 538 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 539 (void) memset((char *)&cdb, 0, sizeof (union scsi_cdb)); 540 541 ucmd.uscsi_cdb = (caddr_t)&cdb; 542 ucmd.uscsi_cdblen = CDB_GROUP4; 543 ucmd.uscsi_bufaddr = (caddr_t)cap_ptr; 544 ucmd.uscsi_buflen = buf_len; 545 ucmd.uscsi_rqbuf = (caddr_t)&sense; 546 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 547 ucmd.uscsi_timeout = 60; 548 549 /* 550 * Read Capacity (16) is a Service Action In command. One 551 * command byte (0x9E) is overloaded for multiple operations, 552 * with the second CDB byte specifying the desired operation 553 */ 554 cdb.scc_cmd = SCMD_SVC_ACTION_IN_G4; 555 cdb.cdb_opaque[1] = SSVC_ACTION_READ_CAPACITY_G4; 556 557 /* 558 * Fill in allocation length field 559 */ 560 cdb.cdb_opaque[10] = 561 (uchar_t)((ucmd.uscsi_buflen & 0xff000000) >> 24); 562 cdb.cdb_opaque[11] = 563 (uchar_t)((ucmd.uscsi_buflen & 0x00ff0000) >> 16); 564 cdb.cdb_opaque[12] = 565 (uchar_t)((ucmd.uscsi_buflen & 0x0000ff00) >> 8); 566 cdb.cdb_opaque[13] = 567 (uchar_t)(ucmd.uscsi_buflen & 0x000000ff); 568 569 return (cmd(fd, &ucmd, USCSI_READ)); 570 } 571 572 int 573 g_scsi_release_cmd(int fd) 574 { 575 struct uscsi_cmd ucmd; 576 const my_cdb_g0 cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0}; 577 struct scsi_extended_sense sense; 578 579 if (fd < 0) { 580 return (L_INVALID_ARG); 581 } 582 583 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 584 585 ucmd.uscsi_cdb = (caddr_t)&cdb; 586 ucmd.uscsi_cdblen = CDB_GROUP0; 587 ucmd.uscsi_bufaddr = NULL; 588 ucmd.uscsi_buflen = 0; 589 ucmd.uscsi_rqbuf = (caddr_t)&sense; 590 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 591 ucmd.uscsi_timeout = 60; 592 return (cmd(fd, &ucmd, 0)); 593 } 594 595 int 596 g_scsi_reserve_cmd(int fd) 597 { 598 struct uscsi_cmd ucmd; 599 const my_cdb_g0 cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0}; 600 struct scsi_extended_sense sense; 601 602 if (fd < 0) { 603 return (L_INVALID_ARG); 604 } 605 606 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 607 608 ucmd.uscsi_cdb = (caddr_t)&cdb; 609 ucmd.uscsi_cdblen = CDB_GROUP0; 610 ucmd.uscsi_bufaddr = NULL; 611 ucmd.uscsi_buflen = 0; 612 ucmd.uscsi_rqbuf = (caddr_t)&sense; 613 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 614 ucmd.uscsi_timeout = 60; 615 return (cmd(fd, &ucmd, 0)); 616 } 617 618 int 619 g_scsi_start_cmd(int fd) 620 { 621 struct uscsi_cmd ucmd; 622 /* 623 * Use this to induce a SCSI error 624 * const my_cdb_g0 cdb = {SCMD_START_STOP, 0, 0xff, 0, 1, 0}; 625 */ 626 const my_cdb_g0 cdb = {SCMD_START_STOP, 0, 0, 0, 1, 0}; 627 struct scsi_extended_sense sense; 628 629 if (fd < 0) { 630 return (L_INVALID_ARG); 631 } 632 633 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 634 ucmd.uscsi_cdb = (caddr_t)&cdb; 635 ucmd.uscsi_cdblen = CDB_GROUP0; 636 ucmd.uscsi_bufaddr = NULL; 637 ucmd.uscsi_buflen = 0; 638 ucmd.uscsi_rqbuf = (caddr_t)&sense; 639 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 640 ucmd.uscsi_timeout = 240; /* takes a while to start all */ 641 return (cmd(fd, &ucmd, 0)); 642 } 643 644 int 645 g_scsi_stop_cmd(int fd, int immediate_flag) 646 { 647 struct uscsi_cmd ucmd; 648 my_cdb_g0 cdb = {SCMD_START_STOP, 0, 0, 0, 0, 0}; 649 struct scsi_extended_sense sense; 650 651 if (fd < 0) { 652 return (L_INVALID_ARG); 653 } 654 655 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 656 if (immediate_flag) { 657 cdb.lba_msb = IMMED; 658 } 659 ucmd.uscsi_cdb = (caddr_t)&cdb; 660 ucmd.uscsi_cdblen = CDB_GROUP0; 661 ucmd.uscsi_bufaddr = NULL; 662 ucmd.uscsi_buflen = 0; 663 ucmd.uscsi_rqbuf = (caddr_t)&sense; 664 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 665 ucmd.uscsi_timeout = 120; 666 return (cmd(fd, &ucmd, 0)); 667 } 668 669 int 670 g_scsi_tur(int fd) 671 { 672 struct uscsi_cmd ucmd; 673 const my_cdb_g0 cdb = {SCMD_TEST_UNIT_READY, 0, 0, 0, 0, 0}; 674 struct scsi_extended_sense sense; 675 676 if (fd < 0) { 677 return (L_INVALID_ARG); 678 } 679 680 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 681 682 ucmd.uscsi_cdb = (caddr_t)&cdb; 683 ucmd.uscsi_cdblen = CDB_GROUP0; 684 ucmd.uscsi_bufaddr = NULL; 685 ucmd.uscsi_buflen = 0; 686 ucmd.uscsi_rqbuf = (caddr_t)&sense; 687 ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); 688 ucmd.uscsi_timeout = 60; 689 return (cmd(fd, &ucmd, 0)); 690 } 691 692 /* 693 * NOTE: This function includes a delay. 694 */ 695 int 696 g_scsi_reset(int fd) 697 { 698 struct uscsi_cmd ucmd; 699 struct scsi_extended_sense sense; 700 int err; 701 702 if (fd < 0) { 703 return (L_INVALID_ARG); 704 } 705 706 (void) memset((char *)&ucmd, 0, sizeof (ucmd)); 707 708 ucmd.uscsi_cdb = NULL; 709 ucmd.uscsi_cdblen = 0; 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 if (err = cmd(fd, &ucmd, USCSI_RESET)) { 716 return (err); 717 } 718 /* 719 * Allow time for things to stabilize. 720 */ 721 sleep(20); 722 return (0); 723 } 724 725 726 /* 727 * Description: 728 * Retrieves a devid from a device path. 729 * 730 * Input Values: 731 * 732 * devpath: Valid block device path. 733 * Example:/devices/scsi_vhci/ssd@g280000602200416d6257333030303353:c,raw 734 * 735 * devid: ptr to ddi_devid_t struct 736 * root: root handle to device tree snapshot 737 * drvr_name: driver name to start the node tree search 738 * On success, devid points to device tree handle to devid 739 * di_fini on root will invalidate devid pointer 740 * 741 * Return Value: 742 * 0 on success 743 * non-zero on failure 744 */ 745 int 746 g_devid_get(char *devpath, ddi_devid_t *devid, di_node_t root, 747 const char *drvr_name) 748 { 749 char *cptr; 750 char rootpath[MAXPATHLEN]; 751 di_node_t node; 752 char *devfs_path = NULL; 753 hrtime_t start_time, end_time; 754 char *env = NULL; 755 756 if (devpath == NULL || devid == NULL || drvr_name == NULL) { 757 return (L_INVALID_ARG); 758 } 759 760 if ((env = getenv("_LUX_T_DEBUG")) != NULL) { 761 start_time = gethrtime(); 762 } 763 764 *devid = NULL; 765 rootpath[0] = '\0'; 766 767 /* 768 * Form a valid root path by stripping off the /devices/ mount point 769 * prefix and the minor name (:a[,raw]). 770 */ 771 if (strstr(devpath, DEV_PREFIX)) { 772 strcat(rootpath, devpath + strlen(DEV_PREFIX) - 1); 773 if (strchr(devpath, ':')) { 774 cptr = strrchr(rootpath, ':'); 775 *cptr = '\0'; 776 } else { 777 return (L_INVALID_PATH); 778 } 779 } else { 780 return (L_INVALID_PATH); 781 } 782 783 /* point to first node which matches portdrvr */ 784 node = di_drv_first_node(drvr_name, root); 785 if (node == DI_NODE_NIL) { 786 /* 787 * Could not find driver node 788 */ 789 return (L_NO_DEVID); 790 } 791 792 while (node != DI_NODE_NIL) { 793 if ((devfs_path = di_devfs_path(node)) != NULL) { 794 if (strcmp(rootpath, devfs_path) == 0) { 795 *devid = di_devid(node); 796 di_devfs_path_free(devfs_path); 797 break; 798 } 799 di_devfs_path_free(devfs_path); 800 } 801 node = di_drv_next_node(node); 802 } 803 804 if (env != NULL) { 805 end_time = gethrtime(); 806 (void) fprintf(stdout, 807 " g_devid_get: " 808 "\t\tTime = %lld millisec\n", 809 (end_time - start_time)/1000000); 810 } 811 /* Did we get back a handle? */ 812 if (*devid != NULL) { 813 return (0); 814 } else { /* Couldn't get a devid. */ 815 return (L_NO_DEVID); 816 } 817 } 818