1993-11-18 05:03:27 +00:00
|
|
|
/*
|
|
|
|
* Dummy driver for a device we can't identify.
|
|
|
|
* by Julian Elischer (julian@tfs.com)
|
|
|
|
*
|
1995-01-08 13:38:38 +00:00
|
|
|
* $Id: uk.c,v 1.5 1994/12/16 06:03:28 phk Exp $
|
1993-11-18 05:03:27 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
1994-08-13 03:50:34 +00:00
|
|
|
#include <sys/systm.h>
|
1993-11-18 05:03:27 +00:00
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/ioctl.h>
|
1994-12-16 06:03:28 +00:00
|
|
|
#include <sys/malloc.h>
|
1993-11-18 05:03:27 +00:00
|
|
|
#include <scsi/scsi_all.h>
|
|
|
|
#include <scsi/scsiconf.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This driver is so simple it uses all the default services
|
|
|
|
*/
|
|
|
|
struct scsi_device uk_switch =
|
|
|
|
{
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"uk",
|
|
|
|
0,
|
|
|
|
0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
struct uk_data {
|
|
|
|
u_int32 flags;
|
1994-12-16 06:03:28 +00:00
|
|
|
#define UK_KNOWN 0x02
|
1993-11-18 05:03:27 +00:00
|
|
|
struct scsi_link *sc_link; /* all the inter level info */
|
1994-12-16 06:03:28 +00:00
|
|
|
};
|
1993-11-18 05:03:27 +00:00
|
|
|
|
1994-12-16 06:03:28 +00:00
|
|
|
struct uk_driver {
|
|
|
|
u_int32 size;
|
|
|
|
struct uk_data **uk_data;
|
|
|
|
} uk_driver;
|
1993-11-18 05:03:27 +00:00
|
|
|
|
|
|
|
static u_int32 next_uk_unit = 0;
|
|
|
|
|
1995-01-08 13:38:38 +00:00
|
|
|
errval ukopen();
|
1993-11-18 05:03:27 +00:00
|
|
|
/*
|
|
|
|
* The routine called by the low level scsi routine when it discovers
|
|
|
|
* a device suitable for this driver.
|
|
|
|
*/
|
|
|
|
errval
|
|
|
|
ukattach(sc_link)
|
|
|
|
struct scsi_link *sc_link;
|
|
|
|
{
|
|
|
|
u_int32 unit, i, stat;
|
1994-12-16 06:03:28 +00:00
|
|
|
struct uk_data *uk, **ukrealloc;
|
1993-11-18 05:03:27 +00:00
|
|
|
unsigned char *tbl;
|
|
|
|
|
|
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("ukattach: "));
|
1994-12-16 06:03:28 +00:00
|
|
|
|
1993-11-18 05:03:27 +00:00
|
|
|
/*
|
1994-12-16 06:03:28 +00:00
|
|
|
* allocate the resources for another drive
|
|
|
|
* if we have already allocate a uk_data pointer we must
|
|
|
|
* copy the old pointers into a new region that is
|
|
|
|
* larger and release the old region, aka realloc
|
|
|
|
*/
|
|
|
|
/* XXX
|
|
|
|
* This if will always be true for now, but future code may
|
|
|
|
* preallocate more units to reduce overhead. This would be
|
|
|
|
* done by changing the malloc to be (next_uk_unit * x) and
|
|
|
|
* the uk_driver.size++ to be +x
|
1993-11-18 05:03:27 +00:00
|
|
|
*/
|
|
|
|
unit = next_uk_unit++;
|
1994-12-16 06:03:28 +00:00
|
|
|
if (unit >= uk_driver.size) {
|
|
|
|
ukrealloc =
|
|
|
|
malloc(sizeof(uk_driver.uk_data) * next_uk_unit,
|
|
|
|
M_DEVBUF, M_NOWAIT);
|
|
|
|
if (!ukrealloc) {
|
|
|
|
printf("uk%ld: malloc failed for ukrealloc\n", unit);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
/* Make sure we have something to copy before we copy it */
|
|
|
|
bzero(ukrealloc, sizeof(uk_driver.uk_data) * next_uk_unit);
|
|
|
|
if (uk_driver.size) {
|
|
|
|
bcopy(uk_driver.uk_data, ukrealloc,
|
|
|
|
sizeof(uk_driver.uk_data) * uk_driver.size);
|
|
|
|
free(uk_driver.uk_data, M_DEVBUF);
|
|
|
|
}
|
|
|
|
uk_driver.uk_data = ukrealloc;
|
|
|
|
uk_driver.uk_data[unit] = NULL;
|
|
|
|
uk_driver.size++;
|
|
|
|
}
|
|
|
|
if (uk_driver.uk_data[unit]) {
|
|
|
|
printf("uk%ld: Already has storage!\n", unit);
|
1993-11-18 05:03:27 +00:00
|
|
|
return (0);
|
|
|
|
}
|
1994-12-16 06:03:28 +00:00
|
|
|
/*
|
|
|
|
* alloate the per drive data area
|
|
|
|
*/
|
|
|
|
uk = uk_driver.uk_data[unit] =
|
|
|
|
malloc(sizeof(struct uk_data), M_DEVBUF, M_NOWAIT);
|
|
|
|
if (!uk) {
|
|
|
|
printf("uk%ld: malloc failed for uk_data\n", unit);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
bzero(uk, sizeof(struct uk_data));
|
|
|
|
|
1993-11-18 05:03:27 +00:00
|
|
|
/*
|
|
|
|
* Store information needed to contact our base driver
|
|
|
|
*/
|
1994-12-16 06:03:28 +00:00
|
|
|
uk->sc_link = sc_link;
|
1993-11-18 05:03:27 +00:00
|
|
|
sc_link->device = &uk_switch;
|
|
|
|
sc_link->dev_unit = unit;
|
1995-01-08 13:38:38 +00:00
|
|
|
sc_link->dev = UKSETUNIT(scsi_dev_lookup(ukopen), unit);
|
1993-11-18 05:03:27 +00:00
|
|
|
|
|
|
|
printf("uk%d: unknown device\n", unit);
|
1994-12-16 06:03:28 +00:00
|
|
|
uk->flags = UK_KNOWN;
|
1993-11-18 05:03:27 +00:00
|
|
|
|
1993-11-25 01:38:01 +00:00
|
|
|
return 1; /* XXX ??? */
|
1993-11-18 05:03:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* open the device.
|
|
|
|
*/
|
|
|
|
errval
|
|
|
|
ukopen(dev)
|
1993-11-25 01:38:01 +00:00
|
|
|
dev_t dev;
|
1993-11-18 05:03:27 +00:00
|
|
|
{
|
|
|
|
errval errcode = 0;
|
|
|
|
u_int32 unit, mode;
|
1994-12-16 06:03:28 +00:00
|
|
|
struct uk_data *uk;
|
1993-11-18 05:03:27 +00:00
|
|
|
struct scsi_link *sc_link;
|
1995-01-08 13:38:38 +00:00
|
|
|
unit = UKUNIT(dev);
|
1993-11-18 05:03:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the unit is legal
|
|
|
|
*/
|
1994-12-16 06:03:28 +00:00
|
|
|
if (unit >= uk_driver.size) {
|
|
|
|
printf("uk%d: uk %d > %d\n", unit, unit, uk_driver.size);
|
1993-11-18 05:03:27 +00:00
|
|
|
return ENXIO;
|
|
|
|
}
|
1994-12-16 06:03:28 +00:00
|
|
|
uk = uk_driver.uk_data[unit];
|
1993-11-18 05:03:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the device has been initialised
|
|
|
|
*/
|
1994-12-16 06:03:28 +00:00
|
|
|
if((!uk) || (!(uk->flags & UK_KNOWN))) {
|
1993-11-18 05:03:27 +00:00
|
|
|
printf("uk%d: not set up\n", unit);
|
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only allow one at a time
|
|
|
|
*/
|
1994-12-16 06:03:28 +00:00
|
|
|
sc_link = uk->sc_link;
|
1993-11-18 05:03:27 +00:00
|
|
|
if (sc_link->flags & SDEV_OPEN) {
|
|
|
|
printf("uk%d: already open\n", unit);
|
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
sc_link->flags |= SDEV_OPEN;
|
1994-12-16 06:03:28 +00:00
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("ukopen: dev=0x%x (unit %d (of %d))\n",
|
|
|
|
dev, unit, uk_driver.size));
|
1993-11-18 05:03:27 +00:00
|
|
|
/*
|
|
|
|
* Catch any unit attention errors.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* close the device.. only called if we are the LAST
|
|
|
|
* occurence of an open device
|
|
|
|
*/
|
|
|
|
errval
|
|
|
|
ukclose(dev)
|
1993-11-25 01:38:01 +00:00
|
|
|
dev_t dev;
|
1993-11-18 05:03:27 +00:00
|
|
|
{
|
1994-12-16 06:03:28 +00:00
|
|
|
u_int32 unit = minor(dev);
|
|
|
|
unsigned mode; /* XXX !!! XXX FIXME!!! 0??? */
|
|
|
|
struct uk_data *uk;
|
1993-11-18 05:03:27 +00:00
|
|
|
struct scsi_link *sc_link;
|
|
|
|
|
1994-12-16 06:03:28 +00:00
|
|
|
uk = uk_driver.uk_data[unit];
|
|
|
|
sc_link = uk->sc_link;
|
1993-11-18 05:03:27 +00:00
|
|
|
|
|
|
|
SC_DEBUG(sc_link, SDEV_DB1, ("Closing device"));
|
|
|
|
sc_link->flags &= ~SDEV_OPEN;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform special action on behalf of the user
|
|
|
|
* Only does generic scsi ioctls.
|
|
|
|
*/
|
|
|
|
errval
|
|
|
|
ukioctl(dev, cmd, arg, mode)
|
|
|
|
dev_t dev;
|
|
|
|
u_int32 cmd;
|
|
|
|
caddr_t arg;
|
1993-11-25 01:38:01 +00:00
|
|
|
int mode;
|
1993-11-18 05:03:27 +00:00
|
|
|
{
|
|
|
|
unsigned char unit;
|
1994-12-16 06:03:28 +00:00
|
|
|
struct uk_data *uk;
|
1993-11-18 05:03:27 +00:00
|
|
|
struct scsi_link *sc_link;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the device that the user is talking about
|
|
|
|
*/
|
1995-01-08 13:38:38 +00:00
|
|
|
unit = UKUNIT(dev);
|
1994-12-16 06:03:28 +00:00
|
|
|
uk = uk_driver.uk_data[unit];
|
|
|
|
sc_link = uk->sc_link;
|
1995-01-08 13:38:38 +00:00
|
|
|
return(scsi_do_ioctl(dev,sc_link,cmd,arg,mode));
|
1993-11-18 05:03:27 +00:00
|
|
|
}
|
|
|
|
|