/* * Copyright (C) 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. * * $Id: scsi_driver.c,v 1.23 1997/03/23 06:33:47 bde Exp $ * */ #include "opt_scsi.h" #include #include #include #include #include #include #include #include #include #include #include #define GETUNIT(DEVICE, DEV) \ ((DEVICE)->getunit) ? (*(DEVICE)->getunit)((DEV)) \ : (minor((DEV)) & ~SCSI_CONTROL_MASK) int scsi_goaway(int force) /* XXX should do a lot more */ { return 0; } /* scsi_device_attach: Attach a SCSI device. This routine will * print out the device address, what it is, then call the type * attach function and when that returns print a newline. If the * type attach will make LOT's of noise it should print a leading * newline and then the address using sc_print_addr. See "sd.c". */ int scsi_device_attach(struct scsi_link *sc_link) { errval errcode; dev_t dev; struct scsi_device *device = sc_link->device; if (bootverbose) sc_link->flags |= SDEV_BOOTVERBOSE; SC_DEBUG(sc_link, SDEV_DB2, ("%s%dattach: ", device->name, sc_link->dev_unit)); /* Print _sane_ probe info! */ printf("%s%d at scbus%d target %d lun %d\n", sc_link->device->name, sc_link->dev_unit, sc_link->scsibus, sc_link->target, sc_link->lun); #ifndef SCSIDEBUG scsi_print_info(sc_link); #endif printf("%s%d: %s ", device->name, sc_link->dev_unit, device->desc); /* * XXX some SCSI adapter drivers print out things while the * device-specific attach routine is running. The result is * something of a mess. This hack at least keeps it so each * line will begin with foodev0:. */ sc_print_init(); dev = scsi_dev_lookup(device->open); sc_link->dev = (device->setunit ? (*device->setunit)(dev, sc_link->dev_unit) : makedev(major(dev), sc_link->dev_unit) ); errcode = (device->attach) ? (*(device->attach))(sc_link) : 0; printf("\n"); sc_print_finish(); if (errcode == 0) sc_link->flags |= device->link_flags; return errcode; } int scsi_open(dev_t dev, int flags, int fmt, struct proc *p, struct scsi_device *device) { errval errcode; u_int32_t unit; struct scsi_link *sc_link; if (device == 0) return ENXIO; unit = GETUNIT(device, dev); sc_link = SCSI_LINK(device, unit); /* * Check the unit is legal */ if (sc_link == 0 || (sc_link->sd == 0 && !(sc_link->flags & SDEV_UK))) return ENXIO; /* If it is a "once only" device that is already open return EBUSY. */ if ((sc_link->flags & SDEV_ONCE_ONLY) && (sc_link->flags & SDEV_IS_OPEN)) return EBUSY; /* For the control device (user ioctl's only) don't call the open * entry. */ if (SCSI_CONTROL(dev) || (device->dev_open == 0)) { scsi_test_unit_ready(sc_link, SCSI_SILENT); errcode = 0; } else errcode = (*device->dev_open)(dev, flags, fmt, p, sc_link); if (!errcode ) sc_link->flags |= SDEV_IS_OPEN; SC_DEBUG(sc_link, SDEV_DB1, ("%sopen: dev=0x%lx (unit %ld) result %d\n", device->name, dev, unit, errcode)); return errcode; } int scsi_close(dev_t dev, int flags, int fmt, struct proc *p, struct scsi_device *device) { errval errcode; struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev)); SC_DEBUG(sc_link, SDEV_DB1, ("%sclose: Closing device\n", device->name)); if (SCSI_CONTROL(dev) || (device->dev_close == 0)) errcode = 0; else errcode = (*device->dev_close)(dev, flags, fmt, p, sc_link); sc_link->flags &= ~SDEV_IS_OPEN; return errcode; } int scsi_ioctl(dev_t dev, u_int32_t cmd, caddr_t arg, int flags, struct proc *p, struct scsi_device *device) { errval errcode; struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev)); if (SCSI_CONTROL(dev) || (device->dev_ioctl == 0)) errcode = scsi_do_ioctl(dev, cmd, arg, flags, p, sc_link); else errcode = (*device->dev_ioctl)(dev, cmd, arg, flags, p, sc_link); return errcode; } void scsi_minphys(struct buf *bp, struct scsi_device *device) { struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, bp->b_dev)); (*sc_link->adapter->scsi_minphys)(bp); } void scsi_strategy(struct buf *bp, struct scsi_device *device) { u_int32_t unit = GETUNIT(device, bp->b_dev); struct scsi_link *sc_link = SCSI_LINK(device, unit); SC_DEBUG(sc_link, SDEV_DB2, ("\n%sstrategy ", device->name)); SC_DEBUG(sc_link, SDEV_DB1, ("%ld bytes @ blk%ld\n", bp->b_bcount, bp->b_blkno)); if (SCSI_CONTROL(bp->b_dev) || (device->dev_strategy == 0)) { bp->b_resid = bp->b_bcount; bp->b_error = EIO; bp->b_flags |= B_ERROR; biodone(bp); } else { bp->b_resid = 0; bp->b_error = 0; if (bp->b_bcount == 0) biodone(bp); else { (*sc_link->adapter->scsi_minphys)(bp); (*device->dev_strategy)(bp, sc_link); } } } int scsi_device_lock(struct scsi_link *sc_link) { int error; while (sc_link->flags & SDEV_XLOCK) { sc_link->flags |= SDEV_WANT; error = tsleep(&sc_link->flags, PRIBIO | PCATCH, "sdevlk",0); if (error) return error; } sc_link->flags |= SDEV_XLOCK; return 0; } void scsi_device_unlock(struct scsi_link *sc_link) { sc_link->flags &= ~SDEV_XLOCK; if (sc_link->flags & SDEV_WANT) { sc_link->flags &= ~SDEV_WANT; wakeup(&sc_link->flags); } }