1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-17 10:26:15 +00:00

Added driver to support ATAPI floppies ie LS-120 & ZIP drives.

Added "options ATA_STATIC_ID" that wires ATA disks like the old wd driver.

Fixed problems:

	Dont use more sectors/intr than the drive supports.
	Fix announce of > 8.4G disks.
	Dont call ad_interrupt/ad_transfer when no disks config'd.
	Use the right page# for CDR write mode params.
	Fix breakage when no PCI support in kernel.
	Implement DEVFS stuff.

General code clenaup.
This commit is contained in:
Søren Schmidt 1999-03-03 21:10:29 +00:00
parent 90b4d77467
commit b9bb98b32b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=44454
12 changed files with 1159 additions and 612 deletions

View File

@ -25,12 +25,14 @@
* (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: ata-all.c,v 1.4 1999/03/01 21:03:15 sos Exp sos $
* $Id: ata-all.c,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
#include "ata.h"
#if NATA > 0
#include "isa.h"
#include "pci.h"
#include "atadisk.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@ -53,24 +55,28 @@
#define UNIT(dev) (dev>>3 & 0x1f) /* assume 8 minor # per unit */
/* prototypes */
void ataintr(int32_t);
#if NISA > 0
static int32_t ata_isaprobe(struct isa_device *);
static int32_t ata_isaattach(struct isa_device *);
#endif
#if NPCI > 0
static const char *ata_pciprobe(pcici_t, pcidi_t);
static void ata_pciattach(pcici_t, int32_t);
static void promise_intr(int32_t);
#endif
static int32_t ata_probe(int32_t, int32_t, int32_t *);
static int32_t ata_attach(int32_t);
static void promise_intr(int32_t);
static int32_t ata_reset(struct ata_softc *);
static void ataintr(int32_t);
static int32_t ata_device_attach(struct ata_softc *, int32_t);
static int32_t atapi_device_attach(struct ata_softc *, int32_t);
static void bswap(int8_t *, int32_t);
static void btrim(int8_t *, int32_t);
static int32_t atanlun, sysctrl = 0;
static int32_t atanlun = 0, sysctrl = 0;
struct ata_softc *atadevices[MAXATA];
struct isa_driver atadriver = { ata_isaprobe, ata_isaattach, "ata" };
#if NISA > 0
static int32_t
ata_isaprobe(struct isa_device *devp)
{
@ -85,7 +91,7 @@ ata_isaprobe(struct isa_device *devp)
}
res=ata_probe(devp->id_iobase, devp->id_iobase+ATA_ALTPORT, &devp->id_unit);
if (res)
devp->id_intr = ataintr;
devp->id_intr = (inthand2_t *)ataintr;
return res;
}
@ -94,7 +100,9 @@ ata_isaattach(struct isa_device *devp)
{
return ata_attach(devp->id_unit);
}
#endif
#if NPCI > 0
static u_long ata_pcicount;
static struct pci_device ata_pcidevice = {
"ata-pci", ata_pciprobe, ata_pciattach, &ata_pcicount, 0
@ -127,7 +135,7 @@ ata_pciprobe(pcici_t tag, pcidi_t type)
case 0x522910b9:
return "Acer Aladdin IV/V IDE controller";
default:
return ("Unknown PCI IDE controller");
return "Unknown PCI IDE controller";
}
}
return NULL;
@ -208,9 +216,10 @@ ata_pciattach(pcici_t tag, int32_t unit)
register_intr(irq1, 0, 0, (inthand2_t *)ataintr, &bio_imask, lun);
else {
if (sysctrl)
pci_map_int(tag, promise_intr, (void *)lun, &bio_imask);
pci_map_int(tag, (inthand2_t *)promise_intr,
(void *)lun, &bio_imask);
else
pci_map_int(tag, ataintr, (void *)lun, &bio_imask);
pci_map_int(tag, (inthand2_t *)ataintr, (void *)lun,&bio_imask);
}
printf("ata%d at 0x%04x irq %d on ata-pci%d\n",
lun, iobase_1, irq1, unit);
@ -221,7 +230,7 @@ ata_pciattach(pcici_t tag, int32_t unit)
register_intr(irq2, 0, 0, (inthand2_t *)ataintr, &bio_imask, lun);
else {
if (!sysctrl)
pci_map_int(tag, ataintr, (void *) lun, &bio_imask);
pci_map_int(tag, (inthand2_t *)ataintr, (void *)lun,&bio_imask);
}
printf("ata%d at 0x%04x irq %d on ata-pci%d\n",
lun, iobase_2, irq2, unit);
@ -237,37 +246,42 @@ promise_intr(int32_t unit)
if (inl(sysctrl) & 0x00004000)
ataintr(unit+1);
}
#endif
static int32_t
ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t *unit)
{
struct ata_softc *scp = atadevices[atanlun];
u_int8_t status0, status1;
int32_t mask = 0;
int32_t timeout;
int32_t lun = atanlun;
u_int8_t status0, status1;
if (atanlun > MAXATA) {
printf("ata: unit of of range(%d)\n", atanlun);
return(0);
#ifdef ATA_STATIC_ID
atanlun++;
#endif
if (lun > MAXATA) {
printf("ata: unit of of range(%d)\n", lun);
return 0;
}
if (scp) {
printf("ata%d: unit already attached\n", atanlun);
return(0);
printf("ata%d: unit already attached\n", lun);
return 0;
}
scp = malloc(sizeof(struct ata_softc), M_DEVBUF, M_NOWAIT);
if (scp == NULL) {
printf("ata%d: failed to allocate driver storage\n", atanlun);
return(0);
printf("ata%d: failed to allocate driver storage\n", lun);
return 0;
}
bzero(scp, sizeof(struct ata_softc));
scp->unit = atanlun;
scp->unit = lun;
scp->ioaddr = ioaddr;
scp->altioaddr = altioaddr;
#ifdef ATA_DEBUG
printf("ata%d: iobase=0x%04x altiobase=0x%04x\n",
atanlun, scp->ioaddr, scp->altioaddr);
scp->unit, scp->ioaddr, scp->altioaddr);
#endif
/* do we have any signs of ATA/ATAPI HW being present ? */
@ -283,7 +297,7 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t *unit)
mask |= 0x02;
#ifdef ATA_DEBUG
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
atanlun, mask, status0, status1);
scp->unit, mask, status0, status1);
#endif
if (!mask) {
free(scp, M_DEVBUF);
@ -325,7 +339,7 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t *unit)
mask &= ~0x02;
#ifdef ATA_DEBUG
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
atanlun, mask, status0, status1);
scp->unit, mask, status0, status1);
#endif
if (!mask) {
free(scp, M_DEVBUF);
@ -370,7 +384,7 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t *unit)
}
}
#ifdef ATA_DEBUG
printf("ata%d: devices = 0x%x\n", atanlun, scp->devices);
printf("ata%d: devices = 0x%x\n", scp->unit, scp->devices);
#endif
if (!(scp->devices & (ATA_ATA_MASTER|ATA_ATAPI_MASTER)))
scp->flags |= ATA_F_SLAVE_ONLY;
@ -380,8 +394,11 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t *unit)
}
bufq_init(&scp->ata_queue);
TAILQ_INIT(&scp->atapi_queue);
*unit = atanlun;
atadevices[atanlun++] = scp;
*unit = scp->unit;
atadevices[scp->unit] = scp;
#ifndef ATA_STATIC_ID
atanlun++;
#endif
return ATA_IOSIZE;
}
@ -410,7 +427,7 @@ ata_attach(int32_t unit)
return scp->devices;
}
void
static void
ataintr(int32_t unit)
{
struct ata_softc *scp;
@ -431,16 +448,12 @@ ataintr(int32_t unit)
/* find & call the responsible driver to process this interrupt */
switch (scp->active) {
case ATA_IDLE:
if (intcount++ < 5)
printf("ata%d: unwanted interrupt\n", unit);
break;
#if NATADISK > 0
case ATA_ACTIVE_ATA:
if ((ata_request = bufq_first(&scp->ata_queue)))
ad_interrupt(ata_request);
break;
#endif
case ATA_ACTIVE_ATAPI:
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue)))
atapi_interrupt(atapi_request);
@ -449,6 +462,12 @@ ataintr(int32_t unit)
case ATA_IGNORE_INTR:
scp->active = ATA_IDLE;
break;
default:
case ATA_IDLE:
if (intcount++ < 5)
printf("ata%d: unwanted interrupt\n", unit);
break;
}
}
@ -508,22 +527,6 @@ ata_wait(struct ata_softc *scp, u_int8_t mask)
return -1;
}
static int32_t
ata_reset(struct ata_softc *scp)
{
outb(scp->altioaddr, ATA_A_RESET | ATA_A_IDS);
DELAY(10000);
outb(scp->altioaddr, ATA_A_IDS);
DELAY(10000);
inb(scp->ioaddr + ATA_ERROR);
outb(scp->altioaddr, ATA_A_4BIT);
if (ata_wait(scp, 0) < 0) {
printf("ata%d: RESET failed\n", scp->unit);
return 1;
}
return 0;
}
static int32_t
ata_device_attach(struct ata_softc *scp, int32_t device)
{

View File

@ -25,11 +25,10 @@
* (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: ata-all.h,v 1.3 1999/03/01 21:03:15 sos Exp sos $
* $Id: ata-all.h,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
/* ATA register defines */
#define ATA_DATA 0x00 /* data register */
#define ATA_ERROR 0x01 /* (R) error register */
#define ATA_PRECOMP 0x01 /* (W) precompensation */
@ -153,9 +152,7 @@ struct ata_params {
int16_t securelevel;
};
/*
* Structure describing an ATA device
*/
/* Structure describing an ATA device */
struct ata_softc {
u_int32_t unit; /* this instance's number */
u_int32_t ioaddr; /* port addr */
@ -178,10 +175,6 @@ struct ata_softc {
struct ata_params *ata_parm[2]; /* ata device params */
TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */
struct atapi_params *atapi_parm[2]; /* atapi device params */
#ifdef DEVFS
static void *devfs_token;
#endif
};
struct ata_request {

View File

@ -25,7 +25,7 @@
* (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: ata-disk.c,v 1.14 1999/03/01 21:03:15 sos Exp sos $
* $Id: ata-disk.c,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
#include "ata.h"
@ -58,8 +58,8 @@
static d_open_t adopen;
static d_close_t adclose;
static d_write_t adwrite;
static d_read_t adread;
static d_write_t adwrite;
static d_ioctl_t adioctl;
static d_strategy_t adstrategy;
static d_psize_t adpsize;
@ -95,7 +95,7 @@ static void
ad_attach(void *notused)
{
struct ad_softc *adp;
int32_t ctlr, dev;
int32_t ctlr, dev, secsperint;
int8_t model_buf[40+1];
int8_t revision_buf[8+1];
@ -103,6 +103,9 @@ ad_attach(void *notused)
for (ctlr=0; ctlr<MAXATA && atadevices[ctlr]; ctlr++) {
for (dev=0; dev<2; dev++) {
if (atadevices[ctlr]->ata_parm[dev]) {
#ifdef ATA_STATIC_ID
adnlun = dev + ctlr * 2;
#endif
adp = adtab[adnlun];
if (adp)
printf("ad%d: unit already attached\n", adnlun);
@ -113,20 +116,23 @@ ad_attach(void *notused)
adp->controller = atadevices[ctlr];
adp->ata_parm = atadevices[ctlr]->ata_parm[dev];
adp->unit = (dev == 0) ? ATA_MASTER : ATA_SLAVE;
adp->lun = adnlun;
adp->cylinders = adp->ata_parm->cylinders;
adp->heads = adp->ata_parm->heads;
adp->sectors = adp->ata_parm->sectors;
adp->total_secs = adp->ata_parm->lbasize;
if (!adp->total_secs)
adp->total_secs = adp->cylinders*adp->heads*adp->sectors;
if (adp->cylinders == 16383)
adp->cylinders = adp->total_secs/(adp->heads*adp->sectors);
/* support multiple sectors / interrupt ? */
if (ad_command(adp, ATA_C_SET_MULTI, 0, 0, 0, 16))
adp->transfersize = DEV_BSIZE;
else {
if (ata_wait(adp->controller, ATA_S_DRDY) < 0)
adp->transfersize = DEV_BSIZE;
else
adp->transfersize = 16*DEV_BSIZE;
}
adp->transfersize = DEV_BSIZE;
secsperint = min(adp->ata_parm->nsecperint, 16);
if (!ad_command(adp, ATA_C_SET_MULTI, 0, 0, 0, secsperint) &&
ata_wait(adp->controller, ATA_S_DRDY) >= 0)
adp->transfersize *= secsperint;
bpack(adp->ata_parm->model, model_buf, sizeof(model_buf));
bpack(adp->ata_parm->revision, revision_buf,
sizeof(revision_buf));
@ -152,6 +158,18 @@ ad_attach(void *notused)
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
0x180);
#ifdef DEVFS
adp->cdevs_token = devfs_add_devswf(&ad_cdevsw,
dkmakeminor(adp->lun, 0, 0),
DV_CHR,
UID_ROOT, GID_OPERATOR,
0640, "rad%d", adp->lun);
adp->bdevs_token = devfs_add_devswf(&ad_cdevsw,
dkmakeminor(adp->lun, 0, 0),
DV_BLK,
UID_ROOT, GID_OPERATOR,
0640, "ad%d", adp->lun);
#endif
bufq_init(&adp->queue);
adtab[adnlun++] = adp;
}
@ -245,17 +263,6 @@ adioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flags, struct proc *p)
return ENOTTY;
}
static int32_t
adpsize(dev_t dev)
{
struct ad_softc *adp;
int32_t lun = UNIT(dev);
if (lun >= adnlun || !(adp = adtab[lun]))
return -1;
return (dssize(dev, &adp->slices, adopen, adclose));
}
static void
adstrategy(struct buf *bp)
{
@ -301,6 +308,17 @@ printf("adstrategy: entered\n");
splx(s);
}
static int32_t
adpsize(dev_t dev)
{
struct ad_softc *adp;
int32_t lun = UNIT(dev);
if (lun >= adnlun || !(adp = adtab[lun]))
return -1;
return dssize(dev, &adp->slices, adopen, adclose);
}
static void
ad_strategy(struct buf *bp)
{
@ -434,14 +452,14 @@ ad_interrupt(struct buf *bp)
if (adp->controller->status & (ATA_S_ERROR | ATA_S_CORR)) {
oops:
printf("ad%d: status=%02x error=%02x\n",
adp->unit, adp->controller->status, adp->controller->error);
adp->lun, adp->controller->status, adp->controller->error);
if (adp->controller->status & ATA_S_ERROR) {
printf("ad_interrupt: hard error");
printf("ad_interrupt: hard error\n");
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
if (adp->controller->status & ATA_S_CORR)
printf("ad_interrupt: soft ECC");
printf("ad_interrupt: soft ECC\n");
}
/* if this was a read operation, get the data */
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && adp->active) {

View File

@ -25,17 +25,16 @@
* (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: ata-disk.h,v 1.5 1999/03/01 12:11:01 sos Exp $
* $Id: ata-disk.h,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
/*
* Structure describing an ATA disk
*/
/* Structure describing an ATA disk */
struct ad_softc {
struct ata_softc *controller; /* ptr to parent ctrl */
struct ata_params *ata_parm; /* ata device params */
struct diskslices *slices;
int32_t unit; /* ATA_MASTER or ATA_SLAVE */
int32_t lun; /* logical unit number */
u_int16_t cylinders; /* disk geometry (probed) */
u_int8_t heads;
u_int8_t sectors;
@ -47,9 +46,12 @@ struct ad_softc {
u_int32_t donecount; /* bytes transferred */
u_int32_t active; /* active processing request */
u_int32_t flags; /* drive flags */
#define AD_F_LABELLING 0x0001
struct devstat stats; /* devstat entry */
#define AD_F_LABELLING 0x0001
#ifdef DEVFS
void *cdevs_token;
void *bdevs_token;
#endif
};
void ad_transfer(struct buf *);

View File

@ -25,13 +25,13 @@
* (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: atapi-all.c,v 1.5 1999/03/01 21:03:15 sos Exp sos $
* $Id: atapi-all.c,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
#include "ata.h"
#include "atapicd.h"
#include "atapist.h"
/*#include "atapifd.h"*/
#include "atapifd.h"
#include "opt_devfs.h"
#if NATA > 0
@ -326,7 +326,7 @@ printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
#ifdef ATAPI_DEBUG
printf("atapi_interrupt: error=%02x\n", request->result);
printf("atapi_interrupt: error=0x%02x\n", request->result);
#endif
if (request->callback) {
(request->callback)(request);
@ -341,7 +341,7 @@ printf("atapi_interrupt: error=%02x\n", request->result);
void
atapi_error(struct atapi_softc *atp, int32_t error)
{
printf("atapi: error = %02x\n", error);
printf("atapi: error = 0x%02x\n", error);
}
void
@ -350,7 +350,7 @@ atapi_dump(int8_t *label, void *data, int32_t len)
u_int8_t *p = data;
printf ("atapi: %s %x", label, *p++);
while (--len > 0) printf ("-%x", *p++);
while (--len > 0) printf ("-%02x", *p++);
printf ("\n");
}

View File

@ -25,7 +25,7 @@
* (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: atapi-all.h,v 1.2 1999/03/01 12:11:01 sos Exp $
* $Id: atapi-all.h,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
/* ATAPI misc defines */
@ -88,25 +88,25 @@
/* ATAPI device parameter information */
struct atapi_params {
u_int cmdsize :2; /* packet command size */
u_int8_t cmdsize :2; /* packet command size */
#define ATAPI_PSIZE_12 0 /* 12 bytes */
#define ATAPI_PSIZE_16 1 /* 16 bytes */
u_int :3;
u_int drqtype :2; /* DRQ type */
u_int8_t :3;
u_int8_t drqtype :2; /* DRQ type */
#define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */
#define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */
#define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */
u_int removable :1; /* device is removable */
u_int device_type :5; /* device type */
u_int8_t removable :1; /* device is removable */
u_int8_t device_type :5; /* device type */
#define ATAPI_TYPE_DIRECT 0 /* disk/floppy */
#define ATAPI_TYPE_TAPE 1 /* streaming tape */
#define ATAPI_TYPE_CDROM 5 /* CD-ROM device */
#define ATAPI_TYPE_OPTICAL 7 /* optical disk */
u_int :1;
u_int proto :2; /* command protocol */
u_int8_t :1;
u_int8_t proto :2; /* command protocol */
#define ATAPI_PROTO_ATAPI 2
int16_t reserved1[9];

View File

@ -25,7 +25,7 @@
* (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: atapi-cd.c,v 1.5 1999/03/01 21:03:15 sos Exp sos $
* $Id: atapi-cd.c,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
#include "ata.h"
@ -56,8 +56,8 @@
static d_open_t acdopen;
static d_close_t acdclose;
static d_write_t acdwrite;
static d_read_t acdread;
static d_write_t acdwrite;
static d_ioctl_t acdioctl;
static d_strategy_t acdstrategy;
@ -106,6 +106,9 @@ static int32_t acd_close_track(struct acd_softc *);
static int32_t acd_close_disk(struct acd_softc *);
static int32_t acd_read_track_info(struct acd_softc *, int, struct acd_track_info*);
static int32_t acd_blank_disk(struct acd_softc *);
static void lba2msf(int32_t, u_int8_t *, u_int8_t *, u_int8_t *);
static int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t);
static void acd_drvinit(void *);
int
acdattach(struct atapi_softc *atp)
@ -201,7 +204,7 @@ acdattach(struct atapi_softc *atp)
return 0;
}
struct acd_softc *
static struct acd_softc *
acd_init_lun(struct atapi_softc *atp, int32_t lun, struct devstat *stats)
{
struct acd_softc *acd;
@ -227,27 +230,25 @@ acd_init_lun(struct atapi_softc *atp, int32_t lun, struct devstat *stats)
else
acd->stats = stats;
#ifdef DEVFS
acd->ra_devfs_token =
devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, 0),
DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
"racd%da", lun);
acd->rc_devfs_token =
devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
"racd%dc", lun);
acd->a_devfs_token =
devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, 0),
DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
"acd%da", lun);
acd->c_devfs_token =
devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART),
DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
"acd%dc", lun);
acd->a_cdevfs_token = devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, 0),
DV_CHR, UID_ROOT, GID_OPERATOR, 0644,
"racd%da", lun);
acd->c_cdevfs_token = devfs_add_devswf(&acd_cdevsw,
dkmakeminor(lun, 0, RAW_PART),
DV_CHR, UID_ROOT, GID_OPERATOR, 0644,
"racd%dc", lun);
acd->a_bdevfs_token = devfs_add_devswf(&acd_cdevsw, dkmakeminor(lun, 0, 0),
DV_BLK, UID_ROOT, GID_OPERATOR, 0644,
"acd%da", lun);
acd->c_bdevfs_token = devfs_add_devswf(&acd_cdevsw,
dkmakeminor(lun, 0, RAW_PART),
DV_BLK, UID_ROOT, GID_OPERATOR, 0644,
"acd%dc", lun);
#endif
return acd;
}
void
static void
acd_describe(struct acd_softc *cdp)
{
int32_t comma;
@ -377,7 +378,24 @@ acd_describe(struct acd_softc *cdp)
printf("\n");
}
static int
static __inline void
lba2msf(int32_t lba, u_int8_t *m, u_int8_t *s, u_int8_t *f)
{
lba += 150;
lba &= 0xffffff;
*m = lba / (60 * 75);
lba %= (60 * 75);
*s = lba / 75;
*f = lba % 75;
}
static __inline int32_t
msf2lba(u_int8_t m, u_int8_t s, u_int8_t f)
{
return (m * 60 + s) * 75 + f - 150;
}
static int32_t
acdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = dkunit(dev);
@ -393,7 +411,7 @@ acdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
if (fmt == S_IFBLK)
cdp->flags |= F_BOPEN;
else
++cdp->refcnt;
cdp->refcnt++;
if ((flags & O_NONBLOCK) == 0) {
if ((flags & FWRITE) != 0) {
@ -413,7 +431,7 @@ acdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
return 0;
}
int32_t
static int32_t
acdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = dkunit(dev);
@ -425,7 +443,7 @@ acdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
if (fmt == S_IFBLK)
cdp->flags &= ~F_BOPEN;
else
--cdp->refcnt;
cdp->refcnt--;
/* Are we the last open ?? */
if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) {
@ -442,155 +460,19 @@ acdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
return 0;
}
static int
static int32_t
acdread(dev_t dev, struct uio *uio, int32_t ioflag)
{
return physio(acdstrategy, NULL, dev, 1, minphys, uio);
}
static int
static int32_t
acdwrite(dev_t dev, struct uio *uio, int32_t ioflag)
{
return physio(acdstrategy, NULL, dev, 0, minphys, uio);
}
void
acdstrategy(struct buf *bp)
{
int32_t lun = dkunit(bp->b_dev);
struct acd_softc *cdp = acdtab[lun];
int32_t x;
#ifdef NOTYET
/* allow write only on CD-R/RW media */ /* all for now SOS */
if (!(bp->b_flags & B_READ) && !(writeable_media)) {
bp->b_error = EROFS;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
#endif
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
/* check for valid blocksize SOS */
bp->b_pblkno = bp->b_blkno;
bp->b_resid = bp->b_bcount;
x = splbio();
bufqdisksort(&cdp->buf_queue, bp);
acd_start(cdp);
splx(x);
}
static void
acd_start(struct acd_softc *cdp)
{
struct buf *bp = bufq_first(&cdp->buf_queue);
u_long lba, count;
int8_t ccb[16];
if (!bp)
return;
bzero(ccb, sizeof(ccb));
bufq_remove(&cdp->buf_queue, bp);
/* Should reject all queued entries if media have changed. */
if (cdp->flags & F_MEDIA_CHANGED) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
acd_select_slot(cdp);
if ((bp->b_flags & B_READ) == B_WRITE) {
if ((cdp->flags & F_TRACK_PREPED) == 0) {
if ((cdp->flags & F_TRACK_PREP) == 0) {
printf("acd%d: sequence error\n", cdp->lun);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
} else {
if (acd_open_track(cdp, &cdp->preptrack) != 0) {
biodone(bp);
return;
}
cdp->flags |= F_TRACK_PREPED;
}
}
}
if (bp->b_flags & B_READ) {
lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE);
ccb[0] = ATAPI_READ_BIG;
}
else {
lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size);
ccb[0] = ATAPI_WRITE_BIG;
}
count = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size;
ccb[1] = 0;
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = count>>8;
ccb[8] = count;
devstat_start_transaction(cdp->stats);
atapi_queue_cmd(cdp->atp, ccb, bp->b_data, bp->b_bcount,
(bp->b_flags&B_READ)?A_READ : 0, acd_done, cdp, (void *)bp);
}
static void
acd_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct acd_softc *cdp = request->driver;
devstat_end_transaction(cdp->stats, bp->b_bcount-request->bytecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
printf("acd_done: ");
atapi_error(request->device, request->result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
else {
bp->b_resid = request->bytecount;
if ((bp->b_flags & B_READ) == B_WRITE)
cdp->flags |= F_WRITTEN;
}
biodone(bp);
acd_start(cdp);
}
static __inline void
lba2msf(int32_t lba, u_int8_t *m, u_int8_t *s, u_int8_t *f)
{
lba += 150;
lba &= 0xffffff;
*m = lba / (60 * 75);
lba %= (60 * 75);
*s = lba / 75;
*f = lba % 75;
}
static __inline int32_t
msf2lba(u_int8_t m, u_int8_t s, u_int8_t f)
{
return (m * 60 + s) * 75 + f - 150;
}
int32_t
static int32_t
acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
int32_t lun = dkunit(dev);
@ -634,7 +516,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
case CDIOCRESET:
error = suser(p->p_ucred, &p->p_acflag);
if (error)
return (error);
return error;
return acd_test_unit_ready(cdp);
case CDIOCEJECT:
@ -658,7 +540,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr;
struct toc *toc = &cdp->toc;
struct toc buf;
u_long len;
u_int32_t len;
u_int8_t starting_track = te->starting_track;
if (!cdp->toc.hdr.ending_track)
@ -741,7 +623,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
struct ioc_read_subchannel *args =
(struct ioc_read_subchannel *)addr;
struct cd_sub_channel_info data;
u_long len = args->data_len;
u_int32_t len = args->data_len;
int32_t abslba, rellba;
int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0,
sizeof(cdp->subchan)>>8, sizeof(cdp->subchan),
@ -755,7 +637,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
sizeof(cdp->subchan), A_READ, NULL, NULL, NULL))
return EIO;
#ifdef ACD_DEBUG
atapi_dump("acd: subchan", &cdp->subchan, sizeof(cdp->subchan));
atapi_dump("acd: subchan", &cdp->subchan, sizeof(cdp->subchan));
#endif
abslba = cdp->subchan.abslba;
@ -807,7 +689,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
case CDIOCPLAYTRACKS:
{
struct ioc_play_track *args = (struct ioc_play_track *)addr;
u_long start, len;
u_int32_t start, len;
int32_t t1, t2;
int8_t ccb[16];
@ -1049,6 +931,128 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
return error;
}
static void
acdstrategy(struct buf *bp)
{
int32_t lun = dkunit(bp->b_dev);
struct acd_softc *cdp = acdtab[lun];
int32_t x;
#ifdef NOTYET
/* allow write only on CD-R/RW media */ /* all for now SOS */
if (!(bp->b_flags & B_READ) && !(writeable_media)) {
bp->b_error = EROFS;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
#endif
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
/* check for valid blocksize SOS */
bp->b_pblkno = bp->b_blkno;
bp->b_resid = bp->b_bcount;
x = splbio();
bufqdisksort(&cdp->buf_queue, bp);
acd_start(cdp);
splx(x);
}
static void
acd_start(struct acd_softc *cdp)
{
struct buf *bp = bufq_first(&cdp->buf_queue);
u_int32_t lba, count;
int8_t ccb[16];
if (!bp)
return;
bufq_remove(&cdp->buf_queue, bp);
/* Should reject all queued entries if media have changed. */
if (cdp->flags & F_MEDIA_CHANGED) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
acd_select_slot(cdp);
if ((bp->b_flags & B_READ) == B_WRITE) {
if ((cdp->flags & F_TRACK_PREPED) == 0) {
if ((cdp->flags & F_TRACK_PREP) == 0) {
printf("acd%d: sequence error\n", cdp->lun);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
} else {
if (acd_open_track(cdp, &cdp->preptrack) != 0) {
biodone(bp);
return;
}
cdp->flags |= F_TRACK_PREPED;
}
}
}
bzero(ccb, sizeof(ccb));
if (bp->b_flags & B_READ) {
lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE);
ccb[0] = ATAPI_READ_BIG;
}
else {
lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size);
ccb[0] = ATAPI_WRITE_BIG;
}
count = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size;
#ifdef ACD_DEBUG
printf("acd%d: lba=%d, count=%d\n", cdp->lun, lba, count);
#endif
ccb[1] = 0;
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = count>>8;
ccb[8] = count;
devstat_start_transaction(cdp->stats);
atapi_queue_cmd(cdp->atp, ccb, bp->b_data, bp->b_bcount,
(bp->b_flags&B_READ)?A_READ : 0, acd_done, cdp, (void *)bp);
}
static void
acd_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct acd_softc *cdp = request->driver;
devstat_end_transaction(cdp->stats, bp->b_bcount-request->bytecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
atapi_error(request->device, request->result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
else {
bp->b_resid = request->bytecount;
if ((bp->b_flags & B_READ) == B_WRITE)
cdp->flags |= F_WRITTEN;
}
biodone(bp);
acd_start(cdp);
}
static int32_t
acd_test_unit_ready(struct acd_softc *cdp)
{
@ -1095,8 +1099,8 @@ acd_mode_sense(struct acd_softc *cdp, u_int8_t page,
error = atapi_queue_cmd(cdp->atp, ccb, pagebuf, pagesize, A_READ,
NULL, NULL, NULL);
#ifdef AST_DEBUG
atapi_dump("acd: mode sense ", &cdp->au, sizeof(cdp->au));
#ifdef ACD_DEBUG
atapi_dump("acd: mode sense ", pagebuf, pagesize);
#endif
return error;
}
@ -1107,8 +1111,9 @@ acd_mode_select(struct acd_softc *cdp, void *pagebuf, int32_t pagesize)
int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, 0, 0, 0, 0,
pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 };
#ifdef AST_DEBUG
atapi_dump("acd: mode select ", &cdp->au, sizeof(cdp->au));
#ifdef ACD_DEBUG
printf("acd: modeselect pagesize=%d\n", pagesize);
atapi_dump("acd: mode select ", pagebuf, pagesize);
#endif
return atapi_queue_cmd(cdp->atp, ccb, pagebuf, pagesize, 0,
NULL, NULL, NULL);
@ -1196,9 +1201,6 @@ acd_read_toc(struct acd_softc *cdp)
return 0;
}
/*
* Set up the audio channel masks.
*/
static int32_t
acd_setchan(struct acd_softc *cdp,
u_int8_t c0, u_int8_t c1, u_int8_t c2, u_int8_t c3)
@ -1287,7 +1289,7 @@ acd_select_slot(struct acd_softc *cdp)
acd_lock_device(cdp, 1);
}
static int
static int32_t
acd_rezero_unit(struct acd_softc *cdp)
{
int8_t ccb[16];
@ -1297,14 +1299,14 @@ acd_rezero_unit(struct acd_softc *cdp)
return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL);
}
static int
static int32_t
acd_open_disk(struct acd_softc *cdp, int32_t test)
{
cdp->next_writeable_lba = 0;
return 0;
}
static int
static int32_t
acd_close_disk(struct acd_softc *cdp)
{
int8_t ccb[16];
@ -1316,7 +1318,7 @@ acd_close_disk(struct acd_softc *cdp)
return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL);
}
static int
static int32_t
acd_open_track(struct acd_softc *cdp, struct wormio_prepare_track *ptp)
{
struct write_param param;
@ -1386,7 +1388,7 @@ acd_open_track(struct acd_softc *cdp, struct wormio_prepare_track *ptp)
return acd_mode_select(cdp, &param, sizeof(param));
}
static int
static int32_t
acd_close_track(struct acd_softc *cdp)
{
int8_t ccb[16];
@ -1396,7 +1398,7 @@ acd_close_track(struct acd_softc *cdp)
return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL);
}
static int
static int32_t
acd_read_track_info(struct acd_softc *cdp,
int32_t lba, struct acd_track_info *info)
{
@ -1418,7 +1420,7 @@ acd_read_track_info(struct acd_softc *cdp,
return 0;
}
static int
static int32_t
acd_blank_disk(struct acd_softc *cdp)
{
int32_t error;

View File

@ -25,21 +25,17 @@
* (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: atapi-cd.h,v 1.3 1999/03/01 21:03:15 sos Exp sos $
* $Id: atapi-cd.h,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
/*
* CDROM Table Of Contents
*/
/* CDROM Table Of Contents */
#define MAXTRK 99
struct toc {
struct ioc_toc_header hdr;
struct cd_toc_entry tab[MAXTRK + 1];
struct ioc_toc_header hdr;
struct cd_toc_entry tab[MAXTRK + 1];
};
/*
* CDROM Audio Control Parameters Page
*/
/* CDROM Audio Control Parameters Page */
struct audiopage {
/* Mode Page data header */
u_int16_t data_length;
@ -63,22 +59,21 @@ struct audiopage {
u_int8_t reserved5;
u_int16_t lb_per_sec;
struct port_control {
u_int8_t channels:4;
u_int8_t channels:4;
#define CHANNEL_0 1
#define CHANNEL_1 2
#define CHANNEL_2 4
#define CHANNEL_3 8
u_int8_t volume;
u_int8_t volume;
} port[4];
};
/*
* CDROM Capabilities and Mechanical Status Page
*/
/* CDROM Capabilities and Mechanical Status Page */
struct cappage {
/* Mode data header */
u_int16_t data_length;
u_int8_t medium_type; /* Present media type */
u_int8_t medium_type;
#define MST_TYPE_MASK_LOW 0x0f
#define MST_FMT_NONE 0x00
#define MST_DATA_120 0x01
@ -108,55 +103,55 @@ struct cappage {
#define ATAPI_CDROM_CAP_PAGE 0x2a
u_int8_t param_len;
u_int8_t read_cdr :1; /* Supports CD-R read */
u_int8_t read_cdrw :1; /* Supports CD-RW read */
u_int8_t method2 :1; /* Supports reading packet tracks */
u_int8_t byte2_37 :5;
u_int8_t write_cdr :1; /* Supports CD-R write */
u_int8_t write_cdrw :1; /* Supports CD-RW write */
u_int8_t test_write :1; /* Supports test writing */
u_int8_t byte3_37 :5;
u_int8_t audio_play :1; /* Audio play supported */
u_int8_t composite :1; /* Composite audio/video supported */
u_int8_t dport1 :1; /* Digital audio on port 1 */
u_int8_t dport2 :1; /* Digital audio on port 2 */
u_int8_t mode2_form1 :1; /* Mode 2 form 1 (XA) read */
u_int8_t mode2_form2 :1; /* Mode 2 form 2 format */
u_int8_t multisession :1; /* Multi-session photo-CD */
u_int8_t read_cdr :1; /* supports CD-R read */
u_int8_t read_cdrw :1; /* supports CD-RW read */
u_int8_t method2 :1; /* supports reading packet tracks */
u_int8_t reserved2_37 :5;
u_int8_t write_cdr :1; /* supports CD-R write */
u_int8_t write_cdrw :1; /* supports CD-RW write */
u_int8_t test_write :1; /* supports test writing */
u_int8_t reserved3_37 :5;
u_int8_t audio_play :1; /* audio play supported */
u_int8_t composite :1; /* composite audio/video supported */
u_int8_t dport1 :1; /* digital audio on port 1 */
u_int8_t dport2 :1; /* digital audio on port 2 */
u_int8_t mode2_form1 :1; /* mode 2 form 1 (XA) read */
u_int8_t mode2_form2 :1; /* mode 2 form 2 format */
u_int8_t multisession :1; /* multi-session photo-CD */
u_int8_t :1;
u_int8_t cd_da :1; /* Audio-CD read supported */
u_int8_t cd_da :1; /* audio-CD read supported */
u_int8_t cd_da_stream :1; /* CD-DA streaming */
u_int8_t rw :1; /* Combined R-W subchannels */
u_int8_t rw :1; /* combined R-W subchannels */
u_int8_t rw_corr :1; /* R-W subchannel data corrected */
u_int8_t c2 :1; /* C2 error pointers supported */
u_int8_t isrc :1; /* Can return the ISRC info */
u_int8_t upc :1; /* Can return the catalog number UPC */
u_int8_t isrc :1; /* can return the ISRC info */
u_int8_t upc :1; /* can return the catalog number UPC */
u_int8_t :1;
u_int8_t lock :1; /* Can be locked */
u_int8_t locked :1; /* Current lock state */
u_int8_t prevent :1; /* Prevent jumper installed */
u_int8_t eject :1; /* Can eject */
u_int8_t lock :1; /* can be locked */
u_int8_t locked :1; /* current lock state */
u_int8_t prevent :1; /* prevent jumper installed */
u_int8_t eject :1; /* can eject */
u_int8_t :1;
u_int8_t mech :3; /* Loading mechanism type */
u_int8_t mech :3; /* loading mechanism type */
#define MST_MECH_CADDY 0
#define MST_MECH_TRAY 1
#define MST_MECH_POPUP 2
#define MST_MECH_CHANGER 4
#define MST_MECH_CARTRIDGE 5
u_int8_t sep_vol :1; /* Independent volume of channels */
u_int8_t sep_mute :1; /* Independent mute of channels */
u_int8_t sep_vol :1; /* independent volume of channels */
u_int8_t sep_mute :1; /* independent mute of channels */
u_int8_t:6;
u_int16_t max_speed; /* Max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* Number of discrete volume levels */
u_int16_t buf_size; /* Internal buffer size in bytes/1024 */
u_int16_t cur_speed; /* Current data rate in bytes/1000 */
u_int16_t max_speed; /* max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* number of discrete volume levels */
u_int16_t buf_size; /* internal buffer size in bytes/1024 */
u_int16_t cur_speed; /* current data rate in bytes/1000 */
u_int8_t reserved3;
u_int8_t bckf :1; /* Data valid on failing edge of BCK */
u_int8_t rch :1; /* High LRCK indicates left channel */
u_int8_t lsbf :1; /* Set if LSB first */
u_int8_t bckf :1; /* data valid on failing edge of BCK */
u_int8_t rch :1; /* high LRCK indicates left channel */
u_int8_t lsbf :1; /* set if LSB first */
u_int8_t dlen :2;
#define MST_DLEN_32 0
#define MST_DLEN_16 1
@ -167,42 +162,38 @@ struct cappage {
u_int8_t reserved4[2];
};
/*
* CDROM Changer mechanism status structure
*/
/* CDROM Changer mechanism status structure */
struct changer {
u_int8_t current_slot :5; /* Active changer slot */
u_int8_t mech_state :2; /* Current changer state */
u_int8_t current_slot :5; /* active changer slot */
u_int8_t mech_state :2; /* current changer state */
#define CH_READY 0
#define CH_LOADING 1
#define CH_UNLOADING 2
#define CH_INITIALIZING 3
u_int8_t fault :1; /* Fault in last operation */
u_int8_t fault :1; /* fault in last operation */
u_int8_t reserved0 :5;
u_int8_t cd_state :3; /* Current mechanism state */
u_int8_t cd_state :3; /* current mechanism state */
#define CD_IDLE 0
#define CD_AUDIO_ACTIVE 1
#define CD_AUDIO_SCAN 2
#define CD_HOST_ACTIVE 3
#define CD_NO_STATE 7
u_int8_t current_lba[3]; /* Current LBA */
u_int8_t slots; /* Number of available slots */
u_int16_t table_length; /* Slot table length */
u_int8_t current_lba[3]; /* current LBA */
u_int8_t slots; /* number of available slots */
u_int16_t table_length; /* slot table length */
struct {
u_int8_t changed :1; /* Media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* Slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t changed :1; /* media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
} slot[32];
};
/*
* CDROM Write Parameters Mode Page (Burners ONLY)
*/
/* CDROM Write Parameters Mode Page (Burners ONLY) */
struct write_param {
/* Mode Page data header */
u_int16_t data_length;
@ -213,63 +204,63 @@ struct write_param {
/* Write Parameters mode page */
u_int8_t page_code;
#define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x0e
#define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x05
u_int8_t page_length; /* 0x32 */
u_int8_t write_type :4; /* Write stream type */
u_int8_t write_type :4; /* write stream type */
#define CDR_WTYPE_PACKET 0x00
#define CDR_WTYPE_TRACK 0x01
#define CDR_WTYPE_SESSION 0x02
#define CDR_WTYPE_RAW 0x03
u_int8_t test_write :1; /* Test write enable */
u_int8_t test_write :1; /* test write enable */
u_int8_t reserved2_567 :3;
u_int8_t track_mode :4; /* Track mode */
u_int8_t track_mode :4; /* track mode */
#define CDR_TMODE_AUDIO 0x01
#define CDR_TMODE_INCR_DATA 0x01
#define CDR_TMODE_ALLOW_COPY 0x02
#define CDR_TMODE_DATA 0x04
#define CDR_TMODE_QUAD_AUDIO 0x08
u_int8_t copy :1; /* Generation stamp */
u_int8_t fp :1; /* Fixed packet type */
u_int8_t multi_session :2; /* Multi-session type */
u_int8_t copy :1; /* generation stamp */
u_int8_t fp :1; /* fixed packet type */
u_int8_t multi_session :2; /* multi-session type */
#define CDR_MSES_NONE 0x00
#define CDR_MSES_FINAL 0x01
#define CDR_MSES_RESERVED 0x02
#define CDR_MSES_NULTI 0x03
u_int8_t data_block_type :4; /* Data block type code */
u_int8_t data_block_type :4; /* data block type code */
#define CDR_DB_RAW 0x0 /* 2352 bytes of raw data */
#define CDR_DB_RAW_PQ 0x1 /* 2368 bytes raw data + P/Q subchan */
#define CDR_DB_RAW_PW 0x2 /* 2448 bytes raw data + P-W subchan */
#define CDR_DB_RAW_PW_R 0x3 /* 2448 bytes raw data + P-W raw sub */
#define CDR_DB_RES_4 0x4 /* Reserved */
#define CDR_DB_RES_5 0x5 /* Reserved */
#define CDR_DB_RES_6 0x6 /* Reserved */
#define CDR_DB_VS_7 0x7 /* Vendor specific */
#define CDR_DB_RES_4 0x4 /* reserved */
#define CDR_DB_RES_5 0x5 /* reserved */
#define CDR_DB_RES_6 0x6 /* reserved */
#define CDR_DB_VS_7 0x7 /* vendor specific */
#define CDR_DB_ROM_MODE1 0x8 /* 2048 bytes Mode 1 (ISO/IEC 10149) */
#define CDR_DB_ROM_MODE2 0x9 /* 2336 bytes Mode 2 (ISO/IEC 10149) */
#define CDR_DB_XA_MODE1 0x10 /* 2048 bytes Mode 1 (CD-ROM XA 1) */
#define CDR_DB_XA_MODE2_F1 0x11 /* 2056 bytes Mode 2 (CD-ROM XA 1) */
#define CDR_DB_XA_MODE2_F2 0x12 /* 2324 bytes Mode 2 (CD-ROM XA 2) */
#define CDR_DB_XA_MODE2_MIX 0x13 /* 2332 bytes Mode 2 (CD-ROM XA 1/2) */
#define CDR_DB_RES_14 0x14 /* Reserved */
#define CDR_DB_VS_15 0x15 /* Vendor specific */
#define CDR_DB_RES_14 0x14 /* reserved */
#define CDR_DB_VS_15 0x15 /* vendor specific */
u_int8_t reserved4_4567 :4;
u_int8_t reserved5;
u_int8_t reserved6;
u_int8_t host_app_code :6; /* Host application code */
u_int8_t host_app_code :6; /* host application code */
u_int8_t reserved7_67 :2;
u_int8_t session_format; /* Session format */
u_int8_t session_format; /* session format */
#define CDR_SESS_CDROM 0x00
#define CDR_SESS_CDI 0x10
#define CDR_SESS_CDROM_XA 0x20
u_int8_t reserved9;
u_int32_t packet_size; /* Packet size in bytes */
u_int16_t audio_pause_length; /* Audio pause length in secs */
u_int32_t packet_size; /* packet size in bytes */
u_int16_t audio_pause_length; /* audio pause length in secs */
u_int8_t media_catalog_number[16];
u_int8_t isr_code[16];
u_int8_t sub_hdr_byte0;
@ -284,75 +275,72 @@ struct write_param {
*/
} __attribute__((packed));
/*
* CDROM Read Track Information structure
*/
/* CDROM Read Track Information structure */
struct acd_track_info {
u_int16_t data_length;
u_int8_t track_number; /* Current track number */
u_int8_t session_number; /* Current session number */
u_int8_t track_number; /* current track number */
u_int8_t session_number; /* current session number */
u_int8_t reserved4;
u_int8_t track_mode :4; /* Mode of this track */
u_int8_t copy :1; /* Generation stamp */
u_int8_t damage :1; /* Damaged track */
u_int8_t track_mode :4; /* mode of this track */
u_int8_t copy :1; /* generation stamp */
u_int8_t damage :1; /* damaged track */
u_int8_t reserved5_67 :2;
u_int8_t data_mode :4; /* Data mode of this disc */
u_int8_t fp :1; /* Fixed packet */
u_int8_t packet :1; /* Packet track */
u_int8_t blank :1; /* Blank (empty) track */
u_int8_t rt :1; /* Reserved track */
u_int8_t data_mode :4; /* data mode of this disc */
u_int8_t fp :1; /* fixed packet */
u_int8_t packet :1; /* packet track */
u_int8_t blank :1; /* blank (empty) track */
u_int8_t rt :1; /* reserved track */
u_int8_t nwa_valid :1; /* next_writeable_addr field valid */
u_int8_t reserved7_17 :7;
u_int track_start_addr; /* Start of this track */
u_int next_writeable_addr; /* Next writeable addr on this disc */
u_int free_blocks; /* Free block on this disc */
u_int fixed_packet_size; /* Size of packets on this track */
u_int track_length; /* Length of this track */
u_int track_start_addr; /* start of this track */
u_int next_writeable_addr; /* next writeable addr on this disc */
u_int free_blocks; /* free block on this disc */
u_int fixed_packet_size; /* size of packets on this track */
u_int track_length; /* length of this track */
};
/*
* Structure describing an ATAPI CDROM device
*/
/* Structure describing an ATAPI CDROM device */
struct acd_softc {
struct atapi_softc *atp; /* Controller structure */
int32_t lun; /* Logical device unit */
int32_t flags; /* Device state flags */
int32_t refcnt; /* The number of raw opens */
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
int32_t refcnt; /* the number of raw opens */
struct buf_queue_head buf_queue; /* Queue of i/o requests */
struct toc toc; /* Table of disc contents */
struct toc toc; /* table of disc contents */
struct {
u_int32_t volsize; /* Volume size in blocks */
u_int32_t blksize; /* Block size in bytes */
} info;
struct audiopage au; /* Audio page info */
struct cappage cap; /* Capabilities page info */
struct audiopage aumask; /* Audio page mask */
struct { /* Subchannel info */
u_int8_t void0;
u_int8_t audio_status;
u_int16_t data_length;
u_int8_t data_format;
u_int8_t control;
u_int8_t track;
u_int8_t indx;
u_int32_t abslba;
u_int32_t rellba;
u_int32_t volsize; /* volume size in blocks */
u_int32_t blksize; /* block size in bytes */
} info;
struct audiopage au; /* audio page info */
struct cappage cap; /* capabilities page info */
struct audiopage aumask; /* audio page mask */
struct { /* subchannel info */
u_int8_t void0;
u_int8_t audio_status;
u_int16_t data_length;
u_int8_t data_format;
u_int8_t control;
u_int8_t track;
u_int8_t indx;
u_int32_t abslba;
u_int32_t rellba;
} subchan;
struct changer *changer_info; /* Changer info */
int32_t slot; /* This lun's slot number */
u_int32_t block_size; /* Blocksize currently used */
u_int8_t dummy; /* Use dummy writes */
u_int8_t speed; /* Select drive speed */
u_int32_t next_writeable_lba; /* Next writable position */
struct wormio_prepare_track preptrack; /* Scratch region */
struct changer *changer_info; /* changer info */
int32_t slot; /* this lun's slot number */
u_int32_t block_size; /* blocksize currently used */
u_int8_t dummy; /* use dummy writes */
u_int8_t speed; /* select drive speed */
u_int32_t next_writeable_lba; /* next writable position */
struct wormio_prepare_track preptrack; /* scratch region */
struct devstat *stats; /* devstat entry */
#ifdef DEVFS
void *ra_devfs_token;
void *rc_devfs_token;
void *a_devfs_token;
void *c_devfs_token;
void *a_cdevfs_token;
void *c_cdevfs_token;
void *a_bdevfs_token;
void *c_bdevfs_token;
#endif
};
#define CDRIOCBLANK _IO('c',100) /* Blank a CDRW disc */
#define CDRIOCBLANK _IO('c',100) /* blank a CDRW disc */
#define CDRIOCNEXTWRITEABLEADDR _IOR('c',101,int)

434
sys/dev/ata/atapi-fd.c Normal file
View File

@ -0,0 +1,434 @@
/*-
* Copyright (c) 1998,1999 Søren Schmidt
* All rights reserved.
*
* 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,
* without modification, immediately at the beginning of the file.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$
*/
#include "ata.h"
#include "atapifd.h"
#include "opt_devfs.h"
#if NATA > 0 && NATAPIFD > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/diskslice.h>
#include <sys/devicestat.h>
#include <sys/cdio.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/stat.h>
#ifdef DEVFS
#include <sys/devfsext.h>
#endif
#include <dev/ata/ata-all.h>
#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-fd.h>
static d_open_t afdopen;
static d_close_t afdclose;
static d_read_t afdread;
static d_write_t afdwrite;
static d_ioctl_t afdioctl;
static d_strategy_t afdstrategy;
#define CDEV_MAJOR 87
#define BDEV_MAJOR 1
static struct cdevsw afd_cdevsw = {
afdopen, afdclose, afdread, afdwrite,
afdioctl, nostop, nullreset, nodevtotty,
seltrue, nommap, afdstrategy, "afd",
NULL, -1 };
#define NUNIT 8
#define UNIT(d) ((minor(d) >> 3) & 3)
#define F_OPEN 0x0001 /* The device is opened */
#define F_MEDIA_CHANGED 0x0002 /* The media have changed */
static struct afd_softc *afdtab[NUNIT]; /* Drive info by unit number */
static int32_t afdnlun = 0; /* Number of config'd drives */
int32_t afdattach(struct atapi_softc *);
static int32_t afd_sense(struct afd_softc *);
static void afd_describe(struct afd_softc *);
static void afd_strategy(struct buf *);
static void afd_start(struct afd_softc *);
static void afd_done(struct atapi_request *);
static int32_t afd_start_device(struct afd_softc *, int32_t);
static int32_t afd_lock_device(struct afd_softc *, int32_t);
static int32_t afd_eject(struct afd_softc *, int32_t);
static void afd_drvinit(void *);
int32_t
afdattach(struct atapi_softc *atp)
{
struct afd_softc *fdp;
if (afdnlun >= NUNIT) {
printf("afd: too many units\n");
return -1;
}
fdp = malloc(sizeof(struct afd_softc), M_TEMP, M_NOWAIT);
if (!fdp) {
printf("afd: out of memory\n");
return -1;
}
bzero(fdp, sizeof(struct afd_softc));
bufq_init(&fdp->buf_queue);
fdp->atp = atp;
fdp->lun = afdnlun;
fdp->flags = F_MEDIA_CHANGED;
if (afd_sense(fdp)) {
free(fdp, M_TEMP);
return -1;
}
afd_describe(fdp);
afdtab[afdnlun++] = fdp;
devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
0x178);
#ifdef DEVFS
fdp->cdevs_token = devfs_add_devswf(&afd_cdevsw, dkmakeminor(fdp->lun, 0,0),
DV_CHR, UID_ROOT, GID_OPERATOR,
0640, "rafd%d", fdp->lun);
fdp->bdevs_token = devfs_add_devswf(&afd_cdevsw, dkmakeminor(fdp->lun, 0,0),
DV_BLK, UID_ROOT, GID_OPERATOR,
0640, "afd%d", fdp->lun);
#endif
return 0;
}
static int32_t
afd_sense(struct afd_softc *fdp)
{
int32_t error, count;
int8_t buffer[256];
int8_t ccb[16] = { ATAPI_MODE_SENSE, 0, ATAPI_REWRITEABLE_CAP_PAGE,
0, 0, 0, 0, sizeof(buffer)>>8, sizeof(buffer) & 0xff,
0, 0, 0, 0, 0, 0, 0 };
bzero(buffer, sizeof(buffer));
/* Get drive capabilities, some drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
if (!(error = atapi_queue_cmd(fdp->atp, ccb, buffer, sizeof(buffer),
A_READ, NULL, NULL, NULL)))
break;
}
#ifdef AFD_DEBUG
atapi_dump("afd: sense", buffer, sizeof(buffer));
#endif
if (error)
return error;
bcopy(buffer, &fdp->header, sizeof(struct afd_header));
bcopy(buffer+sizeof(struct afd_header), &fdp->cap,
sizeof(struct afd_cappage));
if (fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
return 1;
fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
return 0;
}
static void
afd_describe(struct afd_softc *fdp)
{
int8_t model_buf[40+1];
int8_t revision_buf[8+1];
bpack(fdp->atp->atapi_parm->model, model_buf, sizeof(model_buf));
bpack(fdp->atp->atapi_parm->revision, revision_buf, sizeof(revision_buf));
printf("afd%d: <%s/%s> rewriteable drive at ata%d as %s\n",
fdp->lun, model_buf, revision_buf,
fdp->atp->controller->unit,
(fdp->atp->unit == ATA_MASTER) ? "master" : "slave ");
printf("afd%d: %luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
afdnlun,
(fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
((1024L * 1024L) / fdp->cap.sector_size),
fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
fdp->cap.sector_size);
printf("afd%d: ", fdp->lun);
switch (fdp->header.medium_type) {
default: printf("Unknown media (0x%x)", fdp->header.medium_type);
}
if (fdp->header.wp) printf(", writeprotected");
printf("\n");
}
static int32_t
afdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
struct afd_softc *fdp;
struct disklabel label;
int32_t lun = UNIT(dev);
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
fdp->flags &= ~F_MEDIA_CHANGED;
afd_lock_device(fdp, 1);
if (afd_sense(fdp))
printf("afd%d: sense media type failed\n", fdp->lun);
/* build disklabel and initilize slice tables */
bzero(&label, sizeof label);
label.d_secsize = fdp->cap.sector_size;
label.d_nsectors = fdp->cap.sectors;
label.d_ntracks = fdp->cap.heads;
label.d_ncylinders = fdp->cap.cylinders;
label.d_secpercyl = fdp->cap.heads * fdp->cap.sectors;
label.d_secperunit = fdp->cap.heads * fdp->cap.sectors * fdp->cap.cylinders;
/* Initialize slice tables. */
return dsopen("afd", dev, fmt, 0, &fdp->slices, &label, afd_strategy,
(ds_setgeom_t *)NULL, &afd_cdevsw);
}
static int32_t
afdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct afd_softc *fdp;
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
dsclose(dev, fmt, fdp->slices);
if(!dsisopen(fdp->slices))
afd_lock_device(fdp, 0);
return 0;
}
static int32_t
afdread(dev_t dev, struct uio *uio, int32_t ioflag)
{
return physio(afdstrategy, NULL, dev, 1, minphys, uio);
}
static int32_t
afdwrite(dev_t dev, struct uio *uio, int32_t ioflag)
{
return physio(afdstrategy, NULL, dev, 0, minphys, uio);
}
static int32_t
afdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
int32_t lun = UNIT(dev);
int32_t error = 0;
struct afd_softc *fdp;
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
switch (cmd) {
case CDIOCEJECT:
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return EBUSY;
return afd_eject(fdp, 0);
case CDIOCCLOSE:
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return 0;
return afd_eject(fdp, 1);
default:
return ENOTTY;
}
return error;
}
static void
afdstrategy(struct buf *bp)
{
int32_t lun = UNIT(bp->b_dev);
struct afd_softc *fdp = afdtab[lun];
int32_t x;
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
if (dscheck(bp, fdp->slices) <= 0) {
x = splbio();
biodone(bp);
splx(x);
return;
}
x = splbio();
bufq_insert_tail(&fdp->buf_queue, bp);
afd_start(fdp);
splx(x);
}
static void
afd_strategy(struct buf *bp)
{
afdstrategy(bp);
}
static void
afd_start(struct afd_softc *fdp)
{
struct buf *bp = bufq_first(&fdp->buf_queue);
u_int32_t lba, count;
int8_t ccb[16];
if (!bp)
return;
bzero(ccb, sizeof(ccb));
bufq_remove(&fdp->buf_queue, bp);
/* Should reject all queued entries if media have changed. */
if (fdp->flags & F_MEDIA_CHANGED) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
lba = bp->b_blkno / (fdp->cap.sector_size / DEV_BSIZE);
count = (bp->b_bcount + (fdp->cap.sector_size - 1)) / fdp->cap.sector_size;
if (bp->b_flags & B_READ)
ccb[0] = ATAPI_READ_BIG;
else
ccb[0] = ATAPI_WRITE_BIG;
ccb[1] = 0;
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = count>>8;
ccb[8] = count;
devstat_start_transaction(&fdp->stats);
atapi_queue_cmd(fdp->atp, ccb, bp->b_data, bp->b_bcount,
(bp->b_flags & B_READ) ? A_READ : 0, afd_done, fdp, bp);
}
static void
afd_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct afd_softc *fdp = request->driver;
devstat_end_transaction(&fdp->stats, bp->b_bcount-request->bytecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
printf("afd_done: ");
atapi_error(request->device, request->result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
else
bp->b_resid = request->bytecount;
biodone(bp);
afd_start(fdp);
}
static int32_t
afd_start_device(struct afd_softc *fdp, int32_t start)
{
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL);
}
static int32_t
afd_lock_device(struct afd_softc *fdp, int32_t lock)
{
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL);
}
static int32_t
afd_eject(struct afd_softc *fdp, int32_t close)
{
int32_t error;
error = afd_start_device(fdp, 0);
if ((error & ATAPI_SK_MASK) &&
((error & ATAPI_SK_MASK) == ATAPI_SK_NOT_READY ||
(error & ATAPI_SK_MASK) == ATAPI_SK_UNIT_ATTENTION)) {
if (!close)
return 0;
if ((error = afd_start_device(fdp, 3)))
return error;
afd_lock_device(fdp, 1);
return 0;
}
if (error) {
atapi_error(fdp->atp, error);
return EIO;
}
if (close)
return 0;
tsleep((caddr_t) &lbolt, PRIBIO, "afdej1", 0);
tsleep((caddr_t) &lbolt, PRIBIO, "afdej2", 0);
afd_lock_device(fdp, 0);
fdp->flags |= F_MEDIA_CHANGED;
return afd_start_device(fdp, 2);
}
static void
afd_drvinit(void *unused)
{
static afd_devsw_installed = 0;
if (!afd_devsw_installed) {
cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &afd_cdevsw);
afd_devsw_installed = 1;
}
}
SYSINIT(afddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, afd_drvinit, NULL)
#endif /* NATA & NATAPIFD */

90
sys/dev/ata/atapi-fd.h Normal file
View File

@ -0,0 +1,90 @@
/*-
* Copyright (c) 1998,1999 Søren Schmidt
* All rights reserved.
*
* 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,
* without modification, immediately at the beginning of the file.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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$
*/
/* MODE SENSE parameter header */
struct afd_header {
u_int16_t data_length;
u_int8_t medium_type;
#define MFD_2DD_UN 0x10
#define MFD_2DD 0x11
#define MFD_2HD_UN 0x20
#define MFD_2HD_12_98 0x22
#define MFD_2HD_12 0x23
#define MFD_2HD_144 0x24
#define MFD_LS120 0x31
#define MFD_UNKNOWN 0x00
#define MFD_NO_DISC 0x70
#define MFD_DOOR_OPEN 0x71
#define MFD_FMT_ERROR 0x72
u_int8_t reserved0 :7;
u_int8_t wp :1; /* write protect */
u_int8_t unused[4];
};
/* ATAPI Rewriteable drive Capabilities and Mechanical Status Page */
#define ATAPI_REWRITEABLE_CAP_PAGE 0x05
struct afd_cappage {
u_int8_t page_code :6;
u_int8_t reserved1_6 :1;
u_int8_t ps :1; /* page save supported */
u_int8_t page_length; /* page length */
u_int16_t transfer_rate; /* in kilobits per second */
u_int8_t heads; /* number of heads */
u_int8_t sectors; /* number of sectors per track */
u_int16_t sector_size; /* number of bytes per sector */
u_int16_t cylinders; /* number of cylinders */
u_int8_t reserved10[10];
u_int8_t motor_delay; /* motor off delay */
u_int8_t reserved21[7];
u_int16_t rpm; /* rotations per minute */
u_int8_t reserved30[2];
};
struct afd_softc {
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
int32_t refcnt; /* the number of raw opens */
int32_t maxblks; /* transfer size limit */
struct buf_queue_head buf_queue; /* queue of i/o requests */
struct afd_header header; /* capabilities page info */
struct afd_cappage cap; /* capabilities page info */
struct diskslices *slices; /* virtual drives */
struct devstat stats;
#ifdef DEVFS
void *cdevs_token;
void *bdevs_token;
#endif
};

View File

@ -25,7 +25,7 @@
* (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: atapi-tape.c,v 1.5 1999/03/01 21:03:15 sos Exp sos $
* $Id: atapi-tape.c,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
#include "ata.h"
@ -41,6 +41,7 @@
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/mtio.h>
#include <sys/disklabel.h>
#include <sys/devicestat.h>
#ifdef DEVFS
#include <sys/devfsext.h>
@ -50,21 +51,21 @@
#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-tape.h>
static d_open_t astopen;
static d_read_t astread;
static d_write_t astwrite;
static d_close_t astclose;
static d_ioctl_t astioctl;
static d_strategy_t aststrategy;
static d_open_t astopen;
static d_close_t astclose;
static d_read_t astread;
static d_write_t astwrite;
static d_ioctl_t astioctl;
static d_strategy_t aststrategy;
#define CDEV_MAJOR 90
#define BDEV_MAJOR 24
static struct cdevsw ast_cdevsw = {
astopen, astclose, astread, astwrite,
astioctl, nostop, nullreset, nodevtotty,
seltrue, nommap, aststrategy, "ast",
NULL, -1 };
astopen, astclose, astread, astwrite,
astioctl, nostop, nullreset, nodevtotty,
seltrue, nommap, aststrategy, "ast",
NULL, -1 };
static u_int32_t ast_total = 0;
@ -123,12 +124,11 @@ astattach(struct atapi_softc *atp)
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
0x178);
#ifdef DEVFS
t->cdevs = devfs_add_devswf(&ast_cdevsw, 0, DV_CHR, UID_ROOT, GID_OPERATOR,
0640, "rast%d", t->lun);
#endif /* DEVFS */
stp->cdevs_token = devfs_add_devswf(&ast_cdevsw, dkmakeminor(stp->lun, 0,0),
DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
"rast%d", stp->lun);
#endif
return 0;
}
@ -209,14 +209,14 @@ ast_describe(struct ast_softc *stp)
printf("\n");
}
int
static int32_t
astopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct ast_softc *stp;
if (lun >= astnlun || !(stp = asttab[lun]))
return(ENXIO);
return ENXIO;
if (stp->flags == F_OPEN)
return EBUSY;
if (ast_sense(stp))
@ -225,17 +225,17 @@ astopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
stp->flags |= F_OPEN;
ast_total = 0;
return(0);
return 0;
}
int32_t
static int32_t
astclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct ast_softc *stp;
if (lun >= astnlun || !(stp = asttab[lun]))
return(ENXIO);
return ENXIO;
/* Flush buffers, some drives fail here, but they should report ctl = 0 */
if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
@ -254,111 +254,22 @@ astclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
printf("ast%d: %ud total bytes transferred\n", stp->lun, ast_total);
#endif
stp->flags &= ~F_CTL_WARN;
return(0);
return 0;
}
static int
static int32_t
astread(dev_t dev, struct uio *uio, int32_t ioflag)
{
return (physio(aststrategy, NULL, dev, 1, minphys, uio));
return physio(aststrategy, NULL, dev, 1, minphys, uio);
}
static int
static int32_t
astwrite(dev_t dev, struct uio *uio, int32_t ioflag)
{
return (physio(aststrategy, NULL, dev, 0, minphys, uio));
return physio(aststrategy, NULL, dev, 0, minphys, uio);
}
void
aststrategy(struct buf *bp)
{
int32_t lun = UNIT(bp->b_dev);
struct ast_softc *stp = asttab[lun];
int32_t x;
/* If it's a null transfer, return immediatly. */
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
/* Check for != blocksize requests */
if (bp->b_bcount % stp->blksize) {
printf("ast%d: bad request, must be multiple of %d\n",
lun, stp->blksize);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
if (bp->b_bcount > stp->blksize * stp->cap.ctl) {
if ((stp->flags & F_CTL_WARN) == 0) {
printf("ast%d: WARNING: CTL exceeded %ld>%d\n",
lun, bp->b_bcount, stp->blksize * stp->cap.ctl);
stp->flags |= F_CTL_WARN;
}
}
x = splbio();
ast_total += bp->b_bcount;
bufq_insert_tail(&stp->buf_queue, bp);
ast_start(stp);
splx(x);
}
static void
ast_start(struct ast_softc *stp)
{
struct buf *bp = bufq_first(&stp->buf_queue);
u_long blkcount;
int8_t ccb[16];
if (!bp)
return;
bzero(ccb, sizeof(ccb));
bufq_remove(&stp->buf_queue, bp);
blkcount = bp->b_bcount / stp->blksize;
if (bp->b_flags & B_READ) {
ccb[0] = ATAPI_TAPE_READ_CMD;
} else {
ccb[0] = ATAPI_TAPE_WRITE_CMD;
stp->flags |= F_DATA_WRITTEN;
}
ccb[1] = 1;
ccb[2] = blkcount>>16;
ccb[3] = blkcount>>8;
ccb[4] = blkcount;
devstat_start_transaction(&stp->stats);
atapi_queue_cmd(stp->atp, ccb, bp->b_data, bp->b_bcount,
(bp->b_flags & B_READ) ? A_READ : 0, ast_done, stp, bp);
}
static void
ast_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct ast_softc *stp = request->driver;
devstat_end_transaction(&stp->stats, bp->b_bcount-request->bytecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
printf("ast_done: ");
atapi_error(request->device, request->result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
else
bp->b_resid = request->bytecount;
biodone(bp);
ast_start(stp);
}
int32_t
static int32_t
astioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
int32_t lun = UNIT(dev);
@ -444,12 +355,100 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
return error;
}
default:
return(ENOTTY);
return ENOTTY;
}
return(error);
return error;
}
static int
static void
aststrategy(struct buf *bp)
{
int32_t lun = UNIT(bp->b_dev);
struct ast_softc *stp = asttab[lun];
int32_t x;
/* If it's a null transfer, return immediatly. */
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
/* Check for != blocksize requests */
if (bp->b_bcount % stp->blksize) {
printf("ast%d: bad request, must be multiple of %d\n",
lun, stp->blksize);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
if (bp->b_bcount > stp->blksize * stp->cap.ctl) {
if ((stp->flags & F_CTL_WARN) == 0) {
printf("ast%d: WARNING: CTL exceeded %ld>%d\n",
lun, bp->b_bcount, stp->blksize * stp->cap.ctl);
stp->flags |= F_CTL_WARN;
}
}
x = splbio();
ast_total += bp->b_bcount;
bufq_insert_tail(&stp->buf_queue, bp);
ast_start(stp);
splx(x);
}
static void
ast_start(struct ast_softc *stp)
{
struct buf *bp = bufq_first(&stp->buf_queue);
u_int32_t blkcount;
int8_t ccb[16];
if (!bp)
return;
bzero(ccb, sizeof(ccb));
bufq_remove(&stp->buf_queue, bp);
blkcount = bp->b_bcount / stp->blksize;
if (bp->b_flags & B_READ) {
ccb[0] = ATAPI_TAPE_READ_CMD;
} else {
ccb[0] = ATAPI_TAPE_WRITE_CMD;
stp->flags |= F_DATA_WRITTEN;
}
ccb[1] = 1;
ccb[2] = blkcount>>16;
ccb[3] = blkcount>>8;
ccb[4] = blkcount;
devstat_start_transaction(&stp->stats);
atapi_queue_cmd(stp->atp, ccb, bp->b_data, bp->b_bcount,
(bp->b_flags & B_READ) ? A_READ : 0, ast_done, stp, bp);
}
static void
ast_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct ast_softc *stp = request->driver;
devstat_end_transaction(&stp->stats, bp->b_bcount-request->bytecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
atapi_error(request->device, request->result);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
}
else
bp->b_resid = request->bytecount;
biodone(bp);
ast_start(stp);
}
static int32_t
ast_space_cmd(struct ast_softc *stp, u_int8_t function, u_int32_t count)
{
int32_t error;
@ -463,14 +462,13 @@ ast_space_cmd(struct ast_softc *stp, u_int8_t function, u_int32_t count)
ccb[4] = count;
if ((error = atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL))){
printf("ast_space_cmd: ");
atapi_error(stp->atp, error);
return EIO;
}
return 0;
}
static int
static int32_t
ast_write_filemark(struct ast_softc *stp, u_int8_t function)
{
int32_t error;
@ -487,14 +485,13 @@ ast_write_filemark(struct ast_softc *stp, u_int8_t function)
ccb[4] = function;
if ((error = atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL))){
printf("ast_write_filemark: ");
atapi_error(stp->atp, error);
return EIO;
}
return 0;
}
static int
static int32_t
ast_load_unload(struct ast_softc *stp, u_int8_t function)
{
int32_t error;
@ -505,14 +502,13 @@ ast_load_unload(struct ast_softc *stp, u_int8_t function)
ccb[4] = function;
if ((error = atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL))){
printf("ast_load_unload: ");
atapi_error(stp->atp, error);
return EIO;
}
return 0;
}
static int
static int32_t
ast_erase(struct ast_softc *stp)
{
int32_t error;
@ -526,14 +522,13 @@ ast_erase(struct ast_softc *stp)
ccb[1] = 3;
if ((error = atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL))){
printf("ast_erase: ");
atapi_error(stp->atp, error);
return EIO;
}
return 0;
}
static int
static int32_t
ast_rewind(struct ast_softc *stp)
{
int32_t error;
@ -543,7 +538,6 @@ ast_rewind(struct ast_softc *stp)
ccb[0] = ATAPI_TAPE_REWIND;
if ((error = atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, NULL, NULL, NULL))){
printf("ast_rewind: ");
atapi_error(stp->atp, error);
return EIO;
}

View File

@ -1,3 +1,32 @@
/*-
* Copyright (c) 1998,1999 Søren Schmidt
* All rights reserved.
*
* 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,
* without modification, immediately at the beginning of the file.
* 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. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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: atapi-tape.h,v 1.1 1999/03/01 21:19:18 sos Exp $
*/
/* ATAPI tape commands not in std ATAPI command set */
#define ATAPI_TAPE_REWIND 0x01
@ -18,95 +47,89 @@
#define DSC_POLL_INTERVAL 10
/*
* MODE SENSE parameter header
*/
/* MODE SENSE parameter header */
struct ast_header {
u_int8_t data_length; /* Total length of data */
u_int8_t medium_type; /* Medium type (if any) */
u_int8_t dsp; /* Device specific parameter */
u_int8_t bdl; /* Block Descriptor Length */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t dsp; /* device specific parameter */
u_int8_t bdl; /* block Descriptor Length */
};
/*
* ATAPI tape drive Capabilities and Mechanical Status Page
*/
/* ATAPI tape drive Capabilities and Mechanical Status Page */
#define ATAPI_TAPE_CAP_PAGE 0x2a
struct ast_cappage {
u_int8_t page_code :6; /* Page code == 0x2a */
u_int8_t page_code :6; /* page code == 0x2a */
u_int8_t reserved1_67 :2;
u_int8_t page_length; /* Page Length == 0x12 */
u_int8_t page_length; /* page Length == 0x12 */
u_int8_t reserved2;
u_int8_t reserved3;
u_int8_t readonly :1; /* Read Only Mode */
u_int8_t readonly :1; /* read Only Mode */
u_int8_t reserved4_1234 :4;
u_int8_t reverse :1; /* Supports reverse direction */
u_int8_t reverse :1; /* supports reverse direction */
u_int8_t reserved4_67 :2;
u_int8_t reserved5_012 :3;
u_int8_t eformat :1; /* Supports ERASE formatting */
u_int8_t eformat :1; /* supports ERASE formatting */
u_int8_t reserved5_4 :1;
u_int8_t qfa :1; /* Supports QFA formats */
u_int8_t qfa :1; /* supports QFA formats */
u_int8_t reserved5_67 :2;
u_int8_t lock :1; /* Supports locking media */
u_int8_t locked :1; /* The media is locked */
u_int8_t prevent :1; /* Defaults to prevent state */
u_int8_t eject :1; /* Supports eject */
u_int8_t disconnect :1; /* Can break request > ctl */
u_int8_t lock :1; /* supports locking media */
u_int8_t locked :1; /* the media is locked */
u_int8_t prevent :1; /* defaults to prevent state */
u_int8_t eject :1; /* supports eject */
u_int8_t disconnect :1; /* can break request > ctl */
u_int8_t reserved6_5 :1;
u_int8_t ecc :1; /* Supports error correction */
u_int8_t compress :1; /* Supports data compression */
u_int8_t ecc :1; /* supports error correction */
u_int8_t compress :1; /* supports data compression */
u_int8_t reserved7_0 :1;
u_int8_t blk512 :1; /* Supports 512b block size */
u_int8_t blk1024 :1; /* Supports 1024b block size */
u_int8_t blk512 :1; /* supports 512b block size */
u_int8_t blk1024 :1; /* supports 1024b block size */
u_int8_t reserved7_3456 :4;
u_int8_t slowb :1; /* Restricts byte count */
u_int16_t max_speed; /* Supported speed in KBps */
u_int16_t max_defects; /* Max stored defect entries */
u_int16_t ctl; /* Continuous Transfer Limit */
u_int16_t speed; /* Current Speed, in KBps */
u_int16_t buffer_size; /* Buffer Size, in 512 bytes */
u_int8_t slowb :1; /* restricts byte count */
u_int16_t max_speed; /* supported speed in KBps */
u_int16_t max_defects; /* max stored defect entries */
u_int16_t ctl; /* continuous transfer limit */
u_int16_t speed; /* current Speed, in KBps */
u_int16_t buffer_size; /* buffer Size, in 512 bytes */
u_int8_t reserved18;
u_int8_t reserved19;
};
/*
* REQUEST SENSE structure
*/
/* REQUEST SENSE structure */
struct ast_reqsense {
u_int8_t error_code :7; /* Current or deferred errors */
u_int8_t valid :1; /* Follows QIC-157C */
u_int8_t reserved1; /* Segment Number - Reserved */
u_int8_t sense_key :4; /* Sense Key */
u_int8_t reserved2_4 :1; /* Reserved */
u_int8_t ili :1; /* Incorrect Length Indicator */
u_int8_t eom :1; /* End Of Medium */
u_int8_t filemark :1; /* Filemark */
u_int8_t info __attribute__((packed)); /* Cmd specific info */
u_int8_t asl; /* Additional sense length (n-7) */
u_int8_t command_specific; /* Additional cmd specific info */
u_int8_t asc; /* Additional Sense Code */
u_int8_t ascq; /* Additional Sense Code Qualifier */
u_int8_t replaceable_unit_code; /* Field Replaceable Unit Code */
u_int8_t sk_specific1 :7; /* Sense Key Specific */
u_int8_t sksv :1; /* Sense Key Specific info valid */
u_int8_t sk_specific2; /* Sense Key Specific */
u_int8_t sk_specific3; /* Sense Key Specific */
u_int8_t pad[2]; /* Padding */
u_int8_t error_code :7; /* current or deferred errors */
u_int8_t valid :1; /* follows QIC-157C */
u_int8_t reserved1; /* Segment number - reserved */
u_int8_t sense_key :4; /* sense key */
u_int8_t reserved2_4 :1; /* reserved */
u_int8_t ili :1; /* incorrect length indicator */
u_int8_t eom :1; /* end of medium */
u_int8_t filemark :1; /* filemark */
u_int8_t info __attribute__((packed)); /* cmd specific info */
u_int8_t asl; /* additional sense length (n-7) */
u_int8_t command_specific; /* additional cmd specific info */
u_int8_t asc; /* additional sense code */
u_int8_t ascq; /* additional sense code qualifier */
u_int8_t replaceable_unit_code; /* field replaceable unit code */
u_int8_t sk_specific1 :7; /* sense key specific */
u_int8_t sksv :1; /* sense key specific info valid */
u_int8_t sk_specific2; /* sense key specific */
u_int8_t sk_specific3; /* sense key Specific */
u_int8_t pad[2]; /* padding */
};
struct ast_softc {
struct atapi_softc *atp; /* Controller structure */
int32_t lun; /* Logical device unit */
int32_t flags; /* Device state flags */
int32_t blksize; /* Block size (512 | 1024) */
struct buf_queue_head buf_queue; /* Queue of i/o requests */
struct atapi_params *param; /* Drive parameters table */
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
int32_t blksize; /* block size (512 | 1024) */
struct buf_queue_head buf_queue; /* queue of i/o requests */
struct atapi_params *param; /* drive parameters table */
struct ast_header header; /* MODE SENSE param header */
struct ast_cappage cap; /* Capabilities page info */
struct ast_cappage cap; /* capabilities page info */
struct devstat stats; /* devstat entry */
#ifdef DEVFS
void *cdevs;
void *bdevs;
void *cdevs_token;
void *bdevs_token;
#endif
};