diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index f42b6df7bf69..a95f99f26c31 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 662038e567ff..b39de58af38d 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 @@ -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 ad05f0f5295b..fb921fda52f2 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 4e4b21f11fe9..4fae13bd9378 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)); } @@ -615,11 +627,125 @@ retry: return (-1); } +/* + * 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 44f2bd11cfc9..db694f48d05d 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 1228ec5c26b5..5e4253b32407 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: + * + * 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 $ * * - * $Id: scsi_ioctl.c,v 1.7 1994/08/02 07:52:33 davidg Exp $ + * Note: The SCSIUSER option is required to support the user defined + * ioctl calls. */ #include #include @@ -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 53c1cd145b25..275e77005242 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 #include #include +#include #include #include +#include #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 eb3c3c4eae93..7744387a1bbe 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 +#include + +/* 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 @@ -84,6 +125,14 @@ struct scsi_adapter #define HAD_ERROR 3 /* do not use this, use COMPLETE */ #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 11a9db1a2895..a448169c2deb 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 PARTITION(z) (minor(z) & 0x07) -#define UNIT(z) ( (minor(z) >> UNITSHIFT) ) -#define WHOLE_DISK(unit) ( (unit << UNITSHIFT) + RAWPART ) +#define MAKESDDEV(maj, unit, part) (makedev(maj,((unit<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) @@ -1046,6 +1051,56 @@ sdsize(dev_t dev) return (int)sd->disklabel.d_partitions[part].p_size; } +/* + * 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 000000000000..5dc26304ba40 --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include + +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 b15c0aa20502..5dba78e0dcfc 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 de4f0172dac3..84bd6fbae6e6 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 +#include +#include +#include +#include +#include +#include +#include +/* 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 f09fbbfe835f..7544d1e8810e 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 @@ -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)); }