1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1995-03-01 22:24:47 +00:00
|
|
|
* 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.
|
|
|
|
*
|
1997-06-25 19:07:43 +00:00
|
|
|
* $Id: scsi_driver.c,v 1.23 1997/03/23 06:33:47 bde Exp $
|
1995-03-01 22:24:47 +00:00
|
|
|
*
|
|
|
|
*/
|
1996-07-14 10:46:56 +00:00
|
|
|
|
|
|
|
#include "opt_scsi.h"
|
|
|
|
|
1995-03-01 22:24:47 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/param.h>
|
1995-03-16 18:17:34 +00:00
|
|
|
#include <sys/systm.h>
|
1995-03-01 22:24:47 +00:00
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/malloc.h>
|
1995-05-03 18:09:20 +00:00
|
|
|
#include <sys/fcntl.h>
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
#include <scsi/scsi_all.h>
|
|
|
|
#include <scsi/scsiconf.h>
|
1997-03-23 06:33:55 +00:00
|
|
|
#include <scsi/scsi_debug.h>
|
1995-03-01 22:24:47 +00:00
|
|
|
#include <scsi/scsi_driver.h>
|
|
|
|
|
|
|
|
#define GETUNIT(DEVICE, DEV) \
|
1995-12-05 07:14:27 +00:00
|
|
|
((DEVICE)->getunit) ? (*(DEVICE)->getunit)((DEV)) \
|
|
|
|
: (minor((DEV)) & ~SCSI_CONTROL_MASK)
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
int
|
1996-09-06 23:09:20 +00:00
|
|
|
scsi_goaway(int force) /* XXX should do a lot more */
|
1995-03-01 22:24:47 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1995-03-15 14:22:12 +00:00
|
|
|
/* 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".
|
|
|
|
*/
|
1995-03-01 22:24:47 +00:00
|
|
|
int scsi_device_attach(struct scsi_link *sc_link)
|
|
|
|
{
|
|
|
|
errval errcode;
|
|
|
|
dev_t dev;
|
|
|
|
struct scsi_device *device = sc_link->device;
|
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
if (bootverbose)
|
1995-03-21 11:21:08 +00:00
|
|
|
sc_link->flags |= SDEV_BOOTVERBOSE;
|
|
|
|
|
1995-03-01 22:24:47 +00:00
|
|
|
SC_DEBUG(sc_link, SDEV_DB2,
|
|
|
|
("%s%dattach: ", device->name, sc_link->dev_unit));
|
|
|
|
|
Make the SCSI probe messages more BSDish. This may raise a few eyebrows
("Hey! Who made _you_ the keeper of all things BSDish?!") but this has
bugged me for a long time, and now that I finally have the chance
to hack on it (and test the results), I'll take my chances. I can also
point to other BSD implementations for precedents if you put my back to
the wall.
The only thing that's changed is how the messages are formatted. Now,
instead of having this:
aha0 at 0x330-0x333 irq 11 drq 5 on isa
(aha0:3:0): "HP C1553A 9503" type 1 removable SCSI 2
st0(aha0:3:0): Sequential-Access density code 0x24, variable blocks, write-enabled
(aha0:3:1): "HP C1553A 9503" type 8 removable SCSI 2
ch0(aha0:3:1): Medium-Changer 6 slot(s) 1 drive(s) 0 arm(s) 0 i/e-slot(s)
We have this:
aha0 at 0x330-0x333 irq 11 drq 5 on isa
scbus0 at aha0 bus 0
st0 at scbus0 target 3 lun 0
st0: <HP C1553A 9503> type 1 removable SCSI 2
st0: Sequential-Access density code 0x24, variable blocks, write-enabled
ch0 at scbus0 target 3 lun 1
ch0: <HP C1553A 9503> type 8 removable SCSI 2
ch0: Medium-Changer 6 slot(s) 1 drive(s) 0 arm(s) 0 i/e-slot(s)
Which is (to me anyway) is a lot more pleasant to look at. (Call me
crazy -- g'head: you know you wanna -- but the previous messages remind
me of Linux. Ever see the output from the linux device probes? It's a mess
of copyright notices, version numbers/dates, author e-mail addresses and
other crap. Let's not go there, okay? Bleh.)
Notice that devices are now specified in terms of the scsi bus they
live on rather than the adapter. This better reflects the contents
of the kernel config file (if you use wired-down device specifications
anyway) and removes some ambiguity that may arise if you have a multi-
channel adapter with more than one bus.
Also, sc_print_addr() now generates messages like this:
st0 at scbus0 target 3 lun 0: NOT READY asc:3a,0 Medium not present
instead of this:
st0(aha0:3:0): NOT READY asc:3a,0 Medium not present
I also added a quirk entry for the HP Superstore 12000e 6 tape DAT
autoloader, which needs SC_MORE_LUS in order for the changer device
to be properly probed and attached. (I'm working on a chcontrol utility
to manipulate the changer on this drive which should hopefully be general
enough to work with other changers too. If you want the prototype I have
now, it's at ftp://skynet.ctr.columbia.edu/pub/freebsd/changer.c.)
Remaining bugs:
- The 'foodev0: yadda yadda yadda' bits should probably be printed entirely
by the device-specific subdriver attach code instead of half by the
scsi_device_attach() routine and half by the device specific attach
routine like it is now.
- The wired-down device specifications in the kernel config file should
be used to control bus/device probing to some extent rather than just
for choosing names for devices we find. If the config says there's a
device at scbus0 target 0 lun 0 called sd0, we should look there and
check for a device that can be managed by the sd driver. If we don't
find one, we should probably complain that there's no device there or
that there is a device but of the wrong type. Once all the devices from
the wired down list have been probed, the code can then autodetect and
autoattach any devices that remain unassigned.
- Apparently some tape changers (hi Ulf!) return 'not ready/medium not
present' when the magazine is loaded but a tape has not been put in the
drive yet. This causes an open(/dev/ch0) to fail and prevents you from
using the changer.c utility to load the first tape into the drive. My
HP changer does not behave this way. The workaround is to manually load
a tape into the drive before attempting to use the changer program, but
you can get in trouble if you accidentally eject a tape without loading
a new one and you're at a remote location: you won't be able to load
any tapes anymore. I'm not sure what the correct software solution is
for this but ideally there should be one.
- I should not be doing this: I'm the NIS guru, not the SCSI guru.
(This is not my beautiful code. How did I get here? My god: what
have I done?)
1997-01-25 20:27:13 +00:00
|
|
|
/* 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);
|
1997-02-08 03:42:22 +00:00
|
|
|
/*
|
|
|
|
* 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();
|
1995-03-04 20:51:10 +00:00
|
|
|
|
1995-03-01 22:24:47 +00:00
|
|
|
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) );
|
|
|
|
|
1995-03-04 20:51:10 +00:00
|
|
|
errcode = (device->attach) ? (*(device->attach))(sc_link) : 0;
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-03-15 14:22:12 +00:00
|
|
|
printf("\n");
|
1997-02-08 03:42:22 +00:00
|
|
|
sc_print_finish();
|
1995-03-15 14:22:12 +00:00
|
|
|
|
1995-03-01 22:24:47 +00:00
|
|
|
if (errcode == 0)
|
|
|
|
sc_link->flags |= device->link_flags;
|
|
|
|
|
|
|
|
return errcode;
|
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
int
|
1995-03-04 20:51:10 +00:00
|
|
|
scsi_open(dev_t dev, int flags, int fmt, struct proc *p,
|
|
|
|
struct scsi_device *device)
|
1995-03-01 22:24:47 +00:00
|
|
|
{
|
|
|
|
errval errcode;
|
1996-03-10 07:13:15 +00:00
|
|
|
u_int32_t unit;
|
1995-03-01 22:24:47 +00:00
|
|
|
struct scsi_link *sc_link;
|
|
|
|
|
1995-03-03 21:38:43 +00:00
|
|
|
if (device == 0)
|
|
|
|
return ENXIO;
|
|
|
|
|
1995-03-01 22:24:47 +00:00
|
|
|
unit = GETUNIT(device, dev);
|
|
|
|
sc_link = SCSI_LINK(device, unit);
|
|
|
|
|
|
|
|
/*
|
1995-05-30 08:16:23 +00:00
|
|
|
* Check the unit is legal
|
1995-03-01 22:24:47 +00:00
|
|
|
*/
|
1996-01-20 15:05:55 +00:00
|
|
|
if (sc_link == 0 || (sc_link->sd == 0 && !(sc_link->flags & SDEV_UK)))
|
1995-03-01 22:24:47 +00:00
|
|
|
return ENXIO;
|
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
/* 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;
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
/* For the control device (user ioctl's only) don't call the open
|
|
|
|
* entry.
|
|
|
|
*/
|
|
|
|
if (SCSI_CONTROL(dev) || (device->dev_open == 0))
|
1996-06-16 19:54:02 +00:00
|
|
|
{
|
|
|
|
scsi_test_unit_ready(sc_link, SCSI_SILENT);
|
1995-05-03 18:09:20 +00:00
|
|
|
errcode = 0;
|
1996-06-16 19:54:02 +00:00
|
|
|
}
|
1995-05-03 18:09:20 +00:00
|
|
|
else
|
|
|
|
errcode = (*device->dev_open)(dev, flags, fmt, p, sc_link);
|
|
|
|
|
1995-12-05 04:41:20 +00:00
|
|
|
if (!errcode ) sc_link->flags |= SDEV_IS_OPEN;
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-04-14 15:10:44 +00:00
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("%sopen: dev=0x%lx (unit %ld) result %d\n",
|
1995-03-05 20:01:44 +00:00
|
|
|
device->name, dev, unit, errcode));
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
return errcode;
|
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
int
|
1995-03-04 20:51:10 +00:00
|
|
|
scsi_close(dev_t dev, int flags, int fmt, struct proc *p,
|
|
|
|
struct scsi_device *device)
|
1995-03-01 22:24:47 +00:00
|
|
|
{
|
|
|
|
errval errcode;
|
1995-05-03 18:09:20 +00:00
|
|
|
struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev));
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("%sclose: Closing device\n", device->name));
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
if (SCSI_CONTROL(dev) || (device->dev_close == 0))
|
|
|
|
errcode = 0;
|
|
|
|
else
|
|
|
|
errcode = (*device->dev_close)(dev, flags, fmt, p, sc_link);
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
sc_link->flags &= ~SDEV_IS_OPEN;
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
return errcode;
|
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
int
|
1996-03-10 07:13:15 +00:00
|
|
|
scsi_ioctl(dev_t dev, u_int32_t cmd, caddr_t arg, int flags, struct proc *p,
|
1995-03-01 22:24:47 +00:00
|
|
|
struct scsi_device *device)
|
|
|
|
{
|
|
|
|
errval errcode;
|
1995-05-03 18:09:20 +00:00
|
|
|
struct scsi_link *sc_link = SCSI_LINK(device, GETUNIT(device, dev));
|
1995-03-01 22:24:47 +00:00
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
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);
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
return errcode;
|
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
void
|
1995-03-01 22:24:47 +00:00
|
|
|
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)
|
|
|
|
{
|
1996-03-10 07:13:15 +00:00
|
|
|
u_int32_t unit = GETUNIT(device, bp->b_dev);
|
1995-03-05 20:01:44 +00:00
|
|
|
struct scsi_link *sc_link = SCSI_LINK(device, unit);
|
1995-03-01 22:24:47 +00:00
|
|
|
|
|
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("\n%sstrategy ", device->name));
|
1995-04-14 15:10:44 +00:00
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("%ld bytes @ blk%ld\n",
|
|
|
|
bp->b_bcount, bp->b_blkno));
|
|
|
|
|
1995-05-03 18:09:20 +00:00
|
|
|
if (SCSI_CONTROL(bp->b_dev) || (device->dev_strategy == 0))
|
1995-03-04 20:51:10 +00:00
|
|
|
{
|
1995-05-03 18:09:20 +00:00
|
|
|
bp->b_resid = bp->b_bcount;
|
|
|
|
bp->b_error = EIO;
|
|
|
|
bp->b_flags |= B_ERROR;
|
1995-03-04 20:51:10 +00:00
|
|
|
biodone(bp);
|
|
|
|
}
|
1995-05-03 18:09:20 +00:00
|
|
|
else
|
1995-03-01 22:24:47 +00:00
|
|
|
{
|
1995-05-03 18:09:20 +00:00
|
|
|
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);
|
|
|
|
}
|
1995-03-01 22:24:47 +00:00
|
|
|
}
|
|
|
|
}
|
1997-06-25 19:07:43 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|