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