[BACK]Return to scsictl.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / scsictl

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>