1 /* $NetBSD: scsictl.c,v 1.30 2008/02/02 17:07:04 christos Exp $ */
4 * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * scsictl(8) - a program to manipulate SCSI devices and busses.
36 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: scsictl.c,v 1.30 2008/02/02 17:07:04 christos Exp $");
43 #include <sys/param.h>
44 #include <sys/ioctl.h>
45 #include <sys/scsiio.h>
56 #include <dev/scsipi/scsi_spc.h>
57 #include <dev/scsipi/scsipi_all.h>
58 #include <dev/scsipi/scsi_disk.h>
59 #include <dev/scsipi/scsipiconf.h>
65 const char *arg_names
;
66 void (*cmd_func
)(int, char *[]);
71 int fd
; /* file descriptor for device */
72 const char *dvname
; /* device name */
73 char dvname_store
[MAXPATHLEN
]; /* for opendisk(3) */
74 const char *cmdname
; /* command user issued */
75 const char *argnames
; /* helpstring: expected arguments */
76 struct scsi_addr dvaddr
; /* SCSI device's address */
78 void device_defects(int, char *[]);
79 void device_format(int, char *[]);
80 void device_identify(int, char *[]);
81 void device_reassign(int, char *[]);
82 void device_release(int, char *[]);
83 void device_reserve(int, char *[]);
84 void device_reset(int, char *[]);
85 void device_debug(int, char *[]);
86 void device_prevent(int, char *[]);
87 void device_allow(int, char *[]);
88 void device_start(int, char *[]);
89 void device_stop(int, char *[]);
90 void device_tur(int, char *[]);
91 void device_getcache(int, char *[]);
92 void device_setcache(int, char *[]);
93 void device_flushcache(int, char *[]);
94 void device_setspeed(int, char *[]);
96 struct command device_commands
[] = {
97 { "defects", "[primary] [grown] [block|byte|physical]",
99 { "format", "[blocksize [immediate]]", device_format
},
100 { "identify", "", device_identify
},
101 { "reassign", "blkno [blkno [...]]", device_reassign
},
102 { "release", "", device_release
},
103 { "reserve", "", device_reserve
},
104 { "reset", "", device_reset
},
105 { "debug", "level", device_debug
},
106 { "prevent", "", device_prevent
},
107 { "allow", "", device_allow
},
108 { "start", "", device_start
},
109 { "stop", "", device_stop
},
110 { "tur", "", device_tur
},
111 { "getcache", "", device_getcache
},
112 { "setcache", "none|r|w|rw [save]", device_setcache
},
113 { "flushcache", "", device_flushcache
},
114 { "setspeed", "[speed]", device_setspeed
},
115 { NULL
, NULL
, NULL
},
118 void bus_reset(int, char *[]);
119 void bus_scan(int, char *[]);
120 void bus_detach(int, char *[]);
122 struct command bus_commands
[] = {
123 { "reset", "", bus_reset
},
124 { "scan", "target lun", bus_scan
},
125 { "detach", "target lun", bus_detach
},
126 { NULL
, NULL
, NULL
},
130 main(int argc
, char *argv
[])
132 struct command
*commands
;
135 /* Must have at least: device command */
139 /* Skip program name, get and skip device name and command. */
146 * Open the device and determine if it's a scsibus or an actual
147 * device. Devices respond to the SCIOCIDENTIFY ioctl.
149 fd
= opendisk(dvname
, O_RDWR
, dvname_store
, sizeof(dvname_store
), 0);
151 if (errno
== ENOENT
) {
153 * Device doesn't exist. Probably trying to open
154 * a device which doesn't use disk semantics for
155 * device name. Try again, specifying "cooked",
156 * which leaves off the "r" in front of the device's
159 fd
= opendisk(dvname
, O_RDWR
, dvname_store
,
160 sizeof(dvname_store
), 1);
162 err(1, "%s", dvname
);
164 err(1, "%s", dvname
);
168 * Point the dvname at the actual device name that opendisk() opened.
170 dvname
= dvname_store
;
172 if (ioctl(fd
, SCIOCIDENTIFY
, &dvaddr
) < 0)
173 commands
= bus_commands
;
175 commands
= device_commands
;
177 /* Look up and call the command. */
178 for (i
= 0; commands
[i
].cmd_name
!= NULL
; i
++)
179 if (strcmp(cmdname
, commands
[i
].cmd_name
) == 0)
181 if (commands
[i
].cmd_name
== NULL
)
182 errx(1, "unknown %s command: %s",
183 commands
== bus_commands
? "bus" : "device", cmdname
);
185 argnames
= commands
[i
].arg_names
;
187 (*commands
[i
].cmd_func
)(argc
, argv
);
196 fprintf(stderr
, "usage: %s device command [arg [...]]\n",
199 fprintf(stderr
, " Commands pertaining to scsi devices:\n");
200 for (i
=0; device_commands
[i
].cmd_name
!= NULL
; i
++)
201 fprintf(stderr
, "\t%s %s\n", device_commands
[i
].cmd_name
,
202 device_commands
[i
].arg_names
);
203 fprintf(stderr
, " Commands pertaining to scsi busses:\n");
204 for (i
=0; bus_commands
[i
].cmd_name
!= NULL
; i
++)
205 fprintf(stderr
, "\t%s %s\n", bus_commands
[i
].cmd_name
,
206 bus_commands
[i
].arg_names
);
207 fprintf(stderr
, " Use `any' or `all' to wildcard target or lun\n");
217 * device_read_defect:
219 * Read primary and/or growth defect list in physical or block
220 * format from a direct access device.
222 * XXX Does not handle very large defect lists. Needs SCSI3 12
223 * byte READ DEFECT DATA command.
226 void print_bf_dd(union scsi_defect_descriptor
*);
227 void print_bfif_dd(union scsi_defect_descriptor
*);
228 void print_psf_dd(union scsi_defect_descriptor
*);
231 device_defects(int argc
, char *argv
[])
233 struct scsi_read_defect_data cmd
;
234 struct scsi_read_defect_data_data
*data
;
239 void (*pfunc
)(union scsi_defect_descriptor
*);
240 #define RDD_P_G_MASK 0x18
241 #define RDD_DLF_MASK 0x7
243 dlen
= USHRT_MAX
; /* XXX - this may not be enough room
244 * for all of the defects.
248 errx(1, "unable to allocate defect list");
249 memset(data
, 0, dlen
);
250 memset(&cmd
, 0, sizeof(cmd
));
254 /* determine which defect list(s) to read. */
255 for (i
= 0; i
< argc
; i
++) {
256 if (strncmp("primary", argv
[i
], 7) == 0) {
257 cmd
.flags
|= RDD_PRIMARY
;
260 if (strncmp("grown", argv
[i
], 5) == 0) {
261 cmd
.flags
|= RDD_GROWN
;
267 /* no defect list sepecified, assume both. */
268 if ((cmd
.flags
& (RDD_PRIMARY
|RDD_GROWN
)) == 0)
269 cmd
.flags
|= (RDD_PRIMARY
|RDD_GROWN
);
271 /* list format option. */
273 if (strncmp("block", argv
[i
], 5) == 0) {
277 else if (strncmp("byte", argv
[i
], 4) == 0) {
278 cmd
.flags
|= RDD_BFIF
;
281 else if (strncmp("physical", argv
[i
], 4) == 0) {
282 cmd
.flags
|= RDD_PSF
;
291 * no list format specified; since block format not
292 * recommended use physical sector format as default.
295 cmd
.flags
|= RDD_PSF
;
299 cmd
.opcode
= SCSI_READ_DEFECT_DATA
;
300 _lto2b(dlen
, &cmd
.length
[0]);
302 scsi_command(fd
, &cmd
, sizeof(cmd
), data
, dlen
, 30000, SCCMD_READ
);
306 /* is the defect list in the format asked for? */
307 if ((data
->flags
& RDD_DLF_MASK
) != dlfmt
) {
308 strcpy(msg
, "\n\tnotice:"
309 "requested defect list format not supported by device\n\n");
310 dlfmt
= (data
->flags
& RDD_DLF_MASK
);
313 if (data
->flags
& RDD_PRIMARY
)
314 strcat(msg
, "primary");
316 if (data
->flags
& RDD_GROWN
) {
317 if (data
->flags
& RDD_PRIMARY
)
318 strcat(msg
, " and ");
319 strcat(msg
, "grown");
322 strcat(msg
, " defects");
324 if ((data
->flags
& RDD_P_G_MASK
) == 0)
325 strcat(msg
, ": none reported\n");
328 printf("%s: scsibus%d target %d lun %d %s",
329 dvname
, dvaddr
.addr
.scsi
.scbus
, dvaddr
.addr
.scsi
.target
,
330 dvaddr
.addr
.scsi
.lun
, msg
);
332 /* device did not return either defect list. */
333 if ((data
->flags
& RDD_P_G_MASK
) == 0)
338 defects
= _2btol(data
->length
) /
339 sizeof(struct scsi_defect_descriptor_bf
);
341 strcpy(msg
, "block address\n"
345 defects
= _2btol(data
->length
) /
346 sizeof(struct scsi_defect_descriptor_bfif
);
347 pfunc
= print_bfif_dd
;
348 strcpy(msg
, " bytes from\n"
349 "cylinder head index\n"
350 "-------- ---- ----------\n");
353 defects
= _2btol(data
->length
) /
354 sizeof(struct scsi_defect_descriptor_psf
);
355 pfunc
= print_psf_dd
;
356 strcpy(msg
, "cylinder head sector\n"
357 "-------- ---- ----------\n");
361 /* device did not return any defects. */
367 printf(": %d\n", defects
);
372 /* print defect list. */
373 for (i
= 0 ; i
< defects
; i
++) {
374 pfunc(&data
->defect_descriptor
[i
]);
384 * Print a block format defect descriptor.
387 print_bf_dd(union scsi_defect_descriptor
*dd
)
391 block
= _4btol(dd
->bf
.block_address
);
393 printf("%13u\n", block
);
396 #define DEFECTIVE_TRACK 0xffffffff
401 * Print a bytes from index format defect descriptor.
404 print_bfif_dd(union scsi_defect_descriptor
*dd
)
408 u_int32_t bytes_from_index
;
410 cylinder
= _3btol(dd
->bfif
.cylinder
);
411 head
= dd
->bfif
.head
;
412 bytes_from_index
= _4btol(dd
->bfif
.bytes_from_index
);
414 printf("%8u %4u ", cylinder
, head
);
416 if (bytes_from_index
== DEFECTIVE_TRACK
)
417 printf("entire track defective\n");
419 printf("%10u\n", bytes_from_index
);
425 * Print a physical sector format defect descriptor.
428 print_psf_dd(union scsi_defect_descriptor
*dd
)
434 cylinder
= _3btol(dd
->psf
.cylinder
);
436 sector
= _4btol(dd
->psf
.sector
);
438 printf("%8u %4u ", cylinder
, head
);
440 if (sector
== DEFECTIVE_TRACK
)
441 printf("entire track defective\n");
443 printf("%10u\n", sector
);
449 * Format a direct access device.
452 device_format(int argc
, char *argv
[])
456 #define PC (65536/10)
457 static int complete
[] = {
458 PC
*1, PC
*2, PC
*3, PC
*4, PC
*5, PC
*6, PC
*7, PC
*8, PC
*9, 65536
460 char *cp
, buffer
[64];
461 struct scsi_sense_data sense
;
462 struct scsi_format_unit cmd
;
464 struct scsi_format_unit_defect_list_header header
;
465 /* optional initialization pattern */
466 /* optional defect list */
469 struct scsi_mode_parameter_header_6 header
;
470 struct scsi_general_block_descriptor blk_desc
;
471 struct page_disk_format format_page
;
474 struct scsi_mode_parameter_header_6 header
;
475 struct scsi_general_block_descriptor blk_desc
;
479 /* Blocksize is an optional argument. */
484 * Loop doing Request Sense to clear any pending Unit Attention.
486 * Multiple conditions may exist on the drive which are returned
489 for (i
= 0; i
< 8; i
++) {
490 scsi_request_sense(fd
, &sense
, sizeof (sense
));
491 if ((j
= SSD_SENSE_KEY(sense
.flags
)) == SKEY_NO_SENSE
)
495 * Make sure we cleared any pending Unit Attention
497 if (j
!= SKEY_NO_SENSE
) {
498 cp
= scsi_decode_sense((const unsigned char *) &sense
, 2,
499 buffer
, sizeof (buffer
));
500 errx(1, "failed to clean Unit Attention: %s", cp
);
504 * Get the DISK FORMAT mode page. SCSI-2 recommends specifying the
505 * interleave read from this page in the FORMAT UNIT command.
507 scsi_mode_sense(fd
, 0x03, 0x00, &mode_page
, sizeof(mode_page
));
509 j
= (mode_page
.format_page
.bytes_s
[0] << 8) |
510 (mode_page
.format_page
.bytes_s
[1]);
513 printf("current disk sector size: %hd\n", j
);
515 memset(&cmd
, 0, sizeof(cmd
));
517 cmd
.opcode
= SCSI_FORMAT_UNIT
;
518 memcpy(cmd
.interleave
, mode_page
.format_page
.interleave
,
519 sizeof(cmd
.interleave
));
522 * The blocksize on the device is only changed if the user
523 * specified a new blocksize. If not specified the blocksize
524 * used for the device will be the Default value in the device.
525 * We don't specify the number of blocks since the format
526 * command will always reformat the entire drive. Also by
527 * not specifying a block count the drive will reset the
528 * block count to the maximum available after the format
529 * completes if the blocksize was changed in the format.
530 * Finally, the new disk geometry will not but updated on
531 * the drive in permanent storage until _AFTER_ the format
532 * completes successfully.
535 blksize
= strtoul(argv
[0], &cp
, 10);
537 errx(1, "invalid block size: %s", argv
[0]);
539 memset(&data_select
, 0, sizeof(data_select
));
541 data_select
.header
.blk_desc_len
=
542 sizeof(struct scsi_general_block_descriptor
);
544 * blklen in desc is 3 bytes with a leading reserved byte
546 _lto4b(blksize
, &data_select
.blk_desc
.reserved
);
549 * Issue Mode Select to modify the device blocksize to be
550 * used on the Format. The modified device geometry will
551 * be stored as Current and Saved Page 3 parameters when
552 * the Format completes.
554 scsi_mode_select(fd
, 0, &data_select
, sizeof(data_select
));
557 * Since user specified a specific block size make sure it
558 * gets stored in the device when the format completes.
560 * Also scrub the defect list back to the manufacturers
563 cmd
.flags
= SFU_CMPLST
| SFU_FMTDATA
;
566 memset(&dfl
, 0, sizeof(dfl
));
568 if (argc
> 1 && strncmp(argv
[1], "imm", 3) == 0) {
570 * Signal target for an immediate return from Format.
572 * We'll poll for completion status.
574 dfl
.header
.flags
= DLH_IMMED
;
580 scsi_command(fd
, &cmd
, sizeof(cmd
), &dfl
, sizeof(dfl
),
581 8 * 60 * 60 * 1000, 0);
584 * Poll device for completion of Format
588 printf("formatting.");
592 struct scsi_test_unit_ready tcmd
;
594 memset(&tcmd
, 0, sizeof(cmd
));
595 tcmd
.opcode
= SCSI_TEST_UNIT_READY
;
597 memset(&req
, 0, sizeof(req
));
598 memcpy(req
.cmd
, &tcmd
, 6);
601 req
.senselen
= SENSEBUFLEN
;
603 if (ioctl(fd
, SCIOCCOMMAND
, &req
) == -1) {
604 err(1, "SCIOCCOMMAND");
607 if (req
.retsts
== SCCMD_OK
) {
609 } else if (req
.retsts
== SCCMD_TIMEOUT
) {
610 fprintf(stderr
, "%s: SCSI command timed out",
613 } else if (req
.retsts
== SCCMD_BUSY
) {
614 fprintf(stderr
, "%s: device is busy",
617 } else if (req
.retsts
!= SCCMD_SENSE
) {
619 "%s: device had unknown status %x", dvname
,
623 memcpy(&sense
, req
.sense
, sizeof(sense
));
624 if (sense
.sks
.sks_bytes
[0] & SSD_SKSV
) {
625 j
= (sense
.sks
.sks_bytes
[1] << 8) |
626 (sense
.sks
.sks_bytes
[2]);
627 if (j
>= complete
[i
]) {
628 printf(".%d0%%.", ++i
);
633 } while (SSD_SENSE_KEY(sense
.flags
) == SKEY_NOT_READY
);
634 printf(".100%%..done.\n");
642 * Display the identity of the device, including it's SCSI bus,
643 * target, lun, and it's vendor/product/revision information.
646 device_identify(int argc
, char *argv
[])
648 struct scsipi_inquiry_data inqbuf
;
649 struct scsipi_inquiry cmd
;
651 /* x4 in case every character is escaped, +1 for NUL. */
652 char vendor
[(sizeof(inqbuf
.vendor
) * 4) + 1],
653 product
[(sizeof(inqbuf
.product
) * 4) + 1],
654 revision
[(sizeof(inqbuf
.revision
) * 4) + 1];
660 memset(&cmd
, 0, sizeof(cmd
));
661 memset(&inqbuf
, 0, sizeof(inqbuf
));
663 cmd
.opcode
= INQUIRY
;
664 cmd
.length
= sizeof(inqbuf
);
666 scsi_command(fd
, &cmd
, sizeof(cmd
), &inqbuf
, sizeof(inqbuf
),
669 scsi_strvis(vendor
, sizeof(vendor
), inqbuf
.vendor
,
670 sizeof(inqbuf
.vendor
));
671 scsi_strvis(product
, sizeof(product
), inqbuf
.product
,
672 sizeof(inqbuf
.product
));
673 scsi_strvis(revision
, sizeof(revision
), inqbuf
.revision
,
674 sizeof(inqbuf
.revision
));
676 printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n",
677 dvname
, dvaddr
.addr
.scsi
.scbus
, dvaddr
.addr
.scsi
.target
,
678 dvaddr
.addr
.scsi
.lun
, vendor
, product
, revision
);
686 * Reassign bad blocks on a direct access device.
689 device_reassign(int argc
, char *argv
[])
691 struct scsi_reassign_blocks cmd
;
692 struct scsi_reassign_blocks_data
*data
;
698 /* We get a list of block numbers. */
703 * Allocate the reassign blocks descriptor. The 4 comes from the
704 * size of the block address in the defect descriptor.
706 dlen
= sizeof(struct scsi_reassign_blocks_data
) + ((argc
- 1) * 4);
709 errx(1, "unable to allocate defect descriptor");
710 memset(data
, 0, dlen
);
712 cmd
.opcode
= SCSI_REASSIGN_BLOCKS
;
719 /* Defect descriptor length. */
720 _lto2b(argc
* 4, data
->length
);
722 /* Build the defect descriptor list. */
723 for (i
= 0; i
< argc
; i
++) {
724 blkno
= strtoul(argv
[i
], &cp
, 10);
726 errx(1, "invalid block number: %s", argv
[i
]);
727 _lto4b(blkno
, data
->defect_descriptor
[i
].dlbaddr
);
730 scsi_command(fd
, &cmd
, sizeof(cmd
), data
, dlen
, 30000, SCCMD_WRITE
);
739 * Issue a RELEASE command to a SCSI device.
742 #define SCSI_RELEASE 0x17
745 device_release(int argc
, char *argv
[])
747 struct scsi_test_unit_ready cmd
; /* close enough */
753 memset(&cmd
, 0, sizeof(cmd
));
755 cmd
.opcode
= SCSI_RELEASE
;
757 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
767 * Issue a RESERVE command to a SCSI device.
770 #define SCSI_RESERVE 0x16
773 device_reserve(int argc
, char *argv
[])
775 struct scsi_test_unit_ready cmd
; /* close enough */
781 memset(&cmd
, 0, sizeof(cmd
));
783 cmd
.opcode
= SCSI_RESERVE
;
785 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
793 * Issue a reset to a SCSI device.
796 device_reset(int argc
, char *argv
[])
803 if (ioctl(fd
, SCIOCRESET
, NULL
) != 0)
804 err(1, "SCIOCRESET");
812 * Set debug level to a SCSI device.
813 * scsipi will print anything iff SCSIPI_DEBUG set in config.
816 device_debug(int argc
, char *argv
[])
825 if (ioctl(fd
, SCIOCDEBUG
, &lvl
) != 0)
826 err(1, "SCIOCDEBUG");
834 * Get the caching parameters for a SCSI disk.
837 device_getcache(int argc
, char *argv
[])
840 struct scsi_mode_parameter_header_6 header
;
841 struct scsi_general_block_descriptor blk_desc
;
842 struct page_caching caching_params
;
849 scsi_mode_sense(fd
, 0x08, 0x00, &data
, sizeof(data
));
851 if ((data
.caching_params
.flags
& (CACHING_RCD
|CACHING_WCE
)) ==
853 printf("%s: no caches enabled\n", dvname
);
855 printf("%s: read cache %senabled\n", dvname
,
856 (data
.caching_params
.flags
& CACHING_RCD
) ? "not " : "");
857 printf("%s: write-back cache %senabled\n", dvname
,
858 (data
.caching_params
.flags
& CACHING_WCE
) ? "" : "not ");
860 printf("%s: caching parameters are %ssavable\n", dvname
,
861 (data
.caching_params
.pg_code
& PGCODE_PS
) ? "" : "not ");
867 * Set cache enables for a SCSI disk.
870 device_setcache(int argc
, char *argv
[])
873 struct scsi_mode_parameter_header_6 header
;
874 struct scsi_general_block_descriptor blk_desc
;
875 struct page_caching caching_params
;
878 u_int8_t flags
, byte2
;
880 if (argc
> 2 || argc
== 0)
885 if (strcmp(argv
[0], "none") == 0)
887 else if (strcmp(argv
[0], "r") == 0)
889 else if (strcmp(argv
[0], "w") == 0)
890 flags
= CACHING_RCD
|CACHING_WCE
;
891 else if (strcmp(argv
[0], "rw") == 0)
897 if (strcmp(argv
[1], "save") == 0)
903 scsi_mode_sense(fd
, 0x08, 0x00, &data
, sizeof(data
));
905 data
.caching_params
.pg_code
&= PGCODE_MASK
;
906 data
.caching_params
.flags
=
907 (data
.caching_params
.flags
& ~(CACHING_RCD
|CACHING_WCE
)) | flags
;
909 data
.caching_params
.cache_segment_size
[0] = 0;
910 data
.caching_params
.cache_segment_size
[1] = 0;
912 data
.header
.data_length
= 0;
914 dlen
= sizeof(data
.header
) + sizeof(data
.blk_desc
) + 2 +
915 data
.caching_params
.pg_length
;
917 scsi_mode_select(fd
, byte2
, &data
, dlen
);
923 * Issue a FLUSH CACHE command to a SCSI device.
925 #ifndef SCSI_FLUSHCACHE
926 #define SCSI_FLUSHCACHE 0x35
929 device_flushcache(int argc
, char *argv
[])
931 struct scsi_test_unit_ready cmd
; /* close enough */
937 memset(&cmd
, 0, sizeof(cmd
));
939 cmd
.opcode
= SCSI_FLUSHCACHE
;
941 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
949 * Set rotation speed to a CD/DVD drive.
952 device_setspeed(int argc
, char *argv
[])
961 speed
= atoi(argv
[0]) * 177;
963 memset(&pd
, 0, sizeof(pd
));
965 pd
[0] = 4; /* restore drive defaults */
970 pd
[12] = pd
[20] = (speed
>> 24) & 0xff;
971 pd
[13] = pd
[21] = (speed
>> 16) & 0xff;
972 pd
[14] = pd
[22] = (speed
>> 8) & 0xff;
973 pd
[15] = pd
[23] = speed
& 0xff;
974 pd
[18] = pd
[26] = 1000 >> 8;
975 pd
[19] = pd
[27] = 1000 & 0xff;
977 memset(&cmd
, 0, sizeof(cmd
));
979 cmd
[10] = sizeof(pd
);
981 scsi_command(fd
, &cmd
, sizeof(cmd
), pd
, sizeof(pd
), 10000, SCCMD_WRITE
);
989 * Issue a prevent to a SCSI device.
992 device_prevent(int argc
, char *argv
[])
994 struct scsi_prevent_allow_medium_removal cmd
;
1000 memset(&cmd
, 0, sizeof(cmd
));
1002 cmd
.opcode
= SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL
;
1003 cmd
.how
= SPAMR_PREVENT_DT
; /* XXX SMAMR_PREVENT_ALL? */
1005 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
1013 * Issue a stop to a SCSI device.
1016 device_allow(int argc
, char *argv
[])
1018 struct scsi_prevent_allow_medium_removal cmd
;
1024 memset(&cmd
, 0, sizeof(cmd
));
1026 cmd
.opcode
= SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL
;
1027 cmd
.how
= SPAMR_ALLOW
;
1029 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
1037 * Issue a start to a SCSI device.
1040 device_start(int argc
, char *argv
[])
1042 struct scsipi_start_stop cmd
;
1048 memset(&cmd
, 0, sizeof(cmd
));
1050 cmd
.opcode
= START_STOP
;
1051 cmd
.how
= SSS_START
;
1053 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 30000, 0);
1061 * Issue a stop to a SCSI device.
1064 device_stop(int argc
, char *argv
[])
1066 struct scsipi_start_stop cmd
;
1072 memset(&cmd
, 0, sizeof(cmd
));
1074 cmd
.opcode
= START_STOP
;
1077 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 30000, 0);
1085 * Issue a TEST UNIT READY to a SCSI device.
1088 device_tur(int argc
, char *argv
[])
1090 struct scsi_test_unit_ready cmd
;
1096 memset(&cmd
, 0, sizeof(cmd
));
1098 cmd
.opcode
= SCSI_TEST_UNIT_READY
;
1100 scsi_command(fd
, &cmd
, sizeof(cmd
), NULL
, 0, 10000, 0);
1112 * Issue a reset to a SCSI bus.
1115 bus_reset(int argc
, char *argv
[])
1122 if (ioctl(fd
, SCBUSIORESET
, NULL
) != 0)
1123 err(1, "SCBUSIORESET");
1131 * Rescan a SCSI bus for new devices.
1134 bus_scan(int argc
, char *argv
[])
1136 struct scbusioscan_args args
;
1139 /* Must have two args: target lun */
1143 if (strcmp(argv
[0], "any") == 0 || strcmp(argv
[0], "all") == 0)
1144 args
.sa_target
= -1;
1146 args
.sa_target
= strtol(argv
[0], &cp
, 10);
1147 if (*cp
!= '\0' || args
.sa_target
< 0)
1148 errx(1, "invalid target: %s", argv
[0]);
1151 if (strcmp(argv
[1], "any") == 0 || strcmp(argv
[1], "all") == 0)
1154 args
.sa_lun
= strtol(argv
[1], &cp
, 10);
1155 if (*cp
!= '\0' || args
.sa_lun
< 0)
1156 errx(1, "invalid lun: %s", argv
[1]);
1159 if (ioctl(fd
, SCBUSIOSCAN
, &args
) != 0)
1160 err(1, "SCBUSIOSCAN");
1168 * detach SCSI devices from a bus.
1171 bus_detach(int argc
, char *argv
[])
1173 struct scbusiodetach_args args
;
1176 /* Must have two args: target lun */
1180 if (strcmp(argv
[0], "any") == 0 || strcmp(argv
[0], "all") == 0)
1181 args
.sa_target
= -1;
1183 args
.sa_target
= strtol(argv
[0], &cp
, 10);
1184 if (*cp
!= '\0' || args
.sa_target
< 0)
1185 errx(1, "invalid target: %s", argv
[0]);
1188 if (strcmp(argv
[1], "any") == 0 || strcmp(argv
[1], "all") == 0)
1191 args
.sa_lun
= strtol(argv
[1], &cp
, 10);
1192 if (*cp
!= '\0' || args
.sa_lun
< 0)
1193 errx(1, "invalid lun: %s", argv
[1]);
1196 if (ioctl(fd
, SCBUSIODETACH
, &args
) != 0)
1197 err(1, "SCBUSIODETACH");