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