No empty .Rs/.Re
[netbsd-mini2440.git] / sbin / scsictl / scsictl.c
blob9b611b8448cc2da8fbe92799c2166db330f866cb
1 /* $NetBSD: scsictl.c,v 1.30 2008/02/02 17:07:04 christos Exp $ */
3 /*-
4 * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
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
13 * are met:
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>
38 #ifndef lint
39 __RCSID("$NetBSD: scsictl.c,v 1.30 2008/02/02 17:07:04 christos Exp $");
40 #endif
43 #include <sys/param.h>
44 #include <sys/ioctl.h>
45 #include <sys/scsiio.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <limits.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <util.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>
61 #include "extern.h"
63 struct command {
64 const char *cmd_name;
65 const char *arg_names;
66 void (*cmd_func)(int, char *[]);
69 void usage(void);
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]",
98 device_defects },
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;
133 int i;
135 /* Must have at least: device command */
136 if (argc < 3)
137 usage();
139 /* Skip program name, get and skip device name and command. */
140 dvname = argv[1];
141 cmdname = argv[2];
142 argv += 3;
143 argc -= 3;
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);
150 if (fd == -1) {
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
157 * name.
159 fd = opendisk(dvname, O_RDWR, dvname_store,
160 sizeof(dvname_store), 1);
161 if (fd == -1)
162 err(1, "%s", dvname);
163 } else
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;
174 else
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)
180 break;
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);
188 exit(0);
191 void
192 usage(void)
194 int i;
196 fprintf(stderr, "usage: %s device command [arg [...]]\n",
197 getprogname());
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");
209 exit(1);
213 * DEVICE COMMANDS
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 *);
230 void
231 device_defects(int argc, char *argv[])
233 struct scsi_read_defect_data cmd;
234 struct scsi_read_defect_data_data *data;
235 size_t dlen;
236 int i, dlfmt = -1;
237 int defects;
238 char msg[256];
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.
246 data = malloc(dlen);
247 if (data == NULL)
248 errx(1, "unable to allocate defect list");
249 memset(data, 0, dlen);
250 memset(&cmd, 0, sizeof(cmd));
251 defects = 0;
252 pfunc = NULL;
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;
258 continue;
260 if (strncmp("grown", argv[i], 5) == 0) {
261 cmd.flags |= RDD_GROWN;
262 continue;
264 break;
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. */
272 if (i < argc) {
273 if (strncmp("block", argv[i], 5) == 0) {
274 cmd.flags |= RDD_BF;
275 dlfmt = RDD_BF;
277 else if (strncmp("byte", argv[i], 4) == 0) {
278 cmd.flags |= RDD_BFIF;
279 dlfmt = RDD_BFIF;
281 else if (strncmp("physical", argv[i], 4) == 0) {
282 cmd.flags |= RDD_PSF;
283 dlfmt = RDD_PSF;
285 else {
286 usage();
291 * no list format specified; since block format not
292 * recommended use physical sector format as default.
294 if (dlfmt < 0) {
295 cmd.flags |= RDD_PSF;
296 dlfmt = 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);
304 msg[0] = '\0';
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)
334 return;
336 switch (dlfmt) {
337 case RDD_BF:
338 defects = _2btol(data->length) /
339 sizeof(struct scsi_defect_descriptor_bf);
340 pfunc = print_bf_dd;
341 strcpy(msg, "block address\n"
342 "-------------\n");
343 break;
344 case RDD_BFIF:
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");
351 break;
352 case RDD_PSF:
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");
358 break;
361 /* device did not return any defects. */
362 if (defects == 0) {
363 printf(": none\n");
364 return;
367 printf(": %d\n", defects);
369 /* print heading. */
370 printf("%s", msg);
372 /* print defect list. */
373 for (i = 0 ; i < defects; i++) {
374 pfunc(&data->defect_descriptor[i]);
377 free(data);
378 return;
382 * print_bf_dd:
384 * Print a block format defect descriptor.
386 void
387 print_bf_dd(union scsi_defect_descriptor *dd)
389 u_int32_t block;
391 block = _4btol(dd->bf.block_address);
393 printf("%13u\n", block);
396 #define DEFECTIVE_TRACK 0xffffffff
399 * print_bfif_dd:
401 * Print a bytes from index format defect descriptor.
403 void
404 print_bfif_dd(union scsi_defect_descriptor *dd)
406 u_int32_t cylinder;
407 u_int32_t head;
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");
418 else
419 printf("%10u\n", bytes_from_index);
423 * print_psf_dd:
425 * Print a physical sector format defect descriptor.
427 void
428 print_psf_dd(union scsi_defect_descriptor *dd)
430 u_int32_t cylinder;
431 u_int32_t head;
432 u_int32_t sector;
434 cylinder = _3btol(dd->psf.cylinder);
435 head = dd->psf.head;
436 sector = _4btol(dd->psf.sector);
438 printf("%8u %4u ", cylinder, head);
440 if (sector == DEFECTIVE_TRACK)
441 printf("entire track defective\n");
442 else
443 printf("%10u\n", sector);
447 * device_format:
449 * Format a direct access device.
451 void
452 device_format(int argc, char *argv[])
454 u_int32_t blksize;
455 int i, j, immediate;
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;
463 struct {
464 struct scsi_format_unit_defect_list_header header;
465 /* optional initialization pattern */
466 /* optional defect list */
467 } dfl;
468 struct {
469 struct scsi_mode_parameter_header_6 header;
470 struct scsi_general_block_descriptor blk_desc;
471 struct page_disk_format format_page;
472 } mode_page;
473 struct {
474 struct scsi_mode_parameter_header_6 header;
475 struct scsi_general_block_descriptor blk_desc;
476 } data_select;
479 /* Blocksize is an optional argument. */
480 if (argc > 2)
481 usage();
484 * Loop doing Request Sense to clear any pending Unit Attention.
486 * Multiple conditions may exist on the drive which are returned
487 * in priority order.
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)
492 break;
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]);
512 if (j != DEV_BSIZE)
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.
534 if (argc > 0) {
535 blksize = strtoul(argv[0], &cp, 10);
536 if (*cp != '\0')
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
561 * original.
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;
575 immediate = 1;
576 } else {
577 immediate = 0;
580 scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl),
581 8 * 60 * 60 * 1000, 0);
584 * Poll device for completion of Format
586 if (immediate) {
587 i = 0;
588 printf("formatting.");
589 fflush(stdout);
590 do {
591 scsireq_t req;
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);
599 req.cmdlen = 6;
600 req.timeout = 10000;
601 req.senselen = SENSEBUFLEN;
603 if (ioctl(fd, SCIOCCOMMAND, &req) == -1) {
604 err(1, "SCIOCCOMMAND");
607 if (req.retsts == SCCMD_OK) {
608 break;
609 } else if (req.retsts == SCCMD_TIMEOUT) {
610 fprintf(stderr, "%s: SCSI command timed out",
611 dvname);
612 break;
613 } else if (req.retsts == SCCMD_BUSY) {
614 fprintf(stderr, "%s: device is busy",
615 dvname);
616 break;
617 } else if (req.retsts != SCCMD_SENSE) {
618 fprintf(stderr,
619 "%s: device had unknown status %x", dvname,
620 req.retsts);
621 break;
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);
629 fflush(stdout);
632 sleep(10);
633 } while (SSD_SENSE_KEY(sense.flags) == SKEY_NOT_READY);
634 printf(".100%%..done.\n");
636 return;
640 * device_identify:
642 * Display the identity of the device, including it's SCSI bus,
643 * target, lun, and it's vendor/product/revision information.
645 void
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];
656 /* No arguments. */
657 if (argc != 0)
658 usage();
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),
667 10000, SCCMD_READ);
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);
680 return;
684 * device_reassign:
686 * Reassign bad blocks on a direct access device.
688 void
689 device_reassign(int argc, char *argv[])
691 struct scsi_reassign_blocks cmd;
692 struct scsi_reassign_blocks_data *data;
693 size_t dlen;
694 u_int32_t blkno;
695 int i;
696 char *cp;
698 /* We get a list of block numbers. */
699 if (argc < 1)
700 usage();
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);
707 data = malloc(dlen);
708 if (data == NULL)
709 errx(1, "unable to allocate defect descriptor");
710 memset(data, 0, dlen);
712 cmd.opcode = SCSI_REASSIGN_BLOCKS;
713 cmd.byte2 = 0;
714 cmd.unused[0] = 0;
715 cmd.unused[1] = 0;
716 cmd.unused[2] = 0;
717 cmd.control = 0;
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);
725 if (*cp != '\0')
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);
732 free(data);
733 return;
737 * device_release:
739 * Issue a RELEASE command to a SCSI device.
741 #ifndef SCSI_RELEASE
742 #define SCSI_RELEASE 0x17
743 #endif
744 void
745 device_release(int argc, char *argv[])
747 struct scsi_test_unit_ready cmd; /* close enough */
749 /* No arguments. */
750 if (argc != 0)
751 usage();
753 memset(&cmd, 0, sizeof(cmd));
755 cmd.opcode = SCSI_RELEASE;
757 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
759 return;
765 * device_reserve:
767 * Issue a RESERVE command to a SCSI device.
769 #ifndef SCSI_RESERVE
770 #define SCSI_RESERVE 0x16
771 #endif
772 void
773 device_reserve(int argc, char *argv[])
775 struct scsi_test_unit_ready cmd; /* close enough */
777 /* No arguments. */
778 if (argc != 0)
779 usage();
781 memset(&cmd, 0, sizeof(cmd));
783 cmd.opcode = SCSI_RESERVE;
785 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
787 return;
791 * device_reset:
793 * Issue a reset to a SCSI device.
795 void
796 device_reset(int argc, char *argv[])
799 /* No arguments. */
800 if (argc != 0)
801 usage();
803 if (ioctl(fd, SCIOCRESET, NULL) != 0)
804 err(1, "SCIOCRESET");
806 return;
810 * device_debug:
812 * Set debug level to a SCSI device.
813 * scsipi will print anything iff SCSIPI_DEBUG set in config.
815 void
816 device_debug(int argc, char *argv[])
818 int lvl;
820 if (argc < 1)
821 usage();
823 lvl = atoi(argv[0]);
825 if (ioctl(fd, SCIOCDEBUG, &lvl) != 0)
826 err(1, "SCIOCDEBUG");
828 return;
832 * device_getcache:
834 * Get the caching parameters for a SCSI disk.
836 void
837 device_getcache(int argc, char *argv[])
839 struct {
840 struct scsi_mode_parameter_header_6 header;
841 struct scsi_general_block_descriptor blk_desc;
842 struct page_caching caching_params;
843 } data;
845 /* No arguments. */
846 if (argc != 0)
847 usage();
849 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
851 if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) ==
852 CACHING_RCD)
853 printf("%s: no caches enabled\n", dvname);
854 else {
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 ");
865 * device_setcache:
867 * Set cache enables for a SCSI disk.
869 void
870 device_setcache(int argc, char *argv[])
872 struct {
873 struct scsi_mode_parameter_header_6 header;
874 struct scsi_general_block_descriptor blk_desc;
875 struct page_caching caching_params;
876 } data;
877 int dlen;
878 u_int8_t flags, byte2;
880 if (argc > 2 || argc == 0)
881 usage();
883 flags = 0;
884 byte2 = 0;
885 if (strcmp(argv[0], "none") == 0)
886 flags = CACHING_RCD;
887 else if (strcmp(argv[0], "r") == 0)
888 flags = 0;
889 else if (strcmp(argv[0], "w") == 0)
890 flags = CACHING_RCD|CACHING_WCE;
891 else if (strcmp(argv[0], "rw") == 0)
892 flags = CACHING_WCE;
893 else
894 usage();
896 if (argc == 2) {
897 if (strcmp(argv[1], "save") == 0)
898 byte2 = SMS_SP;
899 else
900 usage();
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);
921 * device_flushcache:
923 * Issue a FLUSH CACHE command to a SCSI device.
925 #ifndef SCSI_FLUSHCACHE
926 #define SCSI_FLUSHCACHE 0x35
927 #endif
928 void
929 device_flushcache(int argc, char *argv[])
931 struct scsi_test_unit_ready cmd; /* close enough */
933 /* No arguments. */
934 if (argc != 0)
935 usage();
937 memset(&cmd, 0, sizeof(cmd));
939 cmd.opcode = SCSI_FLUSHCACHE;
941 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
943 return;
947 * device_setspeed:
949 * Set rotation speed to a CD/DVD drive.
951 void
952 device_setspeed(int argc, char *argv[])
954 u_char cmd[11];
955 u_char pd[28];
956 u_int32_t speed;
958 if (argc != 1)
959 usage();
961 speed = atoi(argv[0]) * 177;
963 memset(&pd, 0, sizeof(pd));
964 if (speed == 0)
965 pd[0] = 4; /* restore drive defaults */
966 pd[8] = 0xff;
967 pd[9] = 0xff;
968 pd[10] = 0xff;
969 pd[11] = 0xff;
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));
978 cmd[0] = 0xb6;
979 cmd[10] = sizeof(pd);
981 scsi_command(fd, &cmd, sizeof(cmd), pd, sizeof(pd), 10000, SCCMD_WRITE);
983 return;
987 * device_prevent:
989 * Issue a prevent to a SCSI device.
991 void
992 device_prevent(int argc, char *argv[])
994 struct scsi_prevent_allow_medium_removal cmd;
996 /* No arguments. */
997 if (argc != 0)
998 usage();
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);
1007 return;
1011 * device_allow:
1013 * Issue a stop to a SCSI device.
1015 void
1016 device_allow(int argc, char *argv[])
1018 struct scsi_prevent_allow_medium_removal cmd;
1020 /* No arguments. */
1021 if (argc != 0)
1022 usage();
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);
1031 return;
1035 * device_start:
1037 * Issue a start to a SCSI device.
1039 void
1040 device_start(int argc, char *argv[])
1042 struct scsipi_start_stop cmd;
1044 /* No arguments. */
1045 if (argc != 0)
1046 usage();
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);
1055 return;
1059 * device_stop:
1061 * Issue a stop to a SCSI device.
1063 void
1064 device_stop(int argc, char *argv[])
1066 struct scsipi_start_stop cmd;
1068 /* No arguments. */
1069 if (argc != 0)
1070 usage();
1072 memset(&cmd, 0, sizeof(cmd));
1074 cmd.opcode = START_STOP;
1075 cmd.how = SSS_STOP;
1077 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0);
1079 return;
1083 * device_tur:
1085 * Issue a TEST UNIT READY to a SCSI device.
1087 void
1088 device_tur(int argc, char *argv[])
1090 struct scsi_test_unit_ready cmd;
1092 /* No arguments. */
1093 if (argc != 0)
1094 usage();
1096 memset(&cmd, 0, sizeof(cmd));
1098 cmd.opcode = SCSI_TEST_UNIT_READY;
1100 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1102 return;
1106 * BUS COMMANDS
1110 * bus_reset:
1112 * Issue a reset to a SCSI bus.
1114 void
1115 bus_reset(int argc, char *argv[])
1118 /* No arguments. */
1119 if (argc != 0)
1120 usage();
1122 if (ioctl(fd, SCBUSIORESET, NULL) != 0)
1123 err(1, "SCBUSIORESET");
1125 return;
1129 * bus_scan:
1131 * Rescan a SCSI bus for new devices.
1133 void
1134 bus_scan(int argc, char *argv[])
1136 struct scbusioscan_args args;
1137 char *cp;
1139 /* Must have two args: target lun */
1140 if (argc != 2)
1141 usage();
1143 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1144 args.sa_target = -1;
1145 else {
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)
1152 args.sa_lun = -1;
1153 else {
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");
1162 return;
1166 * bus_detach:
1168 * detach SCSI devices from a bus.
1170 void
1171 bus_detach(int argc, char *argv[])
1173 struct scbusiodetach_args args;
1174 char *cp;
1176 /* Must have two args: target lun */
1177 if (argc != 2)
1178 usage();
1180 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1181 args.sa_target = -1;
1182 else {
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)
1189 args.sa_lun = -1;
1190 else {
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");
1199 return;