scsictl.c revision 1.37 1 /* $NetBSD: scsictl.c,v 1.37 2013/01/12 02:52:59 jakllsch Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
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.
10 *
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.
19 *
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.
31 */
32
33 /*
34 * scsictl(8) - a program to manipulate SCSI devices and busses.
35 */
36 #include <sys/cdefs.h>
37
38 #ifndef lint
39 __RCSID("$NetBSD: scsictl.c,v 1.37 2013/01/12 02:52:59 jakllsch Exp $");
40 #endif
41
42
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>
55
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>
60
61 #include "extern.h"
62
63 struct command {
64 const char *cmd_name;
65 const char *arg_names;
66 void (*cmd_func)(int, char *[]);
67 };
68
69 __dead static void usage(void);
70
71 static int fd; /* file descriptor for device */
72 const char *dvname; /* device name */
73 static char dvname_store[MAXPATHLEN]; /* for opendisk(3) */
74 static const char *cmdname; /* command user issued */
75 static struct scsi_addr dvaddr; /* SCSI device's address */
76
77 static void device_defects(int, char *[]);
78 static void device_format(int, char *[]);
79 static void device_identify(int, char *[]);
80 static void device_reassign(int, char *[]);
81 static void device_release(int, char *[]);
82 static void device_reserve(int, char *[]);
83 static void device_reset(int, char *[]);
84 static void device_debug(int, char *[]);
85 static void device_prevent(int, char *[]);
86 static void device_allow(int, char *[]);
87 static void device_start(int, char *[]);
88 static void device_stop(int, char *[]);
89 static void device_tur(int, char *[]);
90 static void device_getcache(int, char *[]);
91 static void device_setcache(int, char *[]);
92 static void device_flushcache(int, char *[]);
93 static void device_setspeed(int, char *[]);
94
95 static struct command device_commands[] = {
96 { "defects", "[primary] [grown] [block|byte|physical]",
97 device_defects },
98 { "format", "[blocksize [immediate]]", device_format },
99 { "identify", "", device_identify },
100 { "reassign", "blkno [blkno [...]]", device_reassign },
101 { "release", "", device_release },
102 { "reserve", "", device_reserve },
103 { "reset", "", device_reset },
104 { "debug", "level", device_debug },
105 { "prevent", "", device_prevent },
106 { "allow", "", device_allow },
107 { "start", "", device_start },
108 { "stop", "", device_stop },
109 { "tur", "", device_tur },
110 { "getcache", "", device_getcache },
111 { "setcache", "none|r|w|rw [save]", device_setcache },
112 { "flushcache", "", device_flushcache },
113 { "setspeed", "[speed]", device_setspeed },
114 { NULL, NULL, NULL },
115 };
116
117 static void bus_reset(int, char *[]);
118 static void bus_scan(int, char *[]);
119 static void bus_detach(int, char *[]);
120
121 static struct command bus_commands[] = {
122 { "reset", "", bus_reset },
123 { "scan", "target lun", bus_scan },
124 { "detach", "target lun", bus_detach },
125 { NULL, NULL, NULL },
126 };
127
128 int
129 main(int argc, char *argv[])
130 {
131 struct command *commands;
132 int i;
133
134 /* Must have at least: device command */
135 if (argc < 3)
136 usage();
137
138 /* Skip program name, get and skip device name and command. */
139 dvname = argv[1];
140 cmdname = argv[2];
141 argv += 3;
142 argc -= 3;
143
144 /*
145 * Open the device and determine if it's a scsibus or an actual
146 * device. Devices respond to the SCIOCIDENTIFY ioctl.
147 */
148 fd = opendisk(dvname, O_RDWR, dvname_store, sizeof(dvname_store), 0);
149 if (fd == -1) {
150 if (errno == ENOENT) {
151 /*
152 * Device doesn't exist. Probably trying to open
153 * a device which doesn't use disk semantics for
154 * device name. Try again, specifying "cooked",
155 * which leaves off the "r" in front of the device's
156 * name.
157 */
158 fd = opendisk(dvname, O_RDWR, dvname_store,
159 sizeof(dvname_store), 1);
160 if (fd == -1)
161 err(1, "%s", dvname);
162 } else
163 err(1, "%s", dvname);
164 }
165
166 /*
167 * Point the dvname at the actual device name that opendisk() opened.
168 */
169 dvname = dvname_store;
170
171 if (ioctl(fd, SCIOCIDENTIFY, &dvaddr) < 0)
172 commands = bus_commands;
173 else
174 commands = device_commands;
175
176 /* Look up and call the command. */
177 for (i = 0; commands[i].cmd_name != NULL; i++)
178 if (strcmp(cmdname, commands[i].cmd_name) == 0)
179 break;
180 if (commands[i].cmd_name == NULL)
181 errx(1, "unknown %s command: %s",
182 commands == bus_commands ? "bus" : "device", cmdname);
183
184 (*commands[i].cmd_func)(argc, argv);
185 exit(0);
186 }
187
188 static void
189 usage(void)
190 {
191 int i;
192
193 fprintf(stderr, "usage: %s device command [arg [...]]\n",
194 getprogname());
195
196 fprintf(stderr, " Commands pertaining to scsi devices:\n");
197 for (i=0; device_commands[i].cmd_name != NULL; i++)
198 fprintf(stderr, "\t%s %s\n", device_commands[i].cmd_name,
199 device_commands[i].arg_names);
200 fprintf(stderr, " Commands pertaining to scsi busses:\n");
201 for (i=0; bus_commands[i].cmd_name != NULL; i++)
202 fprintf(stderr, "\t%s %s\n", bus_commands[i].cmd_name,
203 bus_commands[i].arg_names);
204 fprintf(stderr, " Use `any' or `all' to wildcard target or lun\n");
205
206 exit(1);
207 }
208
209 /*
210 * DEVICE COMMANDS
211 */
212
213 /*
214 * device_read_defect:
215 *
216 * Read primary and/or growth defect list in physical or block
217 * format from a direct access device.
218 *
219 * XXX Does not handle very large defect lists. Needs SCSI3 12
220 * byte READ DEFECT DATA command.
221 */
222
223 static void print_bf_dd(union scsi_defect_descriptor *);
224 static void print_bfif_dd(union scsi_defect_descriptor *);
225 static void print_psf_dd(union scsi_defect_descriptor *);
226
227 static void
228 device_defects(int argc, char *argv[])
229 {
230 struct scsi_read_defect_data cmd;
231 struct scsi_read_defect_data_data *data;
232 size_t dlen;
233 int i, dlfmt = -1;
234 int defects;
235 char msg[256];
236 void (*pfunc)(union scsi_defect_descriptor *);
237 #define RDD_P_G_MASK 0x18
238 #define RDD_DLF_MASK 0x7
239
240 dlen = USHRT_MAX; /* XXX - this may not be enough room
241 * for all of the defects.
242 */
243 data = malloc(dlen);
244 if (data == NULL)
245 errx(1, "unable to allocate defect list");
246 memset(data, 0, dlen);
247 memset(&cmd, 0, sizeof(cmd));
248 defects = 0;
249 pfunc = NULL;
250
251 /* determine which defect list(s) to read. */
252 for (i = 0; i < argc; i++) {
253 if (strncmp("primary", argv[i], 7) == 0) {
254 cmd.flags |= RDD_PRIMARY;
255 continue;
256 }
257 if (strncmp("grown", argv[i], 5) == 0) {
258 cmd.flags |= RDD_GROWN;
259 continue;
260 }
261 break;
262 }
263
264 /* no defect list sepecified, assume both. */
265 if ((cmd.flags & (RDD_PRIMARY|RDD_GROWN)) == 0)
266 cmd.flags |= (RDD_PRIMARY|RDD_GROWN);
267
268 /* list format option. */
269 if (i < argc) {
270 if (strncmp("block", argv[i], 5) == 0) {
271 cmd.flags |= RDD_BF;
272 dlfmt = RDD_BF;
273 }
274 else if (strncmp("byte", argv[i], 4) == 0) {
275 cmd.flags |= RDD_BFIF;
276 dlfmt = RDD_BFIF;
277 }
278 else if (strncmp("physical", argv[i], 4) == 0) {
279 cmd.flags |= RDD_PSF;
280 dlfmt = RDD_PSF;
281 }
282 else {
283 usage();
284 }
285 }
286
287 /*
288 * no list format specified; since block format not
289 * recommended use physical sector format as default.
290 */
291 if (dlfmt < 0) {
292 cmd.flags |= RDD_PSF;
293 dlfmt = RDD_PSF;
294 }
295
296 cmd.opcode = SCSI_READ_DEFECT_DATA;
297 _lto2b(dlen, &cmd.length[0]);
298
299 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_READ);
300
301 msg[0] = '\0';
302
303 /* is the defect list in the format asked for? */
304 if ((data->flags & RDD_DLF_MASK) != dlfmt) {
305 strcpy(msg, "\n\tnotice:"
306 "requested defect list format not supported by device\n\n");
307 dlfmt = (data->flags & RDD_DLF_MASK);
308 }
309
310 if (data->flags & RDD_PRIMARY)
311 strcat(msg, "primary");
312
313 if (data->flags & RDD_GROWN) {
314 if (data->flags & RDD_PRIMARY)
315 strcat(msg, " and ");
316 strcat(msg, "grown");
317 }
318
319 strcat(msg, " defects");
320
321 if ((data->flags & RDD_P_G_MASK) == 0)
322 strcat(msg, ": none reported\n");
323
324
325 printf("%s: scsibus%d target %d lun %d %s",
326 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target,
327 dvaddr.addr.scsi.lun, msg);
328
329 /* device did not return either defect list. */
330 if ((data->flags & RDD_P_G_MASK) == 0)
331 return;
332
333 switch (dlfmt) {
334 case RDD_BF:
335 defects = _2btol(data->length) /
336 sizeof(struct scsi_defect_descriptor_bf);
337 pfunc = print_bf_dd;
338 strcpy(msg, "block address\n"
339 "-------------\n");
340 break;
341 case RDD_BFIF:
342 defects = _2btol(data->length) /
343 sizeof(struct scsi_defect_descriptor_bfif);
344 pfunc = print_bfif_dd;
345 strcpy(msg, " bytes from\n"
346 "cylinder head index\n"
347 "-------- ---- ----------\n");
348 break;
349 case RDD_PSF:
350 defects = _2btol(data->length) /
351 sizeof(struct scsi_defect_descriptor_psf);
352 pfunc = print_psf_dd;
353 strcpy(msg, "cylinder head sector\n"
354 "-------- ---- ----------\n");
355 break;
356 }
357
358 /* device did not return any defects. */
359 if (defects == 0) {
360 printf(": none\n");
361 return;
362 }
363
364 printf(": %d\n", defects);
365
366 /* print heading. */
367 printf("%s", msg);
368
369 /* print defect list. */
370 for (i = 0 ; i < defects; i++) {
371 pfunc(&data->defect_descriptor[i]);
372 }
373
374 free(data);
375 return;
376 }
377
378 /*
379 * print_bf_dd:
380 *
381 * Print a block format defect descriptor.
382 */
383 static void
384 print_bf_dd(union scsi_defect_descriptor *dd)
385 {
386 u_int32_t block;
387
388 block = _4btol(dd->bf.block_address);
389
390 printf("%13u\n", block);
391 }
392
393 #define DEFECTIVE_TRACK 0xffffffff
394
395 /*
396 * print_bfif_dd:
397 *
398 * Print a bytes from index format defect descriptor.
399 */
400 static void
401 print_bfif_dd(union scsi_defect_descriptor *dd)
402 {
403 u_int32_t cylinder;
404 u_int32_t head;
405 u_int32_t bytes_from_index;
406
407 cylinder = _3btol(dd->bfif.cylinder);
408 head = dd->bfif.head;
409 bytes_from_index = _4btol(dd->bfif.bytes_from_index);
410
411 printf("%8u %4u ", cylinder, head);
412
413 if (bytes_from_index == DEFECTIVE_TRACK)
414 printf("entire track defective\n");
415 else
416 printf("%10u\n", bytes_from_index);
417 }
418
419 /*
420 * print_psf_dd:
421 *
422 * Print a physical sector format defect descriptor.
423 */
424 static void
425 print_psf_dd(union scsi_defect_descriptor *dd)
426 {
427 u_int32_t cylinder;
428 u_int32_t head;
429 u_int32_t sector;
430
431 cylinder = _3btol(dd->psf.cylinder);
432 head = dd->psf.head;
433 sector = _4btol(dd->psf.sector);
434
435 printf("%8u %4u ", cylinder, head);
436
437 if (sector == DEFECTIVE_TRACK)
438 printf("entire track defective\n");
439 else
440 printf("%10u\n", sector);
441 }
442
443 /*
444 * device_format:
445 *
446 * Format a direct access device.
447 */
448 static void
449 device_format(int argc, char *argv[])
450 {
451 u_int32_t blksize;
452 int i, j, immediate;
453 #define PC (65536/10)
454 static int complete[] = {
455 PC*1, PC*2, PC*3, PC*4, PC*5, PC*6, PC*7, PC*8, PC*9, 65536
456 };
457 char *cp, buffer[64];
458 struct scsi_sense_data sense;
459 struct scsi_format_unit cmd;
460 struct {
461 struct scsi_format_unit_defect_list_header header;
462 /* optional initialization pattern */
463 /* optional defect list */
464 } dfl;
465 struct {
466 struct scsi_mode_parameter_header_6 header;
467 struct scsi_general_block_descriptor blk_desc;
468 struct page_disk_format format_page;
469 } mode_page;
470 struct {
471 struct scsi_mode_parameter_header_6 header;
472 struct scsi_general_block_descriptor blk_desc;
473 } data_select;
474
475
476 /* Blocksize is an optional argument. */
477 if (argc > 2)
478 usage();
479
480 /*
481 * Loop doing Request Sense to clear any pending Unit Attention.
482 *
483 * Multiple conditions may exist on the drive which are returned
484 * in priority order.
485 */
486 for (i = 0; i < 8; i++) {
487 scsi_request_sense(fd, &sense, sizeof (sense));
488 if ((j = SSD_SENSE_KEY(sense.flags)) == SKEY_NO_SENSE)
489 break;
490 }
491 /*
492 * Make sure we cleared any pending Unit Attention
493 */
494 if (j != SKEY_NO_SENSE) {
495 cp = scsi_decode_sense((const unsigned char *) &sense, 2,
496 buffer, sizeof (buffer));
497 errx(1, "failed to clean Unit Attention: %s", cp);
498 }
499
500 /*
501 * Get the DISK FORMAT mode page. SCSI-2 recommends specifying the
502 * interleave read from this page in the FORMAT UNIT command.
503 */
504 scsi_mode_sense(fd, 0x03, 0x00, &mode_page, sizeof(mode_page));
505
506 j = (mode_page.format_page.bytes_s[0] << 8) |
507 (mode_page.format_page.bytes_s[1]);
508
509 if (j != DEV_BSIZE)
510 printf("current disk sector size: %d\n", j);
511
512 memset(&cmd, 0, sizeof(cmd));
513
514 cmd.opcode = SCSI_FORMAT_UNIT;
515 memcpy(cmd.interleave, mode_page.format_page.interleave,
516 sizeof(cmd.interleave));
517
518 /*
519 * The blocksize on the device is only changed if the user
520 * specified a new blocksize. If not specified the blocksize
521 * used for the device will be the Default value in the device.
522 * We don't specify the number of blocks since the format
523 * command will always reformat the entire drive. Also by
524 * not specifying a block count the drive will reset the
525 * block count to the maximum available after the format
526 * completes if the blocksize was changed in the format.
527 * Finally, the new disk geometry will not but updated on
528 * the drive in permanent storage until _AFTER_ the format
529 * completes successfully.
530 */
531 if (argc > 0) {
532 blksize = strtoul(argv[0], &cp, 10);
533 if (*cp != '\0')
534 errx(1, "invalid block size: %s", argv[0]);
535
536 memset(&data_select, 0, sizeof(data_select));
537
538 data_select.header.blk_desc_len =
539 sizeof(struct scsi_general_block_descriptor);
540 /*
541 * blklen in desc is 3 bytes with a leading reserved byte
542 */
543 _lto4b(blksize, &data_select.blk_desc.reserved);
544
545 /*
546 * Issue Mode Select to modify the device blocksize to be
547 * used on the Format. The modified device geometry will
548 * be stored as Current and Saved Page 3 parameters when
549 * the Format completes.
550 */
551 scsi_mode_select(fd, 0, &data_select, sizeof(data_select));
552
553 /*
554 * Since user specified a specific block size make sure it
555 * gets stored in the device when the format completes.
556 *
557 * Also scrub the defect list back to the manufacturers
558 * original.
559 */
560 cmd.flags = SFU_CMPLST | SFU_FMTDATA;
561 }
562
563 memset(&dfl, 0, sizeof(dfl));
564
565 if (argc > 1 && strncmp(argv[1], "imm", 3) == 0) {
566 /*
567 * Signal target for an immediate return from Format.
568 *
569 * We'll poll for completion status.
570 */
571 dfl.header.flags = DLH_IMMED;
572 immediate = 1;
573 } else {
574 immediate = 0;
575 }
576
577 scsi_command(fd, &cmd, sizeof(cmd), &dfl, sizeof(dfl),
578 8 * 60 * 60 * 1000, SCCMD_WRITE);
579
580 /*
581 * Poll device for completion of Format
582 */
583 if (immediate) {
584 i = 0;
585 printf("formatting.");
586 fflush(stdout);
587 do {
588 scsireq_t req;
589 struct scsi_test_unit_ready tcmd;
590
591 memset(&tcmd, 0, sizeof(tcmd));
592 tcmd.opcode = SCSI_TEST_UNIT_READY;
593
594 memset(&req, 0, sizeof(req));
595 memcpy(req.cmd, &tcmd, 6);
596 req.cmdlen = 6;
597 req.timeout = 10000;
598 req.senselen = SENSEBUFLEN;
599
600 if (ioctl(fd, SCIOCCOMMAND, &req) == -1) {
601 err(1, "SCIOCCOMMAND");
602 }
603
604 if (req.retsts == SCCMD_OK) {
605 break;
606 } else if (req.retsts == SCCMD_TIMEOUT) {
607 fprintf(stderr, "%s: SCSI command timed out",
608 dvname);
609 break;
610 } else if (req.retsts == SCCMD_BUSY) {
611 fprintf(stderr, "%s: device is busy",
612 dvname);
613 break;
614 } else if (req.retsts != SCCMD_SENSE) {
615 fprintf(stderr,
616 "%s: device had unknown status %x", dvname,
617 req.retsts);
618 break;
619 }
620 memcpy(&sense, req.sense, sizeof(sense));
621 if (sense.sks.sks_bytes[0] & SSD_SKSV) {
622 j = (sense.sks.sks_bytes[1] << 8) |
623 (sense.sks.sks_bytes[2]);
624 if (j >= complete[i]) {
625 printf(".%d0%%.", ++i);
626 fflush(stdout);
627 }
628 }
629 sleep(10);
630 } while (SSD_SENSE_KEY(sense.flags) == SKEY_NOT_READY);
631 printf(".100%%..done.\n");
632 }
633 return;
634 }
635
636 /*
637 * device_identify:
638 *
639 * Display the identity of the device, including it's SCSI bus,
640 * target, lun, and it's vendor/product/revision information.
641 */
642 static void
643 device_identify(int argc, char *argv[])
644 {
645 struct scsipi_inquiry_data inqbuf;
646 struct scsipi_inquiry cmd;
647
648 /* x4 in case every character is escaped, +1 for NUL. */
649 char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
650 product[(sizeof(inqbuf.product) * 4) + 1],
651 revision[(sizeof(inqbuf.revision) * 4) + 1];
652
653 /* No arguments. */
654 if (argc != 0)
655 usage();
656
657 memset(&cmd, 0, sizeof(cmd));
658 memset(&inqbuf, 0, sizeof(inqbuf));
659
660 cmd.opcode = INQUIRY;
661 cmd.length = sizeof(inqbuf);
662
663 scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf),
664 10000, SCCMD_READ);
665
666 scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
667 sizeof(inqbuf.vendor));
668 scsi_strvis(product, sizeof(product), inqbuf.product,
669 sizeof(inqbuf.product));
670 scsi_strvis(revision, sizeof(revision), inqbuf.revision,
671 sizeof(inqbuf.revision));
672
673 printf("%s: scsibus%d target %d lun %d <%s, %s, %s>\n",
674 dvname, dvaddr.addr.scsi.scbus, dvaddr.addr.scsi.target,
675 dvaddr.addr.scsi.lun, vendor, product, revision);
676
677 return;
678 }
679
680 /*
681 * device_reassign:
682 *
683 * Reassign bad blocks on a direct access device.
684 */
685 static void
686 device_reassign(int argc, char *argv[])
687 {
688 struct scsi_reassign_blocks cmd;
689 struct scsi_reassign_blocks_data *data;
690 size_t dlen;
691 u_int32_t blkno;
692 int i;
693 char *cp;
694
695 /* We get a list of block numbers. */
696 if (argc < 1)
697 usage();
698
699 /*
700 * Allocate the reassign blocks descriptor. The 4 comes from the
701 * size of the block address in the defect descriptor.
702 */
703 dlen = sizeof(struct scsi_reassign_blocks_data) + ((argc - 1) * 4);
704 data = malloc(dlen);
705 if (data == NULL)
706 errx(1, "unable to allocate defect descriptor");
707 memset(data, 0, dlen);
708
709 cmd.opcode = SCSI_REASSIGN_BLOCKS;
710 cmd.byte2 = 0;
711 cmd.unused[0] = 0;
712 cmd.unused[1] = 0;
713 cmd.unused[2] = 0;
714 cmd.control = 0;
715
716 /* Defect descriptor length. */
717 _lto2b(argc * 4, data->length);
718
719 /* Build the defect descriptor list. */
720 for (i = 0; i < argc; i++) {
721 blkno = strtoul(argv[i], &cp, 10);
722 if (*cp != '\0')
723 errx(1, "invalid block number: %s", argv[i]);
724 _lto4b(blkno, data->defect_descriptor[i].dlbaddr);
725 }
726
727 scsi_command(fd, &cmd, sizeof(cmd), data, dlen, 30000, SCCMD_WRITE);
728
729 free(data);
730 return;
731 }
732
733 /*
734 * device_release:
735 *
736 * Issue a RELEASE command to a SCSI device.
737 */
738 #ifndef SCSI_RELEASE
739 #define SCSI_RELEASE 0x17
740 #endif
741 static void
742 device_release(int argc, char *argv[])
743 {
744 struct scsi_test_unit_ready cmd; /* close enough */
745
746 /* No arguments. */
747 if (argc != 0)
748 usage();
749
750 memset(&cmd, 0, sizeof(cmd));
751
752 cmd.opcode = SCSI_RELEASE;
753
754 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
755
756 return;
757 }
758
759
760
761 /*
762 * device_reserve:
763 *
764 * Issue a RESERVE command to a SCSI device.
765 */
766 #ifndef SCSI_RESERVE
767 #define SCSI_RESERVE 0x16
768 #endif
769 static void
770 device_reserve(int argc, char *argv[])
771 {
772 struct scsi_test_unit_ready cmd; /* close enough */
773
774 /* No arguments. */
775 if (argc != 0)
776 usage();
777
778 memset(&cmd, 0, sizeof(cmd));
779
780 cmd.opcode = SCSI_RESERVE;
781
782 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
783
784 return;
785 }
786
787 /*
788 * device_reset:
789 *
790 * Issue a reset to a SCSI device.
791 */
792 static void
793 device_reset(int argc, char *argv[])
794 {
795
796 /* No arguments. */
797 if (argc != 0)
798 usage();
799
800 if (ioctl(fd, SCIOCRESET, NULL) != 0)
801 err(1, "SCIOCRESET");
802
803 return;
804 }
805
806 /*
807 * device_debug:
808 *
809 * Set debug level to a SCSI device.
810 * scsipi will print anything iff SCSIPI_DEBUG set in config.
811 */
812 static void
813 device_debug(int argc, char *argv[])
814 {
815 int lvl;
816
817 if (argc < 1)
818 usage();
819
820 lvl = atoi(argv[0]);
821
822 if (ioctl(fd, SCIOCDEBUG, &lvl) != 0)
823 err(1, "SCIOCDEBUG");
824
825 return;
826 }
827
828 /*
829 * device_getcache:
830 *
831 * Get the caching parameters for a SCSI disk.
832 */
833 static void
834 device_getcache(int argc, char *argv[])
835 {
836 struct {
837 struct scsi_mode_parameter_header_6 header;
838 struct scsi_general_block_descriptor blk_desc;
839 struct page_caching caching_params;
840 } data;
841
842 /* No arguments. */
843 if (argc != 0)
844 usage();
845
846 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
847
848 if ((data.caching_params.flags & (CACHING_RCD|CACHING_WCE)) ==
849 CACHING_RCD)
850 printf("%s: no caches enabled\n", dvname);
851 else {
852 printf("%s: read cache %senabled\n", dvname,
853 (data.caching_params.flags & CACHING_RCD) ? "not " : "");
854 printf("%s: write-back cache %senabled\n", dvname,
855 (data.caching_params.flags & CACHING_WCE) ? "" : "not ");
856 }
857 printf("%s: caching parameters are %ssavable\n", dvname,
858 (data.caching_params.pg_code & PGCODE_PS) ? "" : "not ");
859 }
860
861 /*
862 * device_setcache:
863 *
864 * Set cache enables for a SCSI disk.
865 */
866 static void
867 device_setcache(int argc, char *argv[])
868 {
869 struct {
870 struct scsi_mode_parameter_header_6 header;
871 struct scsi_general_block_descriptor blk_desc;
872 struct page_caching caching_params;
873 } data;
874 int dlen;
875 u_int8_t flags, byte2;
876
877 if (argc > 2 || argc == 0)
878 usage();
879
880 flags = 0;
881 byte2 = 0;
882 if (strcmp(argv[0], "none") == 0)
883 flags = CACHING_RCD;
884 else if (strcmp(argv[0], "r") == 0)
885 flags = 0;
886 else if (strcmp(argv[0], "w") == 0)
887 flags = CACHING_RCD|CACHING_WCE;
888 else if (strcmp(argv[0], "rw") == 0)
889 flags = CACHING_WCE;
890 else
891 usage();
892
893 if (argc == 2) {
894 if (strcmp(argv[1], "save") == 0)
895 byte2 = SMS_SP;
896 else
897 usage();
898 }
899
900 scsi_mode_sense(fd, 0x08, 0x00, &data, sizeof(data));
901
902 data.caching_params.pg_code &= PGCODE_MASK;
903 data.caching_params.flags =
904 (data.caching_params.flags & ~(CACHING_RCD|CACHING_WCE)) | flags;
905
906 data.caching_params.cache_segment_size[0] = 0;
907 data.caching_params.cache_segment_size[1] = 0;
908
909 data.header.data_length = 0;
910
911 dlen = sizeof(data.header) + sizeof(data.blk_desc) + 2 +
912 data.caching_params.pg_length;
913
914 scsi_mode_select(fd, byte2, &data, dlen);
915 }
916
917 /*
918 * device_flushcache:
919 *
920 * Issue a FLUSH CACHE command to a SCSI device.
921 */
922 #ifndef SCSI_FLUSHCACHE
923 #define SCSI_FLUSHCACHE 0x35
924 #endif
925 static void
926 device_flushcache(int argc, char *argv[])
927 {
928 struct scsi_test_unit_ready cmd; /* close enough */
929
930 /* No arguments. */
931 if (argc != 0)
932 usage();
933
934 memset(&cmd, 0, sizeof(cmd));
935
936 cmd.opcode = SCSI_FLUSHCACHE;
937
938 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
939
940 return;
941 }
942
943 /*
944 * device_setspeed:
945 *
946 * Set rotation speed to a CD/DVD drive.
947 */
948 static void
949 device_setspeed(int argc, char *argv[])
950 {
951 u_char cmd[11];
952 u_char pd[28];
953 u_int32_t speed;
954
955 if (argc != 1)
956 usage();
957
958 speed = atoi(argv[0]) * 177;
959
960 memset(&pd, 0, sizeof(pd));
961 if (speed == 0)
962 pd[0] = 4; /* restore drive defaults */
963 pd[8] = 0xff;
964 pd[9] = 0xff;
965 pd[10] = 0xff;
966 pd[11] = 0xff;
967 pd[12] = pd[20] = (speed >> 24) & 0xff;
968 pd[13] = pd[21] = (speed >> 16) & 0xff;
969 pd[14] = pd[22] = (speed >> 8) & 0xff;
970 pd[15] = pd[23] = speed & 0xff;
971 pd[18] = pd[26] = 1000 >> 8;
972 pd[19] = pd[27] = 1000 & 0xff;
973
974 memset(&cmd, 0, sizeof(cmd));
975 cmd[0] = 0xb6;
976 cmd[10] = sizeof(pd);
977
978 scsi_command(fd, &cmd, sizeof(cmd), pd, sizeof(pd), 10000, SCCMD_WRITE);
979
980 return;
981 }
982
983 /*
984 * device_prevent:
985 *
986 * Issue a prevent to a SCSI device.
987 */
988 static void
989 device_prevent(int argc, char *argv[])
990 {
991 struct scsi_prevent_allow_medium_removal cmd;
992
993 /* No arguments. */
994 if (argc != 0)
995 usage();
996
997 memset(&cmd, 0, sizeof(cmd));
998
999 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
1000 cmd.how = SPAMR_PREVENT_DT; /* XXX SMAMR_PREVENT_ALL? */
1001
1002 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1003
1004 return;
1005 }
1006
1007 /*
1008 * device_allow:
1009 *
1010 * Issue a stop to a SCSI device.
1011 */
1012 static void
1013 device_allow(int argc, char *argv[])
1014 {
1015 struct scsi_prevent_allow_medium_removal cmd;
1016
1017 /* No arguments. */
1018 if (argc != 0)
1019 usage();
1020
1021 memset(&cmd, 0, sizeof(cmd));
1022
1023 cmd.opcode = SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL;
1024 cmd.how = SPAMR_ALLOW;
1025
1026 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1027
1028 return;
1029 }
1030
1031 /*
1032 * device_start:
1033 *
1034 * Issue a start to a SCSI device.
1035 */
1036 static void
1037 device_start(int argc, char *argv[])
1038 {
1039 struct scsipi_start_stop cmd;
1040
1041 /* No arguments. */
1042 if (argc != 0)
1043 usage();
1044
1045 memset(&cmd, 0, sizeof(cmd));
1046
1047 cmd.opcode = START_STOP;
1048 cmd.how = SSS_START;
1049
1050 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0);
1051
1052 return;
1053 }
1054
1055 /*
1056 * device_stop:
1057 *
1058 * Issue a stop to a SCSI device.
1059 */
1060 static void
1061 device_stop(int argc, char *argv[])
1062 {
1063 struct scsipi_start_stop cmd;
1064
1065 /* No arguments. */
1066 if (argc != 0)
1067 usage();
1068
1069 memset(&cmd, 0, sizeof(cmd));
1070
1071 cmd.opcode = START_STOP;
1072 cmd.how = SSS_STOP;
1073
1074 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 30000, 0);
1075
1076 return;
1077 }
1078
1079 /*
1080 * device_tur:
1081 *
1082 * Issue a TEST UNIT READY to a SCSI device.
1083 */
1084 static void
1085 device_tur(int argc, char *argv[])
1086 {
1087 struct scsi_test_unit_ready cmd;
1088
1089 /* No arguments. */
1090 if (argc != 0)
1091 usage();
1092
1093 memset(&cmd, 0, sizeof(cmd));
1094
1095 cmd.opcode = SCSI_TEST_UNIT_READY;
1096
1097 scsi_command(fd, &cmd, sizeof(cmd), NULL, 0, 10000, 0);
1098
1099 return;
1100 }
1101
1102 /*
1103 * BUS COMMANDS
1104 */
1105
1106 /*
1107 * bus_reset:
1108 *
1109 * Issue a reset to a SCSI bus.
1110 */
1111 static void
1112 bus_reset(int argc, char *argv[])
1113 {
1114
1115 /* No arguments. */
1116 if (argc != 0)
1117 usage();
1118
1119 if (ioctl(fd, SCBUSIORESET, NULL) != 0)
1120 err(1, "SCBUSIORESET");
1121
1122 return;
1123 }
1124
1125 /*
1126 * bus_scan:
1127 *
1128 * Rescan a SCSI bus for new devices.
1129 */
1130 static void
1131 bus_scan(int argc, char *argv[])
1132 {
1133 struct scbusioscan_args args;
1134 char *cp;
1135
1136 /* Must have two args: target lun */
1137 if (argc != 2)
1138 usage();
1139
1140 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1141 args.sa_target = -1;
1142 else {
1143 args.sa_target = strtol(argv[0], &cp, 10);
1144 if (*cp != '\0' || args.sa_target < 0)
1145 errx(1, "invalid target: %s", argv[0]);
1146 }
1147
1148 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0)
1149 args.sa_lun = -1;
1150 else {
1151 args.sa_lun = strtol(argv[1], &cp, 10);
1152 if (*cp != '\0' || args.sa_lun < 0)
1153 errx(1, "invalid lun: %s", argv[1]);
1154 }
1155
1156 if (ioctl(fd, SCBUSIOSCAN, &args) != 0)
1157 err(1, "SCBUSIOSCAN");
1158
1159 return;
1160 }
1161
1162 /*
1163 * bus_detach:
1164 *
1165 * detach SCSI devices from a bus.
1166 */
1167 static void
1168 bus_detach(int argc, char *argv[])
1169 {
1170 struct scbusiodetach_args args;
1171 char *cp;
1172
1173 /* Must have two args: target lun */
1174 if (argc != 2)
1175 usage();
1176
1177 if (strcmp(argv[0], "any") == 0 || strcmp(argv[0], "all") == 0)
1178 args.sa_target = -1;
1179 else {
1180 args.sa_target = strtol(argv[0], &cp, 10);
1181 if (*cp != '\0' || args.sa_target < 0)
1182 errx(1, "invalid target: %s", argv[0]);
1183 }
1184
1185 if (strcmp(argv[1], "any") == 0 || strcmp(argv[1], "all") == 0)
1186 args.sa_lun = -1;
1187 else {
1188 args.sa_lun = strtol(argv[1], &cp, 10);
1189 if (*cp != '\0' || args.sa_lun < 0)
1190 errx(1, "invalid lun: %s", argv[1]);
1191 }
1192
1193 if (ioctl(fd, SCBUSIODETACH, &args) != 0)
1194 err(1, "SCBUSIODETACH");
1195
1196 return;
1197 }
1198