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
g_scsi_persistent_reserve_in_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t action)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
g_scsi_send_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len)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
rec_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code,uchar_t cdb_one)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
g_scsi_rec_diag_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code)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
g_scsi_writebuffer_cmd(int fd,int off,uchar_t * buf_ptr,int buf_len,int sp,int bid)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
g_scsi_readbuffer_cmd(int fd,uchar_t * buf_ptr,int buf_len,int code_off)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
g_scsi_inquiry_cmd(int fd,uchar_t * buf_ptr,int buf_len)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
g_scsi_log_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t page_code)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
g_scsi_mode_select_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t sp)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
g_scsi_mode_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t pc,uchar_t page_code)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
g_scsi_read_capacity_cmd(int fd,uchar_t * buf_ptr,int buf_len)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
g_scsi_read_capacity_1016_cmd(int fd,struct scsi_capacity_16 * cap_ptr,int buf_len)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
scsi_read_capacity_16_cmd(int fd,struct scsi_capacity_16 * cap_ptr,int buf_len)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
g_scsi_release_cmd(int fd)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
g_scsi_reserve_cmd(int fd)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
g_scsi_start_cmd(int fd)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
g_scsi_stop_cmd(int fd,int immediate_flag)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
g_scsi_tur(int fd)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
g_scsi_reset(int fd)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
g_devid_get(char * devpath,ddi_devid_t * devid,di_node_t root,const char * drvr_name)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