diff options
author | dufault <dufault@FreeBSD.org> | 1995-01-08 13:38:38 +0000 |
---|---|---|
committer | dufault <dufault@FreeBSD.org> | 1995-01-08 13:38:38 +0000 |
commit | 3cf1ff13e332d0b753ba08fe1e3ad5b994f1ac6c (patch) | |
tree | 273bcb9e1be1a1dad1080681ddc7edafb2c2060a /sys/scsi | |
parent | c280bae2f039222946dd53421445e050d5f7d844 (diff) | |
download | FreeBSD-src-3cf1ff13e332d0b753ba08fe1e3ad5b994f1ac6c.zip FreeBSD-src-3cf1ff13e332d0b753ba08fe1e3ad5b994f1ac6c.tar.gz |
Reviewed by: gibbs@estienne.CS.Berkeley.EDU
Reenabled "SCIOCOMAND" ioctl.
Restructured so low level drivers can easily request retries.
Added preliminary fixed SCSI devices (should be revisited before 2.1)
Added "ssc" device that can have its' (HBA, ID, LUN) set via ioctl.
Diffstat (limited to 'sys/scsi')
-rw-r--r-- | sys/scsi/cd.c | 22 | ||||
-rw-r--r-- | sys/scsi/ch.c | 12 | ||||
-rw-r--r-- | sys/scsi/scsi_all.h | 48 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 264 | ||||
-rw-r--r-- | sys/scsi/scsi_generic.h | 4 | ||||
-rw-r--r-- | sys/scsi/scsi_ioctl.c | 91 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 70 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 105 | ||||
-rw-r--r-- | sys/scsi/sd.c | 89 | ||||
-rw-r--r-- | sys/scsi/ssc.c | 82 | ||||
-rw-r--r-- | sys/scsi/st.c | 50 | ||||
-rw-r--r-- | sys/scsi/su.c | 271 | ||||
-rw-r--r-- | sys/scsi/uk.c | 10 |
13 files changed, 921 insertions, 197 deletions
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index f42b6df..a95f99f 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: cd.c,v 1.31 1994/12/16 06:03:22 phk Exp $ + * $Id: cd.c,v 1.32 1994/12/24 09:48:32 bde Exp $ */ #define SPLCD splbio @@ -63,10 +63,8 @@ int32 cdstrats, cdqueues; #define CDOUTSTANDING 2 #define CDRETRIES 1 -#define UNITSHIFT 3 #define PARTITION(z) (minor(z) & 0x07) #define RAW_PART 2 -#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) errval cdstrategy(); @@ -159,6 +157,7 @@ cd_registerdev(int unit) } +errval cdopen(); /* * The routine called by the low level scsi routine when it discovers * A device suitable for this driver @@ -226,6 +225,7 @@ cdattach(sc_link) cd->sc_link = sc_link; sc_link->device = &cd_switch; sc_link->dev_unit = unit; + sc_link->dev = CDSETUNIT(scsi_dev_lookup(cdopen), unit); if (cd->sc_link->adapter->adapter_info) { cd->ad_info = ((*(cd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit)); @@ -268,7 +268,7 @@ cdopen(dev) struct cd_data *cd; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = CDUNIT(dev); part = PARTITION(dev); /* @@ -357,7 +357,7 @@ cdopen(dev) cd->openparts |= (1 << part); SC_DEBUG(sc_link, SDEV_DB3, ("open complete\n")); sc_link->flags |= SDEV_MEDIA_LOADED; - return (0); + return 0; bad: /* @@ -383,7 +383,7 @@ cdclose(dev) struct cd_data *cd; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = CDUNIT(dev); part = PARTITION(dev); cd = cd_driver.cd_data[unit]; sc_link = cd->sc_link; @@ -413,7 +413,7 @@ void cdminphys(bp) struct buf *bp; { - (*(cd_driver.cd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); + (*(cd_driver.cd_data[CDUNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } /* @@ -427,7 +427,7 @@ cdstrategy(bp) { struct buf *dp; u_int32 opri; - u_int32 unit = UNIT((bp->b_dev)); + u_int32 unit = CDUNIT((bp->b_dev)); struct cd_data *cd = cd_driver.cd_data[unit]; cdstrats++; @@ -629,7 +629,7 @@ cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) /* * Find the device that the user is talking about */ - unit = UNIT(dev); + unit = CDUNIT(dev); part = PARTITION(dev); cd = cd_driver.cd_data[unit]; SC_DEBUG(cd->sc_link, SDEV_DB2, ("cdioctl 0x%x ", cmd)); @@ -949,8 +949,8 @@ cdioctl(dev_t dev, int cmd, caddr_t addr, int flag) return (cd_reset(unit)); break; default: - if(part == RAW_PART) - error = scsi_do_ioctl(cd->sc_link,cmd,addr,flag); + if(part == RAW_PART || SCSI_SUPER(dev)) + error = scsi_do_ioctl(dev, cd->sc_link,cmd,addr,flag); else error = ENOTTY; break; diff --git a/sys/scsi/ch.c b/sys/scsi/ch.c index 662038e..b39de58 100644 --- a/sys/scsi/ch.c +++ b/sys/scsi/ch.c @@ -2,7 +2,7 @@ * Written by grefen@????? * Based on scsi drivers by Julian Elischer (julian@tfs.com) * - * $Id: ch.c,v 1.10 1994/10/21 01:19:20 wollman Exp $ + * $Id: ch.c,v 1.11 1994/10/23 21:27:53 wollman Exp $ */ #include <sys/types.h> @@ -34,7 +34,6 @@ u_int32 ch_xfer_block_wait[NCH]; #define CHRETRIES 2 #define MODE(z) ( (minor(z) & 0x0F) ) -#define UNIT(z) ( (minor(z) >> 4) ) #define ESUCCESS 0 @@ -140,6 +139,7 @@ chattach(sc_link) ch_data[unit].sc_link = sc_link; sc_link->device = &ch_switch; sc_link->dev_unit = unit; + sc_link->dev = CHSETUNIT(scsi_dev_lookup(chopen), unit); /* * Use the subdriver to request information regarding @@ -172,7 +172,7 @@ chopen(dev) u_int32 unit, mode; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = CHUNIT(dev); mode = MODE(dev); /* @@ -237,7 +237,7 @@ chclose(dev) unsigned char unit, mode; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = CHUNIT(dev); mode = MODE(dev); sc_link = ch_data[unit].sc_link; @@ -272,7 +272,7 @@ chioctl(dev, cmd, arg, mode) * Find the device that the user is talking about */ flags = 0; /* give error messages, act on errors etc. */ - unit = UNIT(dev); + unit = CHUNIT(dev); sc_link = ch_data[unit].sc_link; switch ((int)cmd) { @@ -312,7 +312,7 @@ chioctl(dev, cmd, arg, mode) } } default: - return scsi_do_ioctl(sc_link, cmd, arg, mode); + return scsi_do_ioctl(dev, sc_link, cmd, arg, mode); } return (ret ? ESUCCESS : EIO); } diff --git a/sys/scsi/scsi_all.h b/sys/scsi/scsi_all.h index ad05f0f..fb921fd 100644 --- a/sys/scsi/scsi_all.h +++ b/sys/scsi/scsi_all.h @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsi_all.h,v 1.6 1993/11/18 05:02:49 rgrimes Exp $ + * $Id: scsi_all.h,v 1.7 1994/08/02 07:52:32 davidg Exp $ */ /* @@ -268,6 +268,28 @@ struct scsi_sense_data } extended; }ext; }; /* total of 32 bytes */ + +struct scsi_sense_extended +{ +/* 2*/ u_char segment; +/* 3*/ u_char flags; +#define SSD_KEY 0x0F +#define SSD_ILI 0x20 +#define SSD_EOM 0x40 +#define SSD_FILEMARK 0x80 +/* 7*/ u_char info[4]; +/* 8*/ u_char extra_len; +/*12*/ u_char cmd_spec_info[4]; +/*13*/ u_char add_sense_code; +/*14*/ u_char add_sense_code_qual; +/*15*/ u_char fru; +/*16*/ u_char sense_key_spec_1; +#define SSD_SCS_VALID 0x80 +/*17*/ u_char sense_key_spec_2; +/*18*/ u_char sense_key_spec_3; +/*32*/ u_char extra_bytes[14]; +} extended; + struct scsi_sense_data_new { /* 1*/ u_char error_code; @@ -281,27 +303,9 @@ struct scsi_sense_data_new /* 3*/ u_char blockmed; /* 4*/ u_char blocklow; } unextended; - struct - { -/* 2*/ u_char segment; -/* 3*/ u_char flags; -#define SSD_KEY 0x0F -#define SSD_ILI 0x20 -#define SSD_EOM 0x40 -#define SSD_FILEMARK 0x80 -/* 7*/ u_char info[4]; -/* 8*/ u_char extra_len; -/*12*/ u_char cmd_spec_info[4]; -/*13*/ u_char add_sense_code; -/*14*/ u_char add_sense_code_qual; -/*15*/ u_char fru; -/*16*/ u_char sense_key_spec_1; -#define SSD_SCS_VALID 0x80 -/*17*/ u_char sense_key_spec_2; -/*18*/ u_char sense_key_spec_3; -/*32*/ u_char extra_bytes[14]; - } extended; - }ext; + + struct scsi_sense_extended extended; + } ext; }; /* total of 32 bytes */ struct blk_desc diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index 4e4b21f..4fae13b 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -8,7 +8,7 @@ * file. * * Written by Julian Elischer (julian@dialix.oz.au) - * $Id: scsi_base.c,v 1.14 1994/10/08 22:26:36 phk Exp $ + * $Id: scsi_base.c,v 1.15 1994/11/15 14:49:56 bde Exp $ */ #define SPLSD splbio @@ -331,11 +331,11 @@ scsi_done(xs) */ if (xs->flags & SCSI_USER) { biodone(xs->bp); -#ifdef NOTNOW + SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n")); scsi_user_done(xs); /* to take a copy of the sense etc. */ SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n ")); -#endif + free_xs(xs, sc_link, SCSI_NOSLEEP); /* restarts queue too */ SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n")); return; @@ -353,6 +353,9 @@ scsi_done(xs) free_xs(xs, sc_link, SCSI_NOSLEEP); /*XXX */ return; /* it did it all, finish up */ } + /* BUG: This isn't used anywhere. Do you have plans for it, + * Julian? (dufault@hda.com). + */ if (retval == -2) { return; /* it did it all, finish up */ } @@ -405,7 +408,7 @@ scsi_scsi_cmd(sc_link, scsi_cmd, cmdlen, data_addr, datalen, errval retval; u_int32 s; - if (bp) flags |= SCSI_NOSLEEP; + if (bp && !(flags & SCSI_USER)) flags |= SCSI_NOSLEEP; SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); xs = get_xs(sc_link, flags); /* should wait unless booting */ @@ -567,10 +570,20 @@ sc_err1(xs) break; case XS_SENSE: + retval = scsi_interpret_sense(xs); + if (retval == SCSIRET_DO_RETRY) { + if (xs->retries--) { + xs->error = XS_NOERROR; + xs->flags &= ~ITSDONE; + goto retry; + } + } + retval = EIO; /* Too many retries */ + if (bp) { bp->b_error = 0; bp->b_resid = 0; - if (retval = (scsi_interpret_sense(xs))) { + if (retval) { bp->b_flags |= B_ERROR; bp->b_error = retval; bp->b_resid = bp->b_bcount; @@ -578,7 +591,6 @@ sc_err1(xs) SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_interpret_sense (bp) returned %d\n", retval)); } else { - retval = (scsi_interpret_sense(xs)); SC_DEBUG(xs->sc_link, SDEV_DB3, ("scsi_interpret_sense (no bp) returned %d\n", retval)); } @@ -616,10 +628,124 @@ retry: } /* + * scsi_sense_print will decode the sense data into human + * readable form. Sense handlers can use this to generate + * a report. This DOES NOT send the closing "\n". + */ +void scsi_sense_print(xs) + struct scsi_xfer *xs; +{ + struct scsi_sense_data_new *sense; + struct scsi_sense_extended *ext; + u_int32 key; + u_int32 info; + errval errcode; + + /* This sense key text now matches what is in the SCSI spec + * (Yes, even the capitals) + * so that it is easier to look through the spec to find the + * appropriate place. + */ + static char *sense_key_text[] = + { + "RECOVERED ERROR", + "NOT READY", "MEDIUM ERROR", + "HARDWARE FAILURE", "ILLEGAL REQUEST", + "UNIT ATTENTION", "DATA PROTECT", + "BLANK CHECK", "Vendor Specific", + "COPY ABORTED", "ABORTED COMMAND", + "EQUAL", "VOLUME OVERFLOW", + "MISCOMPARE", "RESERVED" + }; + + sc_print_addr(xs->sc_link); + + sense = (struct scsi_sense_data_new *)&(xs->sense); + ext = &(sense->ext.extended); + + key = ext->flags & SSD_KEY; + + switch (sense->error_code & SSD_ERRCODE) { + case 0x71: /* deferred error */ + printf("Deferred Error: "); + + /* DROP THROUGH */ + + case 0x70: + + printf("%s", sense_key_text[key - 1]); + info = ntohl(*((long *) ext->info)); + + if (sense->error_code & SSD_ERRCODE_VALID) { + + switch ((int)key) { + case 0x2: /* NOT READY */ + case 0x5: /* ILLEGAL REQUEST */ + case 0x6: /* UNIT ATTENTION */ + case 0x7: /* DATA PROTECT */ + break; + case 0x8: /* BLANK CHECK */ + printf(" requested size: %ld (decimal)", + info); + break; + default: + if (info) + printf(" info:%08lx", info); + } + } + else if (info) + printf(" info(inval):%08lx", info); + + if (ext->extra_len >= 4) { + if (memcmp(ext->cmd_spec_info, "\0\0\0\0", 4)) { + printf(" csi:%02x,%02x,%02x,%02x", + ext->cmd_spec_info[0], + ext->cmd_spec_info[1], + ext->cmd_spec_info[2], + ext->cmd_spec_info[3]); + } + } + + if (ext->extra_len >= 5 && ext->add_sense_code) { + printf(" asc:%02x", ext->add_sense_code); + } + + if (ext->extra_len >= 6 && ext->add_sense_code_qual) { + printf(" ascq:%02x", ext->add_sense_code_qual); + } + + if (ext->extra_len >= 7 && ext->fru) { + printf(" fru:%02x", ext->fru); + } + + if (ext->extra_len >= 10 && + (ext->sense_key_spec_1 & SSD_SCS_VALID)) { + printf(" sks:%02x,%04x", ext->sense_key_spec_1, + (ext->sense_key_spec_2 | + ext->sense_key_spec_3)); + } + break; + + /* + * Not code 70, just report it + */ + default: + printf("error code %d", + sense->error_code & SSD_ERRCODE); + if (sense->error_code & SSD_ERRCODE_VALID) { + printf(" at block no. %ld (decimal)", + (((unsigned long)sense->ext.unextended.blockhi) << 16) + + (((unsigned long)sense->ext.unextended.blockmed) << 8) + + ((unsigned long)sense->ext.unextended.blocklow)); + } + } +} + +/* * Look at the returned sense and act on the error, determining * the unix error number to pass back. (0 = report no error) * - * THIS IS THE DEFAULT ERROR HANDLER + * THIS IS THE DEFAULT SENSE HANDLER */ static errval scsi_interpret_sense(xs) @@ -629,22 +755,11 @@ scsi_interpret_sense(xs) struct scsi_link *sc_link = xs->sc_link; u_int32 key; u_int32 silent; - u_int32 info; errval errcode; - static char *error_mes[] = - {"soft error (corrected)", - "not ready", "medium error", - "non-media hardware failure", "illegal request", - "unit attention", "readonly device", - "no data found", "vendor unique", - "copy aborted", "command aborted", - "search returned equal", "volume overflow", - "verify miscompare", "unknown error key" - }; - /* * If the flags say errs are ok, then always return ok. + * BUG: What if it is a deferred error? */ if (xs->flags & SCSI_ERR_OK) return (ESUCCESS); @@ -652,6 +767,7 @@ scsi_interpret_sense(xs) sense = &(xs->sense); #ifdef SCSIDEBUG if (sc_link->flags & SDEV_DB1) { + u_int32 count = 0; printf("code%x valid%x ", sense->error_code & SSD_ERRCODE, @@ -674,56 +790,80 @@ scsi_interpret_sense(xs) } printf("\n"); } -#endif /*SCSIDEBUG */ + #endif /*SCSIDEBUG */ /* - * If the device has it's own error handler, call it first. - * If it returns a legit error value, return that, otherwise - * it wants us to continue with normal error processing. + * If the device has it's own sense handler, call it first. + * If it returns a legit errno value, return that, otherwise + * it should return either DO_RETRY or CONTINUE to either + * request a retry or continue with default sense handling. */ if (sc_link->device->err_handler) { SC_DEBUG(sc_link, SDEV_DB2, ("calling private err_handler()\n")); errcode = (*sc_link->device->err_handler) (xs); - if (errcode != -1) - return errcode; /* errcode >= 0 better ? */ + + if (errcode >= 0) + return errcode; /* valid errno value */ + + switch(errcode) { + case SCSIRET_DO_RETRY: /* Requested a retry */ + return errcode; + + case SCSIRET_CONTINUE: /* Continue with default sense processing */ + break; + + default: + sc_print_addr(xs->sc_link); + printf("unknown return code %d from sense handler.\n", + errcode); + + return errcode; + } } /* otherwise use the default */ silent = (xs->flags & SCSI_SILENT); + key = sense->ext.extended.flags & SSD_KEY; + + if (!silent) { + scsi_sense_print(xs); + printf("\n"); + } + switch (sense->error_code & SSD_ERRCODE) { + case 0x71: /* deferred error */ + /* Print even if silent (not silent was already done) + */ + if (silent) { + scsi_sense_print(xs); + printf("\n"); + } + + /* BUG: + * This error doesn't relate to the command associated + * with this request sense. A deferred error is an error + * for a command that has already returned GOOD status (see 7.2.14.2). + * + * By my reading of that section, it looks like the current command + * has been cancelled, we should now clean things up (hopefully + * recovering any lost data) and then + * retry the current command. There are two easy choices, both + * wrong: + * 1. Drop through (like we had been doing), thus treating this as + * if the error were for the current command and return and stop + * the current command. + * 2. Issue a retry (like I made it do) thus hopefully recovering + * the current transfer, and ignoring the fact that we've dropped + * a command. + * + * These should probably be handled in a device specific + * sense handler or punted back up to a user mode daemon + */ + return SCSIRET_DO_RETRY; + /* * If it's code 70, use the extended stuff and interpret the key */ - case 0x71: /* delayed error */ - sc_print_addr(sc_link); - key = sense->ext.extended.flags & SSD_KEY; - printf(" DELAYED ERROR, key = 0x%lx\n", (u_long)key); case 0x70: - if (sense->error_code & SSD_ERRCODE_VALID) { - info = ntohl(*((long *) sense->ext.extended.info)); - } else { - info = 0; - } - key = sense->ext.extended.flags & SSD_KEY; - if (key && !silent) { - sc_print_addr(sc_link); - printf("%s", error_mes[key - 1]); - if (sense->error_code & SSD_ERRCODE_VALID) { - switch ((int)key) { - case 0x2: /* NOT READY */ - case 0x5: /* ILLEGAL REQUEST */ - case 0x6: /* UNIT ATTENTION */ - case 0x7: /* DATA PROTECT */ - break; - case 0x8: /* BLANK CHECK */ - printf(", requested size: %ld (decimal)", - info); - break; - default: - printf(", info = %ld (decimal)", info); - } - } - printf("\n"); - } switch ((int)key) { case 0x0: /* NO SENSE */ case 0x1: /* RECOVERED ERROR */ @@ -753,21 +893,9 @@ scsi_interpret_sense(xs) return (EIO); } /* - * Not code 70, just report it + * Not code 70, return EIO */ default: - if (!silent) { - sc_print_addr(sc_link); - printf("error code %d", - sense->error_code & SSD_ERRCODE); - if (sense->error_code & SSD_ERRCODE_VALID) { - printf(" at block no. %d (decimal)", - (sense->ext.unextended.blockhi << 16) + - (sense->ext.unextended.blockmed << 8) + - (sense->ext.unextended.blocklow)); - } - printf("\n"); - } return (EIO); } } diff --git a/sys/scsi/scsi_generic.h b/sys/scsi/scsi_generic.h index 44f2bd1..db694f4 100644 --- a/sys/scsi/scsi_generic.h +++ b/sys/scsi/scsi_generic.h @@ -1,5 +1,5 @@ /* - * Contributed by HD Associates (hd@world.std.com). + * Contributed by HD Associates (contact: dufault@hda.com) * Copyright (c) 1992, 1993 HD Associates * * Berkeley style copyright. I've just snarfed it out of stdio.h: @@ -33,7 +33,7 @@ * SUCH DAMAGE. * * from: @(#)stdio.h 5.17 (Berkeley) 6/3/91 - * $Id$ + * $Id: scsi_generic.h,v 1.2 1993/10/16 17:21:05 rgrimes Exp $ */ /* generic SCSI header file. We use the same minor number format diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c index 1228ec5..5e4253b 100644 --- a/sys/scsi/scsi_ioctl.c +++ b/sys/scsi/scsi_ioctl.c @@ -1,11 +1,48 @@ /* - * Contributed by HD Associates (hd@world.std.com). - * Copyright (c) 1992, 1993 HD Associates + *Begin copyright * - * Berkeley style copyright. + * Copyright (C) 1992, 1993, 1994, HD Associates, Inc. + * PO Box 276 + * Pepperell, MA 01463 + * 508 433 5266 + * dufault@hda.com * + * This code is contributed to the University of California at Berkeley: * - * $Id: scsi_ioctl.c,v 1.7 1994/08/02 07:52:33 davidg Exp $ + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + *End copyright + * + * $Id: scsi_ioctl.c,v 1.8 1994/10/08 22:26:37 phk Exp $ + * + * + * Note: The SCSIUSER option is required to support the user defined + * ioctl calls. */ #include <sys/param.h> #include <sys/systm.h> @@ -104,13 +141,6 @@ struct scsi_xfer *xs; * Called by scsi_do_ioctl() via physio/physstrat if there is to * be data transfered, and directly if there is no data transfer. * - * Should I reorganize this so it returns to physio instead - * of sleeping in scsiio_scsi_cmd? Is there any advantage, other - * than avoiding the probable duplicate wakeup in iodone? [PD] - * - * No, seems ok to me... [JRE] - * (I don't see any duplicate wakeups) - * * Can't be used with block devices or raw_read/raw_write directly * from the cdevsw/bdevsw tables because they couldn't have added * the screq structure. [JRE] @@ -214,14 +244,15 @@ void scsiminphys(struct buf *bp) * If user-level type command, we must still be running * in the context of the calling process */ -errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f) +errval scsi_do_ioctl(dev_t dev, +struct scsi_link *sc_link, int cmd, caddr_t addr, int f) { errval ret = 0; SC_DEBUG(sc_link,SDEV_DB2,("scsi_do_ioctl(0x%x)\n",cmd)); switch(cmd) { -#if 0 +#ifdef SCSIUSER case SCIOCCOMMAND: { /* @@ -239,7 +270,9 @@ errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f) caddr_t d_addr; int len; +#if 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */ if((unsigned int)screq < (unsigned int)KERNBASE) +#endif { screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK); bcopy(screq2,screq,sizeof(scsireq_t)); @@ -251,33 +284,45 @@ errval scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f) bp->b_screq = screq; bp->b_sc_link = sc_link; if (len) { - /* have data, translate it. (physio)*/ -#ifdef __NetBSD__ -#error "dev, mincntfn & uio need defining" + struct uio auio; + struct iovec aiov; + long cnt, error = 0; + + aiov.iov_base = d_addr; + aiov.iov_len = len; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + + auio.uio_resid = len; + if (auio.uio_resid < 0) + return (EINVAL); + + auio.uio_rw = (rwflag == B_READ) ? UIO_READ : UIO_WRITE; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_procp = curproc; + cnt = len; ret = physio(scsistrategy, bp, dev, rwflag, - mincntfn, uio); -#else - ret = physio(scsistrategy,0,bp,0,rwflag, - d_addr,&len,curproc); -#endif + minphys, &auio); } else { /* if no data, no need to translate it.. */ bp->b_un.b_addr = 0; - bp->b_dev = -1; /* irrelevant info */ + bp->b_dev = dev; bp->b_flags = 0; scsistrategy(bp); ret = bp->b_error; } free(bp,M_TEMP); +#if 0 /* XXX dufault@hda.com: This looks too rev dependent. Do it always? */ if((unsigned int)screq2 < (unsigned int)KERNBASE) +#endif { bcopy(screq,screq2,sizeof(scsireq_t)); free(screq,M_TEMP); } break; } -#endif /* !NetBSD */ +#endif /* SCSIUSER */ case SCIOCDEBUG: { int level = *((int *)addr); diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index 53c1cd1..275e770 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -14,15 +14,17 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsiconf.c,v 1.16 1994/11/27 23:30:48 ats Exp $ + * $Id: scsiconf.c,v 1.17 1994/12/18 18:48:39 phk Exp $ */ #include <sys/types.h> #include <sys/param.h> #include <sys/systm.h> +#include <sys/stat.h> #include <sys/malloc.h> #include <sys/devconf.h> +#include <sys/conf.h> #include "st.h" #include "sd.h" @@ -550,6 +552,18 @@ scsi_probe_bus(int bus, int targ, int lun) return 0; } +/* Return the scsi_link for this device, if any. + */ +struct scsi_link * +scsi_link_get(bus, targ, lun) + int bus; + int targ; + int lun; +{ + struct scsibus_data *scsi = scbus_data[bus]; + return (scsi) ? scsi->sc_link[targ][lun] : 0; +} + /* * given a target and lu, check if there is a predefined device for * that address @@ -604,7 +618,7 @@ scsi_probedev(sc_link, maybe_more) struct scsidevs *bestmatch = (struct scsidevs *) 0; char *dtype = (char *) 0, *desc; char *qtype; - static struct scsi_inquiry_data inqbuf; + struct scsi_inquiry_data *inqbuf; u_int32 len, qualifier, type; boolean remov; char manu[32]; @@ -612,7 +626,9 @@ scsi_probedev(sc_link, maybe_more) char version[32]; int z; - bzero(&inqbuf, sizeof(inqbuf)); + inqbuf = &sc_link->inqbuf; + + bzero(inqbuf, sizeof(*inqbuf)); /* * Ask the device what it is */ @@ -644,16 +660,16 @@ scsi_probedev(sc_link, maybe_more) #endif /*SCSI_2_DEF */ /* Now go ask the device all about itself */ - if (scsi_inquire(sc_link, &inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) { + if (scsi_inquire(sc_link, inqbuf, SCSI_NOSLEEP | SCSI_NOMASK) != 0) { return (struct scsidevs *) 0; } /* * note what BASIC type of device it is */ - type = inqbuf.device & SID_TYPE; - qualifier = inqbuf.device & SID_QUAL; - remov = inqbuf.dev_qual2 & SID_REMOVABLE; + type = inqbuf->device & SID_TYPE; + qualifier = inqbuf->device & SID_QUAL; + remov = inqbuf->dev_qual2 & SID_REMOVABLE; /* * Any device qualifier that has the top bit set (qualifier&4 != 0) @@ -735,17 +751,17 @@ scsi_probedev(sc_link, maybe_more) * Then if it's advanced enough, more detailed * information */ - if ((inqbuf.version & SID_ANSII) > 0) { - if ((len = inqbuf.additional_length - + ((char *) inqbuf.unused - - (char *) &inqbuf)) + if ((inqbuf->version & SID_ANSII) > 0) { + if ((len = inqbuf->additional_length + + ((char *) inqbuf->unused + - (char *) inqbuf)) > (sizeof(struct scsi_inquiry_data) - 1)) len = sizeof(struct scsi_inquiry_data) - 1; - desc = inqbuf.vendor; - desc[len - (desc - (char *) &inqbuf)] = 0; - strncpy(manu, inqbuf.vendor, 8); - strncpy(model, inqbuf.product, 16); - strncpy(version, inqbuf.revision, 4); + desc = inqbuf->vendor; + desc[len - (desc - (char *) inqbuf)] = 0; + strncpy(manu, inqbuf->vendor, 8); + strncpy(model, inqbuf->product, 16); + strncpy(version, inqbuf->revision, 4); for(z = 0; z < 4; z++) { if (version[z]<' ') version[z]='?'; } @@ -770,7 +786,7 @@ scsi_probedev(sc_link, maybe_more) ,type ,dtype ,remov ? "removable" : "fixed" - ,inqbuf.version & SID_ANSII + ,inqbuf->version & SID_ANSII ); printf("%s%d targ %d lun %d: <%s%s%s>\n" ,scsi_adapter->name @@ -803,6 +819,26 @@ scsi_probedev(sc_link, maybe_more) return (bestmatch); } +/* Try to find the major number for a device during attach. + */ +dev_t +scsi_dev_lookup(d_open) + int (*d_open)(); +{ + int i; + + dev_t d = NODEV; + + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == d_open) + { + d = makedev(i, 0); + break; + } + + return d; +} + #ifdef NEW_SCSICONF /* * Compare name with pattern, return 0 on match. diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index eb3c3c4..7744387 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 * - * $Id: scsiconf.h,v 1.13 1994/10/23 21:27:56 wollman Exp $ + * $Id: scsiconf.h,v 1.14 1994/11/14 23:39:33 ats Exp $ */ #ifndef SCSI_SCSICONF_H #define SCSI_SCSICONF_H 1 @@ -28,6 +28,47 @@ typedef unsigned short int u_int16; typedef unsigned char u_int8; #include <scsi/scsi_debug.h> +#include <scsi/scsi_all.h> + +/* Minor number fields: + * + * OLD STYLE SCSI devices: + * + * ???? ???? ???? ???N MMMMMMMM mmmmmmmm + * + * ?: Don't know; those bits didn't use to exist, currently always 0. + * N: New style device: must be zero. + * M: Major device number. + * m: old style minor device number. + * + * NEW (FIXED) SCSI devices: + * + * ???? SBBB LLLI IIIN MMMMMMMM mmmmmmmm + * + * ?: Not used yet. + * S: "Super" device; reserved for things like resetting the SCSI bus. + * B: Scsi bus + * L: Logical unit + * I: Scsi target (XXX: Why 16? Why that many in scsiconf.h?) + * N: New style device; must be one. + * M: Major device number + * m: Old style minor device number. + */ + +#define SCSI_SUPER(DEV) (((DEV) & 0x08000000) >> 27) +#define SCSI_MKSUPER(DEV) ((DEV) | 0x08000000) + +#define SCSI_BUS(DEV) (((DEV) & 0x07000000) >> 24) +#define SCSI_LUN(DEV) (((DEV) & 0x00E00000) >> 21) +#define SCSI_ID(DEV) (((DEV) & 0x001E0000) >> 17) +#define SCSI_NEW(DEV) (((DEV) & 0x00010000) >> 16) + + +#define SCSI_MKDEV(B, L, I) ( \ + ((B) << 24) | \ + ((L) << 21) | \ + ((I) << 17) | \ + ( 1 << 16) ) /* * The following documentation tries to describe the relationship between the @@ -85,6 +126,14 @@ struct scsi_adapter #define ESCAPE_NOT_SUPPORTED 4 /* + * Return value from sense handler. IMHO, These ought to be merged + * in with the return codes above, all made negative to distinguish + * from valid errno values, and replace "try again later" with "do retry" + */ +#define SCSIRET_CONTINUE -1 /* Continue with standard sense processing */ +#define SCSIRET_DO_RETRY -2 /* Retry the command that got this sense */ + +/* * Format of adapter_info() response data * e.g. maximum number of entries queuable to a device by the adapter */ @@ -172,6 +221,8 @@ struct scsi_link /* 24*/ struct scsi_xfer *active_xs; /* operations under way */ /* 28*/ void * fordriver; /* for private use by the driver */ /* 32*/ void * devmodes; /* device specific mode tables */ +/* 36*/ dev_t dev; /* Device major number (character) */ +/* 40+*/struct scsi_inquiry_data inqbuf; /* Inquiry data */ }; #define SDEV_MEDIA_LOADED 0x01 /* device figures are still valid */ #define SDEV_WAITING 0x02 /* a process is waiting for this */ @@ -259,6 +310,7 @@ struct scsi_xfer #define XS_TIMEOUT 0x03 /* The device timed out.. turned off? */ #define XS_SWTIMEOUT 0x04 /* The Timeout reported was caught by SW */ #define XS_BUSY 0x08 /* The device busy, try again later? */ +#define XS_LENGTH 0x09 /* Illegal length (over/under run) */ #ifdef KERNEL void scsi_attachdevs __P((struct scsi_link *sc_link_proto)); @@ -277,8 +329,15 @@ errval scsi_scsi_cmd( struct scsi_link *sc_link, struct scsi_generic *scsi_cmd, u_int32 datalen, u_int32 retries, u_int32 timeout, struct buf *bp, u_int32 flags); -errval scsi_do_ioctl __P((struct scsi_link *sc_link, int cmd, caddr_t addr, int f)); +errval scsi_do_ioctl __P((dev_t dev, struct scsi_link *sc_link, int cmd, caddr_t addr, int f)); + +struct scsi_link *scsi_link_get __P((int bus, int targ, int lun)); +dev_t scsi_dev_lookup __P((int (*opener)(dev_t dev))); + +int scsi_opened_ok __P((dev_t dev, int flag, int type, struct scsi_link *sc_link)); + +void scsi_sense_print(struct scsi_xfer *xs); void show_scsi_xs(struct scsi_xfer *xs); void show_scsi_cmd(struct scsi_xfer *xs); void show_mem(unsigned char * , u_int32); @@ -359,5 +418,47 @@ extern struct kern_devconf kdc_scbus0; /* XXX should go away */ #define DAT_1 0x13 #endif /* NEW_SCSICONF */ +/* Macros for getting and setting the unit numbers in the original + * (not fixed device name) device numbers. + */ +#define SH0_UNIT(DEV) (minor(DEV)&0xFF) /* 8 bit unit */ +#define SH0SETUNIT(DEV, U) makedev(major(DEV), (U)) + +#define SH3_UNIT(DEV) ((minor(DEV)&0xF8) >> 3) /* 5 bit unit */ +#define SH3SETUNIT(DEV, U) makedev(major(DEV), ((U) << 3)) + +#define SH4_UNIT(DEV) ((minor(DEV)&0xF0) >> 4) /* 4 bit unit. */ +#define SH4SETUNIT(DEV, U) makedev(major(DEV), ((U) << 4)) + +#define CDUNITSHIFT 3 +#define CDUNIT(DEV) SH3_UNIT(DEV) +#define CDSETUNIT(DEV, U) SH3SETUNIT((DEV), (U)) + +#define SDUNITSHIFT 3 +#define SDUNIT(DEV) SH3_UNIT(DEV) +#define SDSETUNIT(DEV, U) SH3SETUNIT((DEV), (U)) + +#define CHUNIT(DEV) SH4_UNIT(DEV) +#define CHSETUNIT(DEV, U) SH4SETUNIT((DEV), (U)) + +#define STUNIT(DEV) SH4_UNIT(DEV) +#define STSETUNIT(DEV, U) SH4SETUNIT((DEV), (U)) + +#define UKUNIT(DEV) SH0_UNIT(DEV) +#define UKSETUNIT(DEV, U) SH0SETUNIT((DEV), (U)) + +/* Build an old style device number (unit encoded in the minor number) + * from a base old one (no flag bits) and a full new one + * (BUS, LUN, TARG in the minor number, and flag bits). + * + * OLDDEV has the major number and device unit only. It was constructed + * at attach time and is stored in the scsi_link structure. + * + * NEWDEV can have whatever in it, but only the old control flags and the + * super bit are present. IT CAN'T HAVE ANY UNIT INFORMATION or you'll + * wind up with the wrong unit. + */ +#define OLD_DEV(NEWDEV, OLDDEV) ((OLDDEV) | ((NEWDEV) & 0x080000FF)) + #endif /*SCSI_SCSICONF_H*/ /* END OF FILE */ diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index 11a9db1..a448169 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -14,7 +14,7 @@ * * Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992 * - * $Id: sd.c,v 1.47 1994/12/23 23:03:32 davidg Exp $ + * $Id: sd.c,v 1.48 1994/12/24 09:19:00 bde Exp $ */ #define SPLSD splbio @@ -52,21 +52,22 @@ u_int32 sdstrats, sdqueues; #define SD_RETRIES 4 #define MAXTRANSFER 8 /* 1 page at a time */ -#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<3)+part))) -#define UNITSHIFT 3 + +#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<<SDUNITSHIFT)+part))) #define PARTITION(z) (minor(z) & 0x07) -#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) -#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAWPART ) +#define WHOLE_DISK(unit) ( (unit << SDUNITSHIFT) + RAWPART ) errval sdgetdisklabel __P((unsigned char unit)); errval sd_get_parms __P((int unit, int flags)); void sdstrategy __P((struct buf *)); void sdstart __P((u_int32)); +int sd_sense_handler __P((struct scsi_xfer *)); + struct scsi_device sd_switch = { - NULL, /* Use default error handler */ + sd_sense_handler, sdstart, /* have a queue, served by this */ NULL, /* have no async handler */ NULL, /* Use default 'done' routine */ @@ -162,6 +163,8 @@ sd_registerdev(int unit) } +errval sdopen(); + /* * The routine called by the low level scsi routine when it discovers * a device suitable for this driver. @@ -230,6 +233,7 @@ sdattach(sc_link) sd->sc_link = sc_link; sc_link->device = &sd_switch; sc_link->dev_unit = unit; + sc_link->dev = SDSETUNIT(scsi_dev_lookup(sdopen), unit); if (sd->sc_link->adapter->adapter_info) { sd->ad_info = ((*(sd->sc_link->adapter->adapter_info)) (sc_link->adapter_unit)); @@ -279,7 +283,7 @@ sdopen(dev) struct sd_data *sd; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = SDUNIT(dev); part = PARTITION(dev); /* * Check the unit is legal @@ -385,6 +389,7 @@ sdopen(dev) sd->partflags[part] |= SDOPEN; sd->openparts |= (1 << part); SC_DEBUG(sc_link, SDEV_DB3, ("open %d %d\n", sdstrats, sdqueues)); + return 0; bad: @@ -406,7 +411,7 @@ sdclose(dev) unsigned char unit, part; struct sd_data *sd; - unit = UNIT(dev); + unit = SDUNIT(dev); part = PARTITION(dev); sd = sd_driver.sd_data[unit]; sd->partflags[part] &= ~SDOPEN; @@ -428,7 +433,7 @@ void sdminphys(bp) struct buf *bp; { - (*(sd_driver.sd_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); + (*(sd_driver.sd_data[SDUNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } /* @@ -446,7 +451,7 @@ sdstrategy(bp) u_int32 unit; sdstrats++; - unit = UNIT((bp->b_dev)); + unit = SDUNIT((bp->b_dev)); sd = sd_driver.sd_data[unit]; SC_DEBUG(sd->sc_link, SDEV_DB2, ("sdstrategy ")); SC_DEBUG(sd->sc_link, SDEV_DB1, @@ -676,7 +681,7 @@ sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) /* * Find the device that the user is talking about */ - unit = UNIT(dev); + unit = SDUNIT(dev); part = PARTITION(dev); sd = sd_driver.sd_data[unit]; SC_DEBUG(sd->sc_link, SDEV_DB1, ("sdioctl (0x%x)", cmd)); @@ -772,8 +777,8 @@ sdioctl(dev_t dev, int cmd, caddr_t addr, int flag) break; default: - if (part == RAWPART) - error = scsi_do_ioctl(sd->sc_link, cmd, addr, flag); + if (part == RAWPART || SCSI_SUPER(dev) ) + error = scsi_do_ioctl(dev, sd->sc_link, cmd, addr, flag); else error = ENOTTY; break; @@ -791,7 +796,7 @@ sdgetdisklabel(unsigned char unit) struct sd_data *sd = sd_driver.sd_data[unit]; dev_t dev; - dev = makedev(0, (unit << UNITSHIFT) + RAWPART); + dev = makedev(0, (unit << SDUNITSHIFT) + RAWPART); /* * If the inflo is already loaded, use it */ @@ -825,7 +830,7 @@ sdgetdisklabel(unsigned char unit) /* we need to pretend this disklabel */ /* is real before we can read */ /* real disklabel */ - errstring = readdisklabel(makedev(0, (unit << UNITSHIFT) + RAWPART), + errstring = readdisklabel(makedev(0, (unit << SDUNITSHIFT) + RAWPART), sdstrategy, &sd->disklabel #ifdef NetBSD @@ -1024,7 +1029,7 @@ sd_get_parms(unit, flags) int sdsize(dev_t dev) { - u_int32 unit = UNIT(dev), part = PARTITION(dev), val; + u_int32 unit = SDUNIT(dev), part = PARTITION(dev), val; struct sd_data *sd; if (unit >= sd_driver.size) @@ -1047,6 +1052,56 @@ sdsize(dev_t dev) } /* + * sense handler: Called to determine what to do when the + * device returns a CHECK CONDITION. + * + * This will issue a retry when the device returns a + * non-media hardware failure. The CDC-WREN IV does this + * when you access it during thermal calibrarion, so the drive + * is pretty useless without this. + * + * In general, you probably almost always would like to issue a retry + * for your disk I/O. It can't hurt too much (the caller only retries + * so many times) and it may save your butt. + */ + +int sd_sense_handler(struct scsi_xfer *xs) +{ + struct scsi_sense_data *sense; + struct scsi_inquiry_data *inqbuf; + + sense = &(xs->sense); + + /* I don't know what the heck to do with a deferred error, + * so I'll just kick it back to the caller. + */ + if ((sense->error_code & SSD_ERRCODE) == 0x71) + return SCSIRET_CONTINUE; + + inqbuf = &(xs->sc_link->inqbuf); + + /* It is dangerous to retry on removable drives without + * looking carefully at the additional sense code + * and sense code qualifier and ensuring the disk hasn't changed: + */ + if (inqbuf->dev_qual2 & SID_REMOVABLE) + return SCSIRET_CONTINUE; + + /* I have to retry HARDWARE ERROR for ASC 44 and ASCQ 0 + * so that the CDC-WREN IV will work during TCAL. In general, + * I think we should just retry disk errors. Does anyone + * have a good reason not to? + */ + scsi_sense_print(xs); + if (xs->retries) + printf(", retries:%d\n", xs->retries); + else + printf(", FAILURE\n"); + + return SCSIRET_DO_RETRY; +} + +/* * dump all of physical memory into the partition specified, starting * at offset 'dumplo' into the partition. */ @@ -1076,7 +1131,7 @@ sddump(dev_t dev) /* size of memory to dump */ num = Maxmem; - unit = UNIT(dev); /* eventually support floppies? */ + unit = SDUNIT(dev); /* eventually support floppies? */ part = PARTITION(dev); /* file system */ /* check for acceptable drive number */ if (unit >= sd_driver.size) diff --git a/sys/scsi/ssc.c b/sys/scsi/ssc.c new file mode 100644 index 0000000..5dc2630 --- /dev/null +++ b/sys/scsi/ssc.c @@ -0,0 +1,82 @@ +/* "superscsi" pseudo device. This requires options SCSISUPER. + * "superscsi" supports general SCSI utilities that can iterate + * over all SCSI targets, including those without device entry + * points. + * + * "superscsi" supports the SCIOCADDR ioctl to change the BUS, ID, LUN + * of the target so that you can get to all devices. The only thing + * you can do to "superscsi" is open it, set the target, perform ioctl + * calls, and close it. + * + * Keep "superscsi" protected: you can drive a truck through the + * security hole if you don't. + * + */ + +#include <sys/types.h> +#include <sys/conf.h> +#include <scsi/scsiconf.h> +#include <sys/scsiio.h> + +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/systm.h> + +static dev_t sscdev = NODEV; + +int sscopen(dev_t dev, int flag, int type, struct proc *p) +{ + if (sscdev != NODEV) + return suopen(sscdev, flag, type, p); + return 0; +} + +int sscclose(dev_t dev, int fflag, int type, struct proc *p) +{ + + if (sscdev != NODEV) + return suclose(sscdev, fflag, type, p); + return 0; +} + +int sscioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p) +{ + if (cmd == SCIOCADDR) + { + struct scsi_addr *sca = (struct scsi_addr *) data; + dev_t newdev = + SCSI_MKSUPER(SCSI_MKDEV(sca->scbus,sca->lun,sca->target)); + int ret; + + if (sscdev != NODEV) + { + suclose(sscdev, fflag, S_IFCHR, p); + sscdev = NODEV; + } + + if ( (ret = suopen(newdev, fflag, S_IFCHR, p)) ) + return ret; + + sscdev = newdev; + + return 0; + } + + if (sscdev != NODEV) + return suioctl(sscdev, cmd, data, fflag, p); + + return ENXIO; +} + +/* I've elected not to support any of these other entries. There + * really is no good reason other than I'm not sure how you would use + * them. + */ +int sscstrategy(struct buf *bp) { return ENXIO; } +int sscdump(dev_t dev) { return ENXIO; } +int sscpsize(dev_t dev) { return ENXIO; } +int sscread(dev_t dev, struct uio *uio, int ioflag) { return ENXIO; } +int sscwrite(dev_t dev, struct uio *uio, int ioflag) { return ENXIO; } +int sscselect(dev_t dev, int which, struct proc *p) { return ENXIO; } diff --git a/sys/scsi/st.c b/sys/scsi/st.c index b15c0aa..5dba78e 100644 --- a/sys/scsi/st.c +++ b/sys/scsi/st.c @@ -12,7 +12,7 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: st.c,v 1.22 1994/10/28 13:19:36 jkh Exp $ + * $Id: st.c,v 1.23 1994/12/16 06:03:26 phk Exp $ */ /* @@ -56,9 +56,10 @@ u_int32 ststrats, stqueues; #define MODE(z) ( (minor(z) & 0x03) ) #define DSTY(z) ( ((minor(z) >> 2) & 0x03) ) -#define UNIT(z) ( (minor(z) >> 4) ) #define CTLMODE 3 +#define IS_CTLMODE(DEV) (MODE(DEV) == CTLMODE || SCSI_SUPER(DEV)) + #define SCSI_2_MAX_DENSITY_CODE 0x17 /* maximum density code specified * in SCSI II spec. */ #ifndef NEW_SCSICONF @@ -299,6 +300,7 @@ st_registerdev(int unit) dev_attach(kdc); } +errval stopen(); /* * The routine called by the low level scsi routine when it discovers * A device suitable for this driver @@ -366,6 +368,7 @@ stattach(sc_link) st->sc_link = sc_link; sc_link->device = &st_switch; sc_link->dev_unit = unit; + sc_link->dev = STSETUNIT(scsi_dev_lookup(stopen), unit); /* * Check if the drive is a known criminal and take @@ -416,23 +419,23 @@ st_identify_drive(unit) u_int32 unit; { struct st_data *st = st_driver.st_data[unit]; - struct scsi_inquiry_data inqbuf; struct rogues *finger; char manu[32]; char model[32]; char model2[32]; char version[32]; u_int32 model_len; + struct scsi_inquiry_data *inqbuf = &st->sc_link->inqbuf; /* * Get the device type information */ - if (scsi_inquire(st->sc_link, &inqbuf, + if (scsi_inquire(st->sc_link, inqbuf, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT) != 0) { printf("st%d: couldn't get device type, using default\n", unit); return; } - if ((inqbuf.version & SID_ANSII) == 0) { + if ((inqbuf->version & SID_ANSII) == 0) { /* * If not advanced enough, use default values */ @@ -443,11 +446,11 @@ st_identify_drive(unit) strncpy(version, "????", 4); version[4] = 0; } else { - strncpy(manu, inqbuf.vendor, 8); + strncpy(manu, inqbuf->vendor, 8); manu[8] = 0; - strncpy(model, inqbuf.product, 16); + strncpy(model, inqbuf->product, 16); model[16] = 0; - strncpy(version, inqbuf.revision, 4); + strncpy(version, inqbuf->revision, 4); version[4] = 0; } @@ -551,7 +554,7 @@ stopen(dev, flags) errval errno = 0; struct st_data *st; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = STUNIT(dev); mode = MODE(dev); dsty = DSTY(dev); @@ -588,9 +591,10 @@ stopen(dev, flags) /* * If the mode is 3 (e.g. minor = 3,7,11,15) * then the device has been openned to set defaults - * This mode does NOT ALLOW I/O, only ioctls + * This mode does NOT ALLOW I/O, only ioctls. + * XXX: Where do we lock out I/O? */ - if (mode == CTLMODE) + if (IS_CTLMODE(dev)) return 0; /* @@ -630,7 +634,7 @@ stopen(dev, flags) SC_DEBUG(sc_link, SDEV_DB2, ("Open complete\n")); st->flags |= ST_OPEN; - return (0); + return 0; } /* @@ -645,7 +649,7 @@ stclose(dev) struct st_data *st; struct scsi_link *sc_link; - unit = UNIT(dev); + unit = STUNIT(dev); mode = MODE(dev); st = st_driver.st_data[unit]; sc_link = st->sc_link; @@ -687,7 +691,7 @@ st_mount_tape(dev, flags) struct scsi_link *sc_link; errval errno = 0; - unit = UNIT(dev); + unit = STUNIT(dev); mode = MODE(dev); dsty = DSTY(dev); st = st_driver.st_data[unit]; @@ -949,7 +953,7 @@ void stminphys(bp) struct buf *bp; { - (*(st_driver.st_data[UNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); + (*(st_driver.st_data[STUNIT(bp->b_dev)]->sc_link->adapter->scsi_minphys)) (bp); } /* @@ -968,7 +972,7 @@ ststrategy(bp) struct st_data *st; ststrats++; - unit = UNIT((bp->b_dev)); + unit = STUNIT((bp->b_dev)); st = st_driver.st_data[unit]; SC_DEBUG(st->sc_link, SDEV_DB1, (" strategy: %d bytes @ blk%d\n", bp->b_bcount, bp->b_blkno)); @@ -1203,7 +1207,7 @@ stioctl(dev, cmd, arg, flag) * Find the device that the user is talking about */ flags = 0; /* give error messages, act on errors etc. */ - unit = UNIT(dev); + unit = STUNIT(dev); dsty = DSTY(dev); st = st_driver.st_data[unit]; hold_blksiz = st->blksiz; @@ -1310,8 +1314,8 @@ stioctl(dev, cmd, arg, flag) case MTIOCEEOT: break; default: - if(MODE(dev) == CTLMODE) - errcode = scsi_do_ioctl(st->sc_link,cmd,arg,flag); + if(IS_CTLMODE(dev)) + errcode = scsi_do_ioctl(dev, st->sc_link,cmd,arg,flag); else errcode = ENOTTY; break; @@ -1340,7 +1344,7 @@ try_new_value: * * The means for deciding this are not finalised yet */ - if (MODE(dev) == 0x03) { + if (IS_CTLMODE(dev)) { /* special mode */ /* XXX */ switch ((short) (mt->mt_op)) { @@ -1879,7 +1883,7 @@ st_erase(unit, immed, flags) /* * Look at the returned sense and act on the error and detirmine * The unix error number to pass back... (0 = report no error) - * (-1 = continue processing) + * (SCSIRET_CONTINUE = continue processing) */ errval st_interpret_sense(xs) @@ -1903,7 +1907,7 @@ st_interpret_sense(xs) info = xs->datalen; /* bad choice if fixed blocks */ } if ((sense->error_code & SSD_ERRCODE) != 0x70) { - return (-1); /* let the generic code handle it */ + return SCSIRET_CONTINUE; /* let the generic code handle it */ } if (st->flags & ST_FIXEDBLOCKS) { xs->resid = info * st->blksiz; @@ -2010,7 +2014,7 @@ st_interpret_sense(xs) return (ESUCCESS); } } - return (-1); /* let the default/generic handler handle it */ + return SCSIRET_CONTINUE; /* let the default/generic handler handle it */ } /* diff --git a/sys/scsi/su.c b/sys/scsi/su.c index de4f017..84bd6fb 100644 --- a/sys/scsi/su.c +++ b/sys/scsi/su.c @@ -1,4 +1,271 @@ +/* su: SCSI Universal. This is a universal SCSI device that + * has a fixed minor number format. This allows you to refer + * to your devices by BUS, ID, LUN instead of st0, st1, ... + * + * This code looks up the underlying device for a given SCSI + * target and uses that driver. + * + *Begin copyright + * + * Copyright (C) 1993, 1994, 1995, HD Associates, Inc. + * PO Box 276 + * Pepperell, MA 01463 + * 508 433 5266 + * dufault@hda.com + * + * This code is contributed to the University of California at Berkeley: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + *End copyright + * + * Tabstops 4 + */ -/* this will be a special user scsi device */ -/* not written yet */ +#include <sys/types.h> +#include <sys/conf.h> +#include <scsi/scsiconf.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/buf.h> +#include <sys/systm.h> +/* bnxio, cnxio: non existent device entries (with ugly casts to quiet gcc). + */ +static struct bdevsw bnxio = { + (int (*) __P((dev_t dev, int oflags, int devtype, + struct proc *p))) enxio, + (int (*) __P((dev_t dev, int fflag, int devtype, + struct proc *p))) enxio, + (d_strategy_t *) enxio, + (int (*) __P((dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p))) enxio, + (int (*) ()) enxio, + (int (*) __P((dev_t dev))) 0, + (int ) 0 +}; + +static struct cdevsw cnxio = { + (int (*) __P((dev_t dev, int oflags, int devtype, + struct proc *p))) enxio, + (int (*) __P((dev_t dev, int fflag, int devtype, + struct proc *))) enxio, + (int (*) __P((dev_t dev, struct uio *uio, int ioflag))) enxio, + (int (*) __P((dev_t dev, struct uio *uio, int ioflag))) enxio, + (int (*) __P((dev_t dev, int cmd, caddr_t data, + int fflag, struct proc *p))) enxio, + (int (*) __P((struct tty *tp, int rw))) nullop, + (int (*) __P((int uban))) enxio, + (struct tty *) 0, + (int (*) __P((dev_t dev, int which, struct proc *p))) enxio, + (int (*) __P(())) enxio, + (d_strategy_t *) enxio +}; + +/* getsws: Look up the base dev switch for a given new style + * device. + */ +static int +getsws(dev_t dev, int type, + struct bdevsw **bdevp, struct cdevsw **cdevp, dev_t *base) +{ + int ret = 0; + struct scsi_link *scsi_link; + int chr_dev, blk_dev; + + struct cdevsw *cdev; + struct bdevsw *bdev; + + int bus = SCSI_BUS(dev), + lun = SCSI_LUN(dev), + id = SCSI_ID(dev); + + /* Try to look up the base device by finding the major number in + * the scsi_link structure: + */ + if ((scsi_link = scsi_link_get(bus, id, lun)) == 0 || + scsi_link->dev == NODEV) + { + ret = ENXIO; + + /* XXX This assumes that you always have a character device if you + * have a block device. That seems reasonable. + */ + cdev = &cnxio; + chr_dev = NODEV; + bdev = &bnxio; + blk_dev = NODEV; + } + else + { + int bmaj, cmaj; + + cmaj = major(scsi_link->dev); + cdev = cdevsw + cmaj; + chr_dev = OLD_DEV(dev, scsi_link->dev); + + bmaj = chrtoblk(cmaj); + bdev = (bmaj == NODEV) ? &bnxio : bdevsw + bmaj; + blk_dev = OLD_DEV(dev, makedev(bmaj, minor(scsi_link->dev))); + } + + if (cdevp) + *cdevp = cdev; + if (bdevp) + *bdevp = bdev; + + if (type == S_IFCHR) + *base = chr_dev; + else + *base = blk_dev; + + return ret; +} + +int +suopen(dev_t dev, int flag, int type, struct proc *p) +{ + struct cdevsw *cdev; + struct bdevsw *bdev; + dev_t base; + + if (getsws(dev, type, &bdev, &cdev, &base)) + { + /* Device not configured? Reprobe then try again. + */ + int bus = SCSI_BUS(dev), lun = SCSI_LUN(dev), id = SCSI_ID(dev); + + if (scsi_probe_bus(bus, id, lun) || getsws(dev, type, &bdev, &cdev, + &base)) + return ENXIO; + } + + /* There is a properly configured underlying device. + * Synthesize an appropriate device number: + */ + if (type == S_IFCHR) + return (*cdev->d_open)(base, flag, S_IFCHR, p); + else + return (*bdev->d_open)(base, flag, S_IFBLK, p); +} + +int suclose(dev_t dev, int fflag, int type, struct proc *p) +{ + struct cdevsw *cdev; + struct bdevsw *bdev; + dev_t base; + + (void)getsws(dev, type, &bdev, &cdev, &base); + + if (type == S_IFCHR) + return (*cdev->d_close)(base, fflag, S_IFCHR, p); + else + return (*bdev->d_open)(base, fflag, S_IFBLK, p); +} + +void sustrategy(struct buf *bp) +{ + dev_t base; + struct bdevsw *bdev; + dev_t dev = bp->b_dev; + + /* XXX: I have no way of knowing if this was through the + * block or the character entry point. + */ + (void)getsws(dev, S_IFBLK, &bdev, 0, &base); + + bp->b_dev = base; + + (*bdev->d_strategy)(bp); + + bp->b_dev = dev; +} + +int suioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p) +{ + struct cdevsw *cdev; + dev_t base; + + /* XXX: I have no way of knowing if this was through the + * block or the character entry point. + */ + (void)getsws(dev, S_IFCHR, 0, &cdev, &base); + + return (*cdev->d_ioctl)(base, cmd, data, fflag, p); +} + +int sudump(dev_t dev) +{ + dev_t base; + struct bdevsw *bdev; + + (void)getsws(dev, S_IFBLK, &bdev, 0, &base); + + return (*bdev->d_dump)(base); +} + +int supsize(dev_t dev) +{ + dev_t base; + struct bdevsw *bdev; + + (void)getsws(dev, S_IFBLK, &bdev, 0, &base); + + return (*bdev->d_psize)(base); +} + +int suread(dev_t dev, struct uio *uio, int ioflag) +{ + dev_t base; + struct cdevsw *cdev; + + (void)getsws(dev, S_IFCHR, 0, &cdev, &base); + + return (*cdev->d_read)(base, uio, ioflag); +} + +int suwrite(dev_t dev, struct uio *uio, int ioflag) +{ + dev_t base; + struct cdevsw *cdev; + + (void)getsws(dev, S_IFCHR, 0, &cdev, &base); + + return (*cdev->d_write)(base, uio, ioflag); +} + +int suselect(dev_t dev, int which, struct proc *p) +{ + dev_t base; + struct cdevsw *cdev; + + (void)getsws(dev, S_IFCHR, 0, &cdev, &base); + + return (*cdev->d_select)(base, which, p); +} diff --git a/sys/scsi/uk.c b/sys/scsi/uk.c index f09fbbf..7544d1e 100644 --- a/sys/scsi/uk.c +++ b/sys/scsi/uk.c @@ -2,7 +2,7 @@ * Dummy driver for a device we can't identify. * by Julian Elischer (julian@tfs.com) * - * $Id: uk.c,v 1.4 1994/08/13 03:50:31 wollman Exp $ + * $Id: uk.c,v 1.5 1994/12/16 06:03:28 phk Exp $ */ #include <sys/param.h> @@ -40,6 +40,7 @@ struct uk_driver { static u_int32 next_uk_unit = 0; +errval ukopen(); /* * The routine called by the low level scsi routine when it discovers * a device suitable for this driver. @@ -107,6 +108,7 @@ ukattach(sc_link) uk->sc_link = sc_link; sc_link->device = &uk_switch; sc_link->dev_unit = unit; + sc_link->dev = UKSETUNIT(scsi_dev_lookup(ukopen), unit); printf("uk%d: unknown device\n", unit); uk->flags = UK_KNOWN; @@ -125,7 +127,7 @@ ukopen(dev) u_int32 unit, mode; struct uk_data *uk; struct scsi_link *sc_link; - unit = minor(dev); + unit = UKUNIT(dev); /* * Check the unit is legal @@ -200,9 +202,9 @@ ukioctl(dev, cmd, arg, mode) /* * Find the device that the user is talking about */ - unit = minor(dev); + unit = UKUNIT(dev); uk = uk_driver.uk_data[unit]; sc_link = uk->sc_link; - return(scsi_do_ioctl(sc_link,cmd,arg,mode)); + return(scsi_do_ioctl(dev,sc_link,cmd,arg,mode)); } |