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