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