Finally!!
The much roumored replacement for our current IDE/ATA/ATAPI is materialising in the CVS repositories around the globe. So what does this bring us: A new reengineered ATA/ATAPI subsystem, that tries to overcome most of the deficiencies with the current drivers. It supports PCI as well as ISA devices without all the hackery in ide_pci.c to make PCI devices look like ISA counterparts. It doesn't have the excessive wait problem on probe, in fact you shouldn't notice any delay when your devices are getting probed. Probing and attaching of devices are postponed until interrupts are enabled (well almost, not finished yet for disks), making things alot cleaner. Improved performance, although DMA support is still WIP and not in this pre alpha release, worldstone is faster with the new driver compared to the old even with DMA. So what does it take away: There is NO support for old MFM/RLL/ESDI disks. There is NO support for bad144, if your disk is bad, ditch it, it has already outgrown its internal spare sectors, and is dying. For you to try this out, you will have to modify your kernel config file to use the "ata" controller instead of all wdc? entries. example: # for a PCI only system (most modern machines) controller ata0 device atadisk0 # ATA disks device atapicd0 # ATAPI CDROM's device atapist0 # ATAPI tapes #You should add the following on ISA systems: controller ata1 at isa? port "IO_WD1" bio irq 14 controller ata2 at isa? port "IO_WD2" bio irq 15 You can leave it all in there, the system knows how to manage. For now this driver reuses the device entries from the old system (that will probably change later), but remember that disks are now numbered in the sequence they are found (like the SCSI system) not as absolute positions as the old system. Although I have tested this on all the systems I can get my hands on, there might very well be gremlins in there, so use AT YOU OWN RISK!! This is still WIP, so there are lots of rough edges and unfinished things in there, and what I have in my lab might look very different from whats in CVS at any given time. So please have all eventual changes go through me, or chances are they just dissapears... I would very much like to hear from you, both good and bad news are very welcome. Enjoy!! -Søren
This commit is contained in:
parent
eff50fcd4c
commit
8b89ef0a2d
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.559 1999/02/21 16:23:23 n_hibma Exp $
|
||||
# $Id: LINT,v 1.560 1999/02/22 18:19:57 des Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -1006,6 +1006,24 @@ controller aha0 at isa? port ? cam irq ?
|
||||
|
||||
#!CAM# controller aic0 at isa? port 0x340 bio irq 11
|
||||
|
||||
#
|
||||
# ATA and ATAPI devices
|
||||
# This is work in progress, use at your own risk.
|
||||
# It currently reuses the majors of wd.c and freinds.
|
||||
# It cannot co-exist with the old system in one kernel.
|
||||
# You only need one "controller ata0" for it to find all
|
||||
# PCI devices on modern machines.
|
||||
#controller ata0
|
||||
#device atadisk0 # ATA disk drives
|
||||
#device atapicd0 # ATAPI CDROM drives
|
||||
#device atapist0 # ATAPI tape drives
|
||||
#
|
||||
# If you need ISA only devices, this is the lines to add:
|
||||
#controller ata1 at isa? port "IO_WD1" bio irq 14
|
||||
#controller ata2 at isa? port "IO_WD2" bio irq 15
|
||||
#
|
||||
# All the controller lines can coexist, the driver will
|
||||
# find out which ones are there.
|
||||
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
|
@ -1,7 +1,7 @@
|
||||
# This file tells config what files go into building a kernel,
|
||||
# files marked standard are always included.
|
||||
#
|
||||
# $Id: files.i386,v 1.222 1999/02/11 07:11:00 gibbs Exp $
|
||||
# $Id: files.i386,v 1.223 1999/02/20 11:17:59 julian Exp $
|
||||
#
|
||||
# The long compile-with and dependency lines are required because of
|
||||
# limitations in config: backslash-newline doesn't work in strings, and
|
||||
@ -24,6 +24,11 @@ font8x16.o optional std8x16font \
|
||||
no-implicit-rule before-depend \
|
||||
clean "${STD8X16FONT}-8x16 font8x16.c"
|
||||
#
|
||||
dev/ata/ata-all.c optional ata device-driver
|
||||
dev/ata/atapi-all.c optional ata device-driver
|
||||
dev/ata/ata-disk.c optional atadisk device-driver
|
||||
dev/ata/atapi-cd.c optional atapicd device-driver
|
||||
dev/ata/atapi-tape.c optional atapist device-driver
|
||||
dev/fb/fb.c optional fb device-driver
|
||||
dev/fb/fb.c optional vga device-driver
|
||||
dev/fb/splash.c optional splash
|
||||
|
658
sys/dev/ata/ata-all.c
Normal file
658
sys/dev/ata/ata-all.c
Normal file
@ -0,0 +1,658 @@
|
||||
/*-
|
||||
* 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: ata-all.c,v 1.4 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
#include "ata.h"
|
||||
#if NATA > 0
|
||||
#include "pci.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <machine/clock.h>
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
#include <i386/isa/icu.h>
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/ata/ata-all.h>
|
||||
#include <dev/ata/ata-disk.h>
|
||||
#include <dev/ata/atapi-all.h>
|
||||
|
||||
/* misc defines */
|
||||
#define UNIT(dev) (dev>>3 & 0x1f) /* assume 8 minor # per unit */
|
||||
|
||||
/* prototypes */
|
||||
void ataintr(int32_t);
|
||||
static int32_t ata_isaprobe(struct isa_device *);
|
||||
static int32_t ata_isaattach(struct isa_device *);
|
||||
static const char *ata_pciprobe(pcici_t, pcidi_t);
|
||||
static void ata_pciattach(pcici_t, int32_t);
|
||||
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 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;
|
||||
struct ata_softc *atadevices[MAXATA];
|
||||
struct isa_driver atadriver = { ata_isaprobe, ata_isaattach, "ata" };
|
||||
|
||||
static int32_t
|
||||
ata_isaprobe(struct isa_device *devp)
|
||||
{
|
||||
int32_t ctlr, res;
|
||||
|
||||
for (ctlr = 0; ctlr < atanlun; ctlr++) {
|
||||
if (atadevices[ctlr]->ioaddr == devp->id_iobase) {
|
||||
printf("ata-isa%d: already registered as ata%d\n",
|
||||
devp->id_unit, ctlr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
res=ata_probe(devp->id_iobase, devp->id_iobase+ATA_ALTPORT, &devp->id_unit);
|
||||
if (res)
|
||||
devp->id_intr = ataintr;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ata_isaattach(struct isa_device *devp)
|
||||
{
|
||||
return ata_attach(devp->id_unit);
|
||||
}
|
||||
|
||||
static u_long ata_pcicount;
|
||||
static struct pci_device ata_pcidevice = {
|
||||
"ata-pci", ata_pciprobe, ata_pciattach, &ata_pcicount, 0
|
||||
};
|
||||
|
||||
DATA_SET(pcidevice_set, ata_pcidevice);
|
||||
|
||||
static const char *
|
||||
ata_pciprobe(pcici_t tag, pcidi_t type)
|
||||
{
|
||||
u_int32_t data;
|
||||
|
||||
data = pci_conf_read(tag, PCI_CLASS_REG);
|
||||
if ((data & PCI_CLASS_MASK) == PCI_CLASS_MASS_STORAGE &&
|
||||
((data & PCI_SUBCLASS_MASK) == 0x00010000 ||
|
||||
((data & PCI_SUBCLASS_MASK) == 0x00040000))) {
|
||||
switch (type) {
|
||||
case 0x71118086:
|
||||
return "Intel PIIX4 IDE controller";
|
||||
case 0x70108086:
|
||||
return "Intel PIIX3 IDE controller";
|
||||
case 0x12308086:
|
||||
return "Intel PIIX IDE controller";
|
||||
case 0x4d33105a:
|
||||
return "Promise Ultra/33 IDE controller";
|
||||
case 0x05711106:
|
||||
return "VIA Apollo IDE controller";
|
||||
case 0x01021078:
|
||||
return "Cyrix 5530 IDE controller";
|
||||
case 0x522910b9:
|
||||
return "Acer Aladdin IV/V IDE controller";
|
||||
default:
|
||||
return ("Unknown PCI IDE controller");
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ata_pciattach(pcici_t tag, int32_t unit)
|
||||
{
|
||||
pcidi_t type, class, cmd;
|
||||
int32_t iobase_1, iobase_2, altiobase_1, altiobase_2, irq1, irq2;
|
||||
int32_t lun;
|
||||
|
||||
/* set up vendor-specific stuff */
|
||||
type = pci_conf_read(tag, PCI_ID_REG);
|
||||
class = pci_conf_read(tag, PCI_CLASS_REG);
|
||||
cmd = pci_conf_read(tag, PCI_COMMAND_STATUS_REG);
|
||||
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata: type=%08x class=%08x cmd=%08x\n", type, class, cmd);
|
||||
#endif
|
||||
|
||||
switch (type) {
|
||||
case 0x71118086:
|
||||
case 0x70108086:
|
||||
case 0x12308086: /* Intel PIIX, PIIX3, PIIX4 */
|
||||
break;
|
||||
|
||||
case 0x05711106: /* VIA Apollo chipset family */
|
||||
break;
|
||||
|
||||
case 0x4d33105a: /* Promise controllers */
|
||||
break;
|
||||
|
||||
case 0x01021078: /* Cyrix 5530 */
|
||||
break;
|
||||
|
||||
case 0x522910B9: /* Acer Aladdin IV/V (M5229) */
|
||||
break;
|
||||
default:
|
||||
/* everybody else */
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == 0x4d33105a) { /* the Promise is special */
|
||||
iobase_1 = pci_conf_read(tag, 0x10) & 0xfffc;
|
||||
altiobase_1 = pci_conf_read(tag, 0x14) & 0xfffc;
|
||||
iobase_2 = pci_conf_read(tag, 0x18) & 0xfffc;
|
||||
altiobase_2 = pci_conf_read(tag, 0x1c) & 0xfffc;
|
||||
irq1 = irq2 = pci_conf_read(tag, PCI_INTERRUPT_REG) & 0xff;
|
||||
sysctrl = (pci_conf_read(tag, 0x20) & 0xfffc) + 0x1c;
|
||||
}
|
||||
else {
|
||||
if ((class & 0x100) == 0) {
|
||||
iobase_1 = IO_WD1;
|
||||
altiobase_1 = iobase_1 + ATA_ALTPORT;
|
||||
irq1 = 14;
|
||||
}
|
||||
else {
|
||||
iobase_1 = pci_conf_read(tag, 0x10) & 0xfffc;
|
||||
altiobase_1 = pci_conf_read(tag, 0x14) & 0xfffc;
|
||||
irq1 = pci_conf_read(tag, PCI_INTERRUPT_REG) & 0xff;
|
||||
}
|
||||
if ((class & 0x400) == 0) {
|
||||
iobase_2 = IO_WD2;
|
||||
altiobase_2 = iobase_2 + ATA_ALTPORT;
|
||||
irq2 = 15;
|
||||
}
|
||||
else {
|
||||
iobase_2 = pci_conf_read(tag, 0x18) & 0xfffc;
|
||||
altiobase_2 = pci_conf_read(tag, 0x1c) & 0xfffc;
|
||||
irq2 = pci_conf_read(tag, PCI_INTERRUPT_REG) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* now probe the addresse found for "real" ATA/ATAPI hardware */
|
||||
if (ata_probe(iobase_1, altiobase_1, &lun)) {
|
||||
if (iobase_1 == IO_WD1)
|
||||
register_intr(irq1, 0, 0, (inthand2_t *)ataintr, &bio_imask, lun);
|
||||
else {
|
||||
if (sysctrl)
|
||||
pci_map_int(tag, promise_intr, (void *)lun, &bio_imask);
|
||||
else
|
||||
pci_map_int(tag, ataintr, (void *)lun, &bio_imask);
|
||||
}
|
||||
printf("ata%d at 0x%04x irq %d on ata-pci%d\n",
|
||||
lun, iobase_1, irq1, unit);
|
||||
ata_attach(lun);
|
||||
}
|
||||
if (ata_probe(iobase_2, altiobase_2, &lun)) {
|
||||
if (iobase_2 == IO_WD2)
|
||||
register_intr(irq2, 0, 0, (inthand2_t *)ataintr, &bio_imask, lun);
|
||||
else {
|
||||
if (!sysctrl)
|
||||
pci_map_int(tag, ataintr, (void *) lun, &bio_imask);
|
||||
}
|
||||
printf("ata%d at 0x%04x irq %d on ata-pci%d\n",
|
||||
lun, iobase_2, irq2, unit);
|
||||
ata_attach(lun);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
promise_intr(int32_t unit)
|
||||
{
|
||||
if (inl(sysctrl) & 0x00000400)
|
||||
ataintr(unit);
|
||||
if (inl(sysctrl) & 0x00004000)
|
||||
ataintr(unit+1);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (atanlun > MAXATA) {
|
||||
printf("ata: unit of of range(%d)\n", atanlun);
|
||||
return(0);
|
||||
}
|
||||
if (scp) {
|
||||
printf("ata%d: unit already attached\n", atanlun);
|
||||
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);
|
||||
}
|
||||
bzero(scp, sizeof(struct ata_softc));
|
||||
|
||||
scp->unit = atanlun;
|
||||
scp->ioaddr = ioaddr;
|
||||
scp->altioaddr = altioaddr;
|
||||
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata%d: iobase=0x%04x altiobase=0x%04x\n",
|
||||
atanlun, scp->ioaddr, scp->altioaddr);
|
||||
#endif
|
||||
|
||||
/* do we have any signs of ATA/ATAPI HW being present ? */
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
|
||||
DELAY(1);
|
||||
status0 = inb(scp->ioaddr + ATA_STATUS);
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
|
||||
DELAY(1);
|
||||
status1 = inb(scp->ioaddr + ATA_STATUS);
|
||||
if ((status0 & 0xf8) != 0xf8)
|
||||
mask |= 0x01;
|
||||
if ((status1 & 0xf8) != 0xf8)
|
||||
mask |= 0x02;
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
|
||||
atanlun, mask, status0, status1);
|
||||
#endif
|
||||
if (!mask) {
|
||||
free(scp, M_DEVBUF);
|
||||
return 0;
|
||||
}
|
||||
/* assert reset for devices and wait for completition */
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
|
||||
DELAY(1);
|
||||
outb(scp->altioaddr, ATA_A_IDS | ATA_A_RESET);
|
||||
DELAY(1000);
|
||||
outb(scp->altioaddr, ATA_A_IDS);
|
||||
DELAY(1000);
|
||||
inb(scp->ioaddr + ATA_ERROR);
|
||||
outb(scp->altioaddr, ATA_A_4BIT);
|
||||
DELAY(1);
|
||||
|
||||
/* wait for BUSY to go inactive */
|
||||
for (timeout = 0; timeout < 30000*10; timeout++) {
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
|
||||
DELAY(1);
|
||||
status0 = inb(scp->ioaddr + ATA_STATUS);
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
|
||||
DELAY(1);
|
||||
status1 = inb(scp->ioaddr + ATA_STATUS);
|
||||
if (mask == 0x01) /* wait for master only */
|
||||
if (!(status0 & ATA_S_BSY))
|
||||
break;
|
||||
if (mask == 0x02) /* wait for slave only */
|
||||
if (!(status1 & ATA_S_BSY))
|
||||
break;
|
||||
if (mask == 0x03) /* wait for both master & slave */
|
||||
if (!(status0 & ATA_S_BSY) && !(status1 & ATA_S_BSY))
|
||||
break;
|
||||
DELAY(100);
|
||||
}
|
||||
if (status0 & ATA_S_BSY)
|
||||
mask &= ~0x01;
|
||||
if (status1 & ATA_S_BSY)
|
||||
mask &= ~0x02;
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
|
||||
atanlun, mask, status0, status1);
|
||||
#endif
|
||||
if (!mask) {
|
||||
free(scp, M_DEVBUF);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* OK, we have at least one device on the chain,
|
||||
* check for ATAPI signatures, if none check if its
|
||||
* a good old ATA device.
|
||||
*/
|
||||
|
||||
outb(scp->ioaddr + ATA_DRIVE, (ATA_D_IBM | ATA_MASTER));
|
||||
DELAY(1);
|
||||
if (inb(scp->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
|
||||
inb(scp->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB) {
|
||||
scp->devices |= ATA_ATAPI_MASTER;
|
||||
}
|
||||
outb(scp->ioaddr + ATA_DRIVE, (ATA_D_IBM | ATA_SLAVE));
|
||||
DELAY(1);
|
||||
if (inb(scp->ioaddr + ATA_CYL_LSB) == ATAPI_MAGIC_LSB &&
|
||||
inb(scp->ioaddr + ATA_CYL_MSB) == ATAPI_MAGIC_MSB) {
|
||||
scp->devices |= ATA_ATAPI_SLAVE;
|
||||
}
|
||||
if (status0 != 0x00 && !(scp->devices & ATA_ATAPI_MASTER)) {
|
||||
outb(scp->ioaddr + ATA_DRIVE, (ATA_D_IBM | ATA_MASTER));
|
||||
DELAY(1);
|
||||
outb(scp->ioaddr + ATA_ERROR, 0x58);
|
||||
outb(scp->ioaddr + ATA_CYL_LSB, 0xa5);
|
||||
if (inb(scp->ioaddr + ATA_ERROR) != 0x58 &&
|
||||
inb(scp->ioaddr + ATA_CYL_LSB) == 0xa5) {
|
||||
scp->devices |= ATA_ATA_MASTER;
|
||||
}
|
||||
}
|
||||
if (status1 != 0x00 && !(scp->devices & ATA_ATAPI_SLAVE)) {
|
||||
outb(scp->ioaddr + ATA_DRIVE, (ATA_D_IBM | ATA_SLAVE));
|
||||
DELAY(1);
|
||||
outb(scp->ioaddr + ATA_ERROR, 0x58);
|
||||
outb(scp->ioaddr + ATA_CYL_LSB, 0xa5);
|
||||
if (inb(scp->ioaddr + ATA_ERROR) != 0x58 &&
|
||||
inb(scp->ioaddr + ATA_CYL_LSB) == 0xa5) {
|
||||
scp->devices |= ATA_ATA_SLAVE;
|
||||
}
|
||||
}
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata%d: devices = 0x%x\n", atanlun, scp->devices);
|
||||
#endif
|
||||
if (!(scp->devices & (ATA_ATA_MASTER|ATA_ATAPI_MASTER)))
|
||||
scp->flags |= ATA_F_SLAVE_ONLY;
|
||||
if (!scp->devices) {
|
||||
free(scp, M_DEVBUF);
|
||||
return 0;
|
||||
}
|
||||
bufq_init(&scp->ata_queue);
|
||||
TAILQ_INIT(&scp->atapi_queue);
|
||||
*unit = atanlun;
|
||||
atadevices[atanlun++] = scp;
|
||||
return ATA_IOSIZE;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ata_attach(int32_t unit)
|
||||
{
|
||||
struct ata_softc *scp;
|
||||
|
||||
if (unit > atanlun)
|
||||
return 0;
|
||||
|
||||
scp = atadevices[unit];
|
||||
|
||||
if (scp->devices & ATA_ATA_MASTER)
|
||||
if (ata_device_attach(scp, ATA_MASTER))
|
||||
scp->devices &= ~ATA_ATA_MASTER;
|
||||
if (scp->devices & ATA_ATA_SLAVE)
|
||||
if (ata_device_attach(scp, ATA_SLAVE))
|
||||
scp->devices &= ~ATA_ATA_SLAVE;
|
||||
if (scp->devices & ATA_ATAPI_MASTER)
|
||||
if (atapi_device_attach(scp, ATA_MASTER))
|
||||
scp->devices &= ~ATA_ATAPI_MASTER;
|
||||
if (scp->devices & ATA_ATAPI_SLAVE)
|
||||
if (atapi_device_attach(scp, ATA_SLAVE))
|
||||
scp->devices &= ~ATA_ATAPI_SLAVE;
|
||||
return scp->devices;
|
||||
}
|
||||
|
||||
void
|
||||
ataintr(int32_t unit)
|
||||
{
|
||||
struct ata_softc *scp;
|
||||
struct atapi_request *atapi_request;
|
||||
struct buf *ata_request;
|
||||
|
||||
static int32_t intcount = 0;
|
||||
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ataintr: entered unit=%d\n", unit);
|
||||
#endif
|
||||
if (unit < 0 || unit > atanlun) {
|
||||
printf("ataintr: unit %d unusable\n", unit);
|
||||
return;
|
||||
}
|
||||
|
||||
scp = atadevices[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;
|
||||
|
||||
case ATA_ACTIVE_ATA:
|
||||
if ((ata_request = bufq_first(&scp->ata_queue)))
|
||||
ad_interrupt(ata_request);
|
||||
break;
|
||||
|
||||
case ATA_ACTIVE_ATAPI:
|
||||
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue)))
|
||||
atapi_interrupt(atapi_request);
|
||||
break;
|
||||
|
||||
case ATA_IGNORE_INTR:
|
||||
scp->active = ATA_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ata_start(struct ata_softc *scp)
|
||||
{
|
||||
struct buf *ata_request;
|
||||
struct atapi_request *atapi_request;
|
||||
|
||||
#ifdef ATA_DEBUG
|
||||
printf("ata_start: entered\n");
|
||||
#endif
|
||||
if (scp->active) {
|
||||
printf("ata: unwanted ata_start\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* find & call the responsible driver if anything on ATA queue */
|
||||
if ((ata_request = bufq_first(&scp->ata_queue))) {
|
||||
scp->active = ATA_ACTIVE_ATA;
|
||||
ad_transfer(ata_request);
|
||||
}
|
||||
|
||||
/* find & call the responsible driver if anything on ATAPI queue */
|
||||
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue))) {
|
||||
scp->active = ATA_ACTIVE_ATAPI;
|
||||
atapi_transfer(atapi_request);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t
|
||||
ata_wait(struct ata_softc *scp, u_int8_t mask)
|
||||
{
|
||||
u_int8_t status;
|
||||
u_int32_t timeout = 0;
|
||||
|
||||
while (timeout++ <= 50000) { /* timeout 5 secs */
|
||||
status = inb(scp->ioaddr + ATA_STATUS);
|
||||
if ((status == 0xff) && (scp->flags & ATA_F_SLAVE_ONLY)) {
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
|
||||
status = inb(scp->ioaddr + ATA_STATUS);
|
||||
}
|
||||
if (status == 0xff)
|
||||
return -1;
|
||||
scp->status = status;
|
||||
if (!(status & ATA_S_BSY)) {
|
||||
if (status & ATA_S_ERROR)
|
||||
scp->error = inb(scp->ioaddr + ATA_ERROR);
|
||||
if ((status & mask) == mask)
|
||||
return (status & ATA_S_ERROR);
|
||||
}
|
||||
if (timeout > 1000)
|
||||
DELAY(1000);
|
||||
else
|
||||
DELAY(10);
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct ata_params *ata_parm;
|
||||
int8_t buffer[DEV_BSIZE];
|
||||
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
|
||||
if (ata_wait(scp, 0) < 0)
|
||||
return -1;
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device); /* XXX SOS */
|
||||
scp->active = ATA_IGNORE_INTR;
|
||||
outb(scp->ioaddr + ATA_CMD, ATA_C_ATA_IDENTIFY);
|
||||
if (ata_wait(scp, ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ))
|
||||
return -1;
|
||||
|
||||
insw(scp->ioaddr + ATA_DATA, buffer, sizeof(buffer)/sizeof(int16_t));
|
||||
ata_parm = malloc(sizeof(struct ata_params), M_DEVBUF, M_NOWAIT);
|
||||
if (!ata_parm)
|
||||
return -1;
|
||||
bcopy(buffer, ata_parm, sizeof(struct ata_params));
|
||||
bswap(ata_parm->model, sizeof(ata_parm->model));
|
||||
btrim(ata_parm->model, sizeof(ata_parm->model));
|
||||
bswap(ata_parm->revision, sizeof(ata_parm->revision));
|
||||
btrim(ata_parm->revision, sizeof(ata_parm->revision));
|
||||
scp->ata_parm[device == ATA_SLAVE] = ata_parm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
atapi_wait(struct ata_softc *scp, u_int8_t mask)
|
||||
{
|
||||
u_int8_t status;
|
||||
u_int32_t timeout = 0;
|
||||
|
||||
while (timeout++ <= 500000) { /* timeout 5 secs */
|
||||
status = inb(scp->ioaddr + ATA_STATUS);
|
||||
if ((status == 0xff) && (scp->flags & ATA_F_SLAVE_ONLY)) {
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
|
||||
status = inb(scp->ioaddr + ATA_STATUS);
|
||||
}
|
||||
|
||||
if (!(status & ATA_S_BSY))
|
||||
break;
|
||||
DELAY (10);
|
||||
}
|
||||
if (timeout <= 0)
|
||||
return -1;
|
||||
if (!mask)
|
||||
return (status & ATA_S_ERROR);
|
||||
|
||||
/* Wait 50 msec for bits wanted. */
|
||||
for (timeout=5000; timeout>0; --timeout) {
|
||||
status = inb(scp->ioaddr + ATA_STATUS);
|
||||
if ((status & mask) == mask)
|
||||
return (status & ATA_S_ERROR);
|
||||
DELAY (10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
atapi_device_attach(struct ata_softc *scp, int32_t device)
|
||||
{
|
||||
struct atapi_params *atapi_parm;
|
||||
int8_t buffer[DEV_BSIZE];
|
||||
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
|
||||
if (atapi_wait(scp, 0) < 0)
|
||||
return -1;
|
||||
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device); /* XXX SOS */
|
||||
outb(scp->ioaddr + ATA_CMD, ATA_C_ATAPI_IDENTIFY);
|
||||
if (atapi_wait(scp, ATA_S_DRQ))
|
||||
return -1;
|
||||
|
||||
insw(scp->ioaddr + ATA_DATA, buffer, sizeof(buffer)/sizeof(int16_t));
|
||||
atapi_parm = malloc(sizeof(struct atapi_params), M_DEVBUF, M_NOWAIT);
|
||||
if (!atapi_parm)
|
||||
return -1;
|
||||
|
||||
bcopy(buffer, atapi_parm, sizeof(struct atapi_params));
|
||||
if (!((atapi_parm->model[0] == 'N' && atapi_parm->model[1] == 'E') ||
|
||||
(atapi_parm->model[0] == 'F' && atapi_parm->model[1] == 'X')))
|
||||
bswap(atapi_parm->model, sizeof(atapi_parm->model));
|
||||
btrim(atapi_parm->model, sizeof(atapi_parm->model));
|
||||
bswap(atapi_parm->revision, sizeof(atapi_parm->revision));
|
||||
btrim(atapi_parm->revision, sizeof(atapi_parm->revision));
|
||||
bswap(atapi_parm->serial, sizeof(atapi_parm->serial)); /* unused SOS */
|
||||
btrim(atapi_parm->serial, sizeof(atapi_parm->serial)); /* unused SOS */
|
||||
scp->atapi_parm[device == ATA_SLAVE] = atapi_parm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bswap(int8_t *buf, int32_t len)
|
||||
{
|
||||
u_int16_t *p = (u_int16_t*)(buf + len);
|
||||
|
||||
while (--p >= (u_int16_t*)buf)
|
||||
*p = ntohs(*p);
|
||||
}
|
||||
|
||||
static void
|
||||
btrim(int8_t *buf, int32_t len)
|
||||
{
|
||||
int8_t *p;
|
||||
|
||||
for (p = buf; p < buf+len; ++p)
|
||||
if (!*p)
|
||||
*p = ' ';
|
||||
for (p = buf + len - 1; p >= buf && *p == ' '; --p)
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
void
|
||||
bpack(int8_t *src, int8_t *dst, int32_t len)
|
||||
{
|
||||
int32_t i, j, blank;
|
||||
|
||||
for (i = j = blank = 0 ; i < len-1; i++) {
|
||||
if (blank && src[i] == ' ') continue;
|
||||
if (blank && src[i] != ' ') {
|
||||
dst[j++] = src[i];
|
||||
blank = 0;
|
||||
continue;
|
||||
}
|
||||
if (src[i] == ' ')
|
||||
blank = 1;
|
||||
dst[j++] = src[i];
|
||||
}
|
||||
dst[j] = 0x00;
|
||||
}
|
||||
#endif
|
209
sys/dev/ata/ata-all.h
Normal file
209
sys/dev/ata/ata-all.h
Normal file
@ -0,0 +1,209 @@
|
||||
/*-
|
||||
* 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: ata-all.h,v 1.3 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
/* ATA register defines */
|
||||
|
||||
#define ATA_DATA 0x00 /* data register */
|
||||
#define ATA_ERROR 0x01 /* (R) error register */
|
||||
#define ATA_PRECOMP 0x01 /* (W) precompensation */
|
||||
#define ATA_COUNT 0x02 /* sector count */
|
||||
#define ATA_I_CMD 0x01 /* cmd (1) | data (0) */
|
||||
#define ATA_I_IN 0x02 /* read (1) | write (0) */
|
||||
#define ATA_I_RELEASE 0x04 /* released bus (1) */
|
||||
|
||||
#define ATA_SECTOR 0x03 /* sector # */
|
||||
#define ATA_CYL_LSB 0x04 /* cylinder# LSB */
|
||||
#define ATA_CYL_MSB 0x05 /* cylinder# MSB */
|
||||
#define ATA_DRIVE 0x06 /* Sector/Drive/Head register */
|
||||
#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */
|
||||
|
||||
#define ATA_CMD 0x07 /* command register */
|
||||
#define ATA_C_ATA_IDENTIFY 0xec /* get ATA params */
|
||||
#define ATA_C_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
|
||||
#define ATA_C_READ 0x20 /* read command */
|
||||
#define ATA_C_WRITE 0x30 /* write command */
|
||||
#define ATA_C_READ_MULTI 0xc4 /* read multi command */
|
||||
#define ATA_C_WRITE_MULTI 0xc5 /* write multi command */
|
||||
#define ATA_C_SET_MULTI 0xc6 /* set multi size command */
|
||||
#define ATA_C_PACKET_CMD 0xa0 /* set multi size command */
|
||||
|
||||
#define ATA_STATUS 0x07 /* status register */
|
||||
#define ATA_S_ERROR 0x01 /* error */
|
||||
#define ATA_S_INDEX 0x02 /* index */
|
||||
#define ATA_S_CORR 0x04 /* data corrected */
|
||||
#define ATA_S_DRQ 0x08 /* data request */
|
||||
#define ATA_S_DSC 0x10 /* drive Seek Completed */
|
||||
#define ATA_S_DWF 0x20 /* drive write fault */
|
||||
#define ATA_S_DRDY 0x40 /* drive ready */
|
||||
#define ATA_S_BSY 0x80 /* busy */
|
||||
|
||||
#define ATA_ALTPORT 0x206 /* alternate Status register */
|
||||
#define ATA_A_IDS 0x02 /* disable interrupts */
|
||||
#define ATA_A_RESET 0x04 /* RESET controller */
|
||||
#define ATA_A_4BIT 0x08 /* 4 head bits */
|
||||
|
||||
/* Misc defines */
|
||||
#define ATA_MASTER 0x00
|
||||
#define ATA_SLAVE 0x10
|
||||
#define ATA_IOSIZE 0x08
|
||||
|
||||
/* Devices types */
|
||||
#define ATA_ATA_MASTER 0x01
|
||||
#define ATA_ATA_SLAVE 0x02
|
||||
#define ATA_ATAPI_MASTER 0x04
|
||||
#define ATA_ATAPI_SLAVE 0x08
|
||||
|
||||
struct ata_params {
|
||||
int16_t config; /* general configuration bits */
|
||||
u_int16_t cylinders; /* number of cylinders */
|
||||
int16_t reserved2;
|
||||
u_int16_t heads; /* # heads */
|
||||
int16_t unfbytespertrk; /* # unformatted bytes/track */
|
||||
int16_t unfbytes; /* # unformatted bytes/sector */
|
||||
u_int16_t sectors; /* # sectors/track */
|
||||
int16_t vendorunique[3];
|
||||
int8_t serial[20]; /* serial number */
|
||||
int16_t buffertype; /* buffer type */
|
||||
#define ATA_BT_SINGLEPORTSECTOR 1 /* 1 port, 1 sector buffer */
|
||||
#define ATA_BT_DUALPORTMULTI 2 /* 2 port, mult sector buffer */
|
||||
#define ATA_BT_DUALPORTMULTICACHE 3 /* above plus track cache */
|
||||
|
||||
int16_t buffersize; /* buf size, 512-byte units */
|
||||
int16_t necc; /* ecc bytes appended */
|
||||
int8_t revision[8]; /* firmware revision */
|
||||
int8_t model[40]; /* model name */
|
||||
int8_t nsecperint; /* sectors per interrupt */
|
||||
int8_t vendorunique1;
|
||||
int16_t usedmovsd; /* double word read/write? */
|
||||
int8_t vendorunique2;
|
||||
int8_t capability; /* various capability bits */
|
||||
int16_t cap_validate; /* validation for above */
|
||||
int8_t vendorunique3;
|
||||
int8_t opiomode; /* PIO modes 0-2 */
|
||||
int8_t vendorunique4;
|
||||
int8_t odmamode; /* old DMA modes, not ATA-3 */
|
||||
int16_t atavalid; /* fields valid */
|
||||
int16_t currcyls;
|
||||
int16_t currheads;
|
||||
int16_t currsectors;
|
||||
int16_t currsize0;
|
||||
int16_t currsize1;
|
||||
int8_t currmultsect;
|
||||
int8_t multsectvalid;
|
||||
int lbasize;
|
||||
int16_t dmasword; /* obsolete in ATA-3 */
|
||||
int16_t dmamword; /* multiword DMA modes */
|
||||
int16_t eidepiomodes; /* advanced PIO modes */
|
||||
int16_t eidedmamin; /* fastest DMA timing */
|
||||
int16_t eidedmanorm; /* recommended DMA timing */
|
||||
int16_t eidepioblind; /* fastest possible blind PIO */
|
||||
int16_t eidepioacked; /* fastest possible IORDY PIO */
|
||||
int16_t reserved69;
|
||||
int16_t reserved70;
|
||||
int16_t reserved71;
|
||||
int16_t reserved72;
|
||||
int16_t reserved73;
|
||||
int16_t reserved74;
|
||||
int16_t queuelen;
|
||||
int16_t reserved76;
|
||||
int16_t reserved77;
|
||||
int16_t reserved78;
|
||||
int16_t reserved79;
|
||||
int16_t versmajor;
|
||||
int16_t versminor;
|
||||
int16_t featsupp1;
|
||||
int16_t featsupp2;
|
||||
int16_t featsupp3;
|
||||
int16_t featenab1;
|
||||
int16_t featenab2;
|
||||
int16_t featenab3;
|
||||
int16_t udmamode; /* UltraDMA modes */
|
||||
int16_t erasetime;
|
||||
int16_t enherasetime;
|
||||
int16_t apmlevel;
|
||||
int16_t reserved92[34];
|
||||
int16_t rmvcap;
|
||||
int16_t securelevel;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure describing an ATA device
|
||||
*/
|
||||
struct ata_softc {
|
||||
u_int32_t unit; /* this instance's number */
|
||||
u_int32_t ioaddr; /* port addr */
|
||||
u_int32_t altioaddr; /* alternate port addr */
|
||||
void *dmacookie; /* handle for DMA services */
|
||||
int32_t flags; /* controller flags */
|
||||
#define ATA_F_SLAVE_ONLY 0x0001
|
||||
|
||||
int32_t devices; /* what is present */
|
||||
u_int8_t status; /* last controller status */
|
||||
u_int8_t error; /* last controller error */
|
||||
|
||||
int32_t active; /* active processing request */
|
||||
#define ATA_IDLE 0x0
|
||||
#define ATA_ACTIVE_ATA 0x1
|
||||
#define ATA_ACTIVE_ATAPI 0x2
|
||||
#define ATA_IGNORE_INTR 0x3
|
||||
|
||||
struct buf_queue_head ata_queue; /* head of ATA queue */
|
||||
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 {
|
||||
struct ad_softc *driver; /* ptr to parent device */
|
||||
/*bla request bla*/
|
||||
u_int32_t flags; /* drive flags */
|
||||
#define A_READ 0x0001
|
||||
|
||||
u_int32_t bytecount; /* bytes to transfer */
|
||||
u_int32_t donecount; /* bytes transferred */
|
||||
u_int32_t currentsize; /* size of current transfer */
|
||||
struct buf *bp; /* associated buf ptr */
|
||||
TAILQ_ENTRY(ata_request) chain; /* list management */
|
||||
};
|
||||
|
||||
#define MAXATA 8
|
||||
|
||||
extern struct ata_softc *atadevices[];
|
||||
|
||||
/* public prototypes */
|
||||
void ata_start(struct ata_softc *);
|
||||
int32_t ata_wait(struct ata_softc *, u_int8_t);
|
||||
int32_t atapi_wait(struct ata_softc *, u_int8_t);
|
||||
void bpack(int8_t *, int8_t *, int32_t);
|
||||
|
585
sys/dev/ata/ata-disk.c
Normal file
585
sys/dev/ata/ata-disk.c
Normal file
@ -0,0 +1,585 @@
|
||||
/*-
|
||||
* 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: ata-disk.c,v 1.14 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
#include "ata.h"
|
||||
#include "atadisk.h"
|
||||
#include "opt_devfs.h"
|
||||
|
||||
#if NATA > 0 && NATADISK > 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/fcntl.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif
|
||||
#include <machine/clock.h>
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <dev/ata/ata-all.h>
|
||||
#include <dev/ata/ata-disk.h>
|
||||
|
||||
static d_open_t adopen;
|
||||
static d_close_t adclose;
|
||||
static d_write_t adwrite;
|
||||
static d_read_t adread;
|
||||
static d_ioctl_t adioctl;
|
||||
static d_strategy_t adstrategy;
|
||||
static d_psize_t adpsize;
|
||||
|
||||
#define BDEV_MAJOR 0
|
||||
#define CDEV_MAJOR 3
|
||||
static struct cdevsw ad_cdevsw = {
|
||||
adopen, adclose, adread, adwrite,
|
||||
adioctl, nostop, nullreset, nodevtotty,
|
||||
seltrue, nommap, adstrategy, "ad",
|
||||
NULL, -1, nodump, adpsize,
|
||||
D_DISK, 0, -1
|
||||
};
|
||||
|
||||
/* misc defines */
|
||||
#define UNIT(dev) (dev>>3 & 0x1f) /* assume 8 minor # per unit */
|
||||
#define NUNIT 16 /* max # of devices */
|
||||
|
||||
/* prototypes */
|
||||
static void ad_attach(void *);
|
||||
static void ad_strategy(struct buf *);
|
||||
static void ad_start(struct ad_softc *);
|
||||
static void ad_sleep(struct ad_softc *, int8_t *);
|
||||
static int32_t ad_command(struct ad_softc *, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
|
||||
static int8_t ad_version(u_int16_t);
|
||||
static void ad_drvinit(void);
|
||||
|
||||
static struct ad_softc *adtab[NUNIT];
|
||||
static int32_t adnlun = 0; /* number of config'd drives */
|
||||
static struct intr_config_hook *ad_attach_hook;
|
||||
|
||||
static void
|
||||
ad_attach(void *notused)
|
||||
{
|
||||
struct ad_softc *adp;
|
||||
int32_t ctlr, dev;
|
||||
int8_t model_buf[40+1];
|
||||
int8_t revision_buf[8+1];
|
||||
|
||||
/* now, run through atadevices and look for ATA disks */
|
||||
for (ctlr=0; ctlr<MAXATA && atadevices[ctlr]; ctlr++) {
|
||||
for (dev=0; dev<2; dev++) {
|
||||
if (atadevices[ctlr]->ata_parm[dev]) {
|
||||
adp = adtab[adnlun];
|
||||
if (adp)
|
||||
printf("ad%d: unit already attached\n", adnlun);
|
||||
adp = malloc(sizeof(struct ad_softc), M_DEVBUF, M_NOWAIT);
|
||||
if (adp == NULL)
|
||||
printf("ad%d: failed to allocate driver storage\n", adnlun);
|
||||
bzero(adp, sizeof(struct ad_softc));
|
||||
adp->controller = atadevices[ctlr];
|
||||
adp->ata_parm = atadevices[ctlr]->ata_parm[dev];
|
||||
adp->unit = (dev == 0) ? ATA_MASTER : ATA_SLAVE;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
bpack(adp->ata_parm->model, model_buf, sizeof(model_buf));
|
||||
bpack(adp->ata_parm->revision, revision_buf,
|
||||
sizeof(revision_buf));
|
||||
printf("ad%d: <%s/%s> ATA-%c disk at ata%d as %s\n",
|
||||
adnlun,
|
||||
model_buf, revision_buf,
|
||||
ad_version(adp->ata_parm->versmajor),
|
||||
ctlr,
|
||||
(adp->unit == ATA_MASTER) ? "master" : "slave ");
|
||||
printf("ad%d: %luMB (%u sectors), "
|
||||
"%u cyls, %u heads, %u S/T, %u B/S\n",
|
||||
adnlun,
|
||||
adp->total_secs / ((1024L * 1024L) / DEV_BSIZE),
|
||||
adp->total_secs,
|
||||
adp->cylinders,
|
||||
adp->heads,
|
||||
adp->sectors,
|
||||
DEV_BSIZE);
|
||||
printf("ad%d: %d secs/int, %d depth queue \n",
|
||||
adnlun, adp->transfersize / DEV_BSIZE,
|
||||
adp->ata_parm->queuelen & 0x1f);
|
||||
devstat_add_entry(&adp->stats, "ad", adnlun, DEV_BSIZE,
|
||||
DEVSTAT_NO_ORDERED_TAGS,
|
||||
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
|
||||
0x180);
|
||||
bufq_init(&adp->queue);
|
||||
adtab[adnlun++] = adp;
|
||||
}
|
||||
}
|
||||
}
|
||||
config_intrhook_disestablish(ad_attach_hook);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
adopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
|
||||
{
|
||||
int32_t lun = UNIT(dev);
|
||||
struct ad_softc *adp;
|
||||
struct disklabel label;
|
||||
int32_t error;
|
||||
|
||||
#ifdef AD_DEBUG
|
||||
printf("adopen: lun=%d adnlun=%d\n", lun, adnlun);
|
||||
#endif
|
||||
if (lun >= adnlun || !(adp = adtab[lun]))
|
||||
return ENXIO;
|
||||
|
||||
/* spinwait if anybody else is reading the disk label */
|
||||
while (adp->flags & AD_F_LABELLING)
|
||||
tsleep((caddr_t)&adp->flags, PZERO - 1, "adop1", 1);
|
||||
|
||||
/* protect agains label race */
|
||||
adp->flags |= AD_F_LABELLING;
|
||||
|
||||
/* build disklabel and initilize slice tables */
|
||||
bzero(&label, sizeof label);
|
||||
label.d_secsize = DEV_BSIZE;
|
||||
label.d_nsectors = adp->sectors;
|
||||
label.d_ntracks = adp->heads;
|
||||
label.d_ncylinders = adp->cylinders;
|
||||
label.d_secpercyl = adp->sectors * adp->heads;
|
||||
label.d_secperunit = adp->total_secs;
|
||||
|
||||
error = dsopen("ad", dev, fmt, 0, &adp->slices, &label, ad_strategy,
|
||||
(ds_setgeom_t *)NULL, &ad_cdevsw);
|
||||
|
||||
adp->flags &= ~AD_F_LABELLING;
|
||||
ad_sleep(adp, "adop2");
|
||||
return error;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
adclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
|
||||
{
|
||||
int32_t lun = UNIT(dev);
|
||||
struct ad_softc *adp;
|
||||
|
||||
#ifdef AD_DEBUG
|
||||
printf("adclose: lun=%d adnlun=%d\n", lun, adnlun);
|
||||
#endif
|
||||
if (lun >= adnlun || !(adp = adtab[lun]))
|
||||
return ENXIO;
|
||||
|
||||
dsclose(dev, fmt, adp->slices);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
adread(dev_t dev, struct uio *uio, int32_t ioflag)
|
||||
{
|
||||
return physio(adstrategy, NULL, dev, 1, minphys, uio);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
adwrite(dev_t dev, struct uio *uio, int32_t ioflag)
|
||||
{
|
||||
return physio(adstrategy, NULL, dev, 0, minphys, uio);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
adioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flags, struct proc *p)
|
||||
{
|
||||
struct ad_softc *adp;
|
||||
int32_t lun = UNIT(dev);
|
||||
int32_t error = 0;
|
||||
|
||||
if (lun >= adnlun || !(adp = adtab[lun]))
|
||||
return ENXIO;
|
||||
|
||||
ad_sleep(adp, "adioct");
|
||||
error = dsioctl("sd", dev, cmd, addr, flags, &adp->slices,
|
||||
ad_strategy, (ds_setgeom_t *)NULL);
|
||||
|
||||
if (error != ENOIOCTL)
|
||||
return error;
|
||||
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)
|
||||
{
|
||||
struct ad_softc *adp;
|
||||
int32_t lun = UNIT(bp->b_dev);
|
||||
int32_t s;
|
||||
|
||||
#ifdef AD_DEBUG
|
||||
printf("adstrategy: entered\n");
|
||||
#endif
|
||||
if (lun >= adnlun || bp->b_blkno < 0 || !(adp = adtab[lun])
|
||||
|| bp->b_bcount % DEV_BSIZE != 0) {
|
||||
bp->b_error = EINVAL;
|
||||
bp->b_flags |= B_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (dscheck(bp, adp->slices) <= 0)
|
||||
goto done;
|
||||
|
||||
s = splbio();
|
||||
|
||||
/* hang around if somebody else is labelling */
|
||||
if (adp->flags & AD_F_LABELLING)
|
||||
ad_sleep(adp, "adlab");
|
||||
|
||||
bufqdisksort(&adp->queue, bp);
|
||||
|
||||
if (!adp->active)
|
||||
ad_start(adp);
|
||||
|
||||
if (!adp->controller->active)
|
||||
ata_start(adp->controller);
|
||||
|
||||
devstat_start_transaction(&adp->stats);
|
||||
|
||||
splx(s);
|
||||
return;
|
||||
|
||||
done:
|
||||
s = splbio();
|
||||
biodone(bp);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static void
|
||||
ad_strategy(struct buf *bp)
|
||||
{
|
||||
adstrategy(bp);
|
||||
}
|
||||
|
||||
static void
|
||||
ad_start(struct ad_softc *adp)
|
||||
{
|
||||
struct buf *bp;
|
||||
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_start:\n");
|
||||
#endif
|
||||
/* newer called when adp->active != 0 SOS */
|
||||
if (adp->active)
|
||||
return;
|
||||
|
||||
if (!(bp = bufq_first(&adp->queue)))
|
||||
return;
|
||||
|
||||
bp->b_driver1 = adp;
|
||||
bufq_remove(&adp->queue, bp);
|
||||
|
||||
/* link onto controller queue */
|
||||
bufq_insert_tail(&adp->controller->ata_queue, bp);
|
||||
|
||||
/* mark the drive as busy */
|
||||
adp->active = 1;
|
||||
}
|
||||
|
||||
void
|
||||
ad_transfer(struct buf *bp)
|
||||
{
|
||||
struct ad_softc *adp;
|
||||
u_int32_t blknum, secsprcyl;
|
||||
u_int32_t cylinder, head, sector, count, command;
|
||||
|
||||
/* get request params */
|
||||
adp = bp->b_driver1;
|
||||
|
||||
/* calculate transfer details */
|
||||
blknum = bp->b_pblkno + (adp->donecount / DEV_BSIZE);
|
||||
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_transfer: blknum=%d\n", blknum);
|
||||
#endif
|
||||
if (adp->donecount == 0) {
|
||||
|
||||
/* setup transfer parameters */
|
||||
adp->bytecount = bp->b_bcount;
|
||||
secsprcyl = adp->sectors * adp->heads;
|
||||
cylinder = blknum / secsprcyl;
|
||||
head = (blknum % secsprcyl) / adp->sectors;
|
||||
sector = blknum % adp->sectors;
|
||||
count = howmany(adp->bytecount, DEV_BSIZE);
|
||||
|
||||
if (count > 255) /* SOS */
|
||||
printf("ad_transfer: count=%d\n", count);
|
||||
|
||||
|
||||
/* setup transfer length if multible sector access present */
|
||||
adp->currentsize = min(adp->bytecount, adp->transfersize);
|
||||
if (adp->currentsize > DEV_BSIZE)
|
||||
command = (bp->b_flags&B_READ) ? ATA_C_READ_MULTI:ATA_C_WRITE_MULTI;
|
||||
else
|
||||
command = (bp->b_flags&B_READ) ? ATA_C_READ : ATA_C_WRITE;
|
||||
|
||||
/* ready to issue command ? */
|
||||
while (ata_wait(adp->controller, 0) < 0) {
|
||||
printf("ad_transfer: timeout waiting to give command");
|
||||
/*ata_unwedge(adp->controller); SOS */
|
||||
}
|
||||
|
||||
outb(adp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | adp->unit | head);
|
||||
outb(adp->controller->ioaddr + ATA_PRECOMP, 0); /* no precompensation */
|
||||
outb(adp->controller->ioaddr + ATA_CYL_LSB, cylinder);
|
||||
outb(adp->controller->ioaddr + ATA_CYL_MSB, cylinder >> 8);
|
||||
outb(adp->controller->ioaddr + ATA_SECTOR, sector + 1);
|
||||
outb(adp->controller->ioaddr + ATA_COUNT, count);
|
||||
/*
|
||||
if (ata_wait(adp->controller, ATA_S_DRDY) < 0)
|
||||
printf("ad_transfer: timeout waiting to send command");
|
||||
*/
|
||||
outb(adp->controller->ioaddr + ATA_CMD, command);
|
||||
}
|
||||
|
||||
/* if this is a read operation, return and wait for interrupt */
|
||||
if (bp->b_flags & B_READ) {
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_transfer: return waiting to read data\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* ready to write data ? */
|
||||
if (ata_wait(adp->controller, ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ) < 0) {
|
||||
printf("ad_transfer: timeout waiting for DRQ");
|
||||
}
|
||||
|
||||
/* calculate transfer length */
|
||||
adp->currentsize = min(adp->bytecount, adp->transfersize);
|
||||
|
||||
/* output the data */
|
||||
#if 0
|
||||
outsw(adp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)bp->b_data + adp->donecount),
|
||||
adp->currentsize / sizeof(int16_t));
|
||||
#else
|
||||
outsl(adp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)bp->b_data + adp->donecount),
|
||||
adp->currentsize / sizeof(int32_t));
|
||||
#endif
|
||||
adp->bytecount -= adp->currentsize;
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_transfer: return wrote data\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ad_interrupt(struct buf *bp)
|
||||
{
|
||||
struct ad_softc *adp = bp->b_driver1;
|
||||
|
||||
/* finish DMA stuff */
|
||||
|
||||
/* get drive status */
|
||||
if (ata_wait(adp->controller, 0) < 0)
|
||||
printf("ad_interrupt: timeout waiting for status");
|
||||
|
||||
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);
|
||||
if (adp->controller->status & ATA_S_ERROR) {
|
||||
printf("ad_interrupt: hard error");
|
||||
bp->b_error = EIO;
|
||||
bp->b_flags |= B_ERROR;
|
||||
}
|
||||
if (adp->controller->status & ATA_S_CORR)
|
||||
printf("ad_interrupt: soft ECC");
|
||||
}
|
||||
/* if this was a read operation, get the data */
|
||||
if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && adp->active) {
|
||||
|
||||
/* ready to receive data? */
|
||||
if ((adp->controller->status & (ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ))
|
||||
!= (ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ))
|
||||
printf("ad_interrupt: read interrupt arrived early");
|
||||
|
||||
if (ata_wait(adp->controller, ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ) != 0){
|
||||
printf("ad_interrupt: read error detected late");
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* calculate transfer length */
|
||||
adp->currentsize = min(adp->bytecount, adp->currentsize);
|
||||
|
||||
/* data are ready, get them */
|
||||
#if 0
|
||||
insw(adp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)bp->b_data + adp->donecount),
|
||||
adp->currentsize / sizeof(int16_t));
|
||||
#else
|
||||
insl(adp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)bp->b_data + adp->donecount),
|
||||
adp->currentsize / sizeof(int32_t));
|
||||
#endif
|
||||
adp->bytecount -= adp->currentsize;
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_interrupt: read in data\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* finish up this tranfer, check for more work on this buffer */
|
||||
if (adp->controller->active) {
|
||||
if ((bp->b_flags & B_ERROR) == 0) {
|
||||
adp->donecount += adp->currentsize;
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_interrupt: %s operation OK\n", (bp->b_flags & B_READ)?"R":"W");
|
||||
#endif
|
||||
if (adp->bytecount > 0) {
|
||||
ad_transfer(bp); /* MESSY!! only needed for W */
|
||||
return;
|
||||
}
|
||||
}
|
||||
bufq_remove(&adp->controller->ata_queue, bp);
|
||||
bp->b_resid = bp->b_bcount - adp->donecount;
|
||||
adp->donecount = 0;
|
||||
devstat_end_transaction(&adp->stats, bp->b_bcount - bp->b_resid,
|
||||
DEVSTAT_TAG_NONE,
|
||||
(bp->b_flags & B_READ) ?
|
||||
DEVSTAT_READ : DEVSTAT_WRITE);
|
||||
biodone(bp);
|
||||
adp->active = 0;
|
||||
}
|
||||
adp->controller->active = ATA_IDLE;
|
||||
ad_start(adp);
|
||||
#ifdef AD_DEBUG
|
||||
printf("ad_interrupt: completed\n");
|
||||
#endif
|
||||
ata_start(adp->controller);
|
||||
}
|
||||
|
||||
static void
|
||||
ad_sleep(struct ad_softc *adp, int8_t *mesg)
|
||||
{
|
||||
int32_t s = splbio();
|
||||
|
||||
while (adp->controller->active)
|
||||
tsleep((caddr_t)&adp->controller->active, PZERO - 1, mesg, 1);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ad_command(struct ad_softc *adp, u_int32_t command,
|
||||
u_int32_t cylinder, u_int32_t head, u_int32_t sector,
|
||||
u_int32_t count)
|
||||
{
|
||||
/* ready to issue command ? */
|
||||
while (ata_wait(adp->controller, 0) < 0) {
|
||||
printf("ad_transfer: timeout waiting to give command");
|
||||
return -1;
|
||||
}
|
||||
|
||||
outb(adp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | adp->unit | head);
|
||||
outb(adp->controller->ioaddr + ATA_PRECOMP, 0); /* no precompensation */
|
||||
outb(adp->controller->ioaddr + ATA_CYL_LSB, cylinder);
|
||||
outb(adp->controller->ioaddr + ATA_CYL_MSB, cylinder >> 8);
|
||||
outb(adp->controller->ioaddr + ATA_SECTOR, sector + 1);
|
||||
outb(adp->controller->ioaddr + ATA_COUNT, count);
|
||||
/*
|
||||
if (ata_wait(adp->controller, ATA_S_DRDY) < 0) {
|
||||
printf("ad_transfer: timeout waiting to send command");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
adp->controller->active = ATA_IGNORE_INTR;
|
||||
outb(adp->controller->ioaddr + ATA_CMD, command);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int8_t
|
||||
ad_version(u_int16_t version)
|
||||
{
|
||||
int32_t bit;
|
||||
|
||||
if (version == 0xffff)
|
||||
return '?';
|
||||
for (bit = 15; bit >= 0; bit--)
|
||||
if (version & (1<<bit))
|
||||
return ('0' + bit);
|
||||
return '?';
|
||||
}
|
||||
|
||||
static void
|
||||
ad_drvinit(void)
|
||||
{
|
||||
static ad_devsw_installed = 0;
|
||||
|
||||
if (!ad_devsw_installed) {
|
||||
cdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &ad_cdevsw);
|
||||
ad_devsw_installed = 1;
|
||||
}
|
||||
/* register callback for when interrupts are enabled */
|
||||
if (!(ad_attach_hook =
|
||||
(struct intr_config_hook *)malloc(sizeof(struct intr_config_hook),
|
||||
M_TEMP, M_NOWAIT))) {
|
||||
printf("ad: malloc attach_hook failed\n");
|
||||
return;
|
||||
}
|
||||
bzero(ad_attach_hook, sizeof(struct intr_config_hook));
|
||||
|
||||
ad_attach_hook->ich_func = ad_attach;
|
||||
if (config_intrhook_establish(ad_attach_hook) != 0) {
|
||||
printf("ad: config_intrhook_establish failed\n");
|
||||
free(ad_attach_hook, M_TEMP);
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(addev, SI_SUB_DRIVERS, SI_ORDER_SECOND, ad_drvinit, NULL)
|
||||
#endif /* NATA && NATADISK */
|
57
sys/dev/ata/ata-disk.h
Normal file
57
sys/dev/ata/ata-disk.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*-
|
||||
* 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: ata-disk.h,v 1.5 1999/03/01 12:11:01 sos Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
u_int16_t cylinders; /* disk geometry (probed) */
|
||||
u_int8_t heads;
|
||||
u_int8_t sectors;
|
||||
u_int32_t total_secs; /* total # of sectors (LBA) */
|
||||
u_int32_t transfersize; /* size of each transfer */
|
||||
u_int32_t currentsize; /* size of current transfer */
|
||||
struct buf_queue_head queue; /* head of request queue */
|
||||
u_int32_t bytecount; /* bytes to transfer */
|
||||
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 */
|
||||
};
|
||||
|
||||
void ad_transfer(struct buf *);
|
||||
void ad_interrupt(struct buf *);
|
||||
|
439
sys/dev/ata/atapi-all.c
Normal file
439
sys/dev/ata/atapi-all.c
Normal file
@ -0,0 +1,439 @@
|
||||
/*-
|
||||
* 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-all.c,v 1.5 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
#include "ata.h"
|
||||
#include "atapicd.h"
|
||||
#include "atapist.h"
|
||||
/*#include "atapifd.h"*/
|
||||
#include "opt_devfs.h"
|
||||
|
||||
#if NATA > 0
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/devicestat.h>
|
||||
#include <machine/clock.h>
|
||||
#include <dev/ata/ata-all.h>
|
||||
#include <dev/ata/atapi-all.h>
|
||||
|
||||
/* prototypes */
|
||||
static void atapi_attach(void *);
|
||||
static int8_t *atapi_type(int32_t);
|
||||
static int8_t *atapi_cmd2str(u_int8_t);
|
||||
static void atapi_init(void);
|
||||
|
||||
/* extern references */
|
||||
int32_t acdattach(struct atapi_softc *);
|
||||
int32_t afdattach(struct atapi_softc *);
|
||||
int32_t astattach(struct atapi_softc *);
|
||||
|
||||
static struct intr_config_hook *atapi_attach_hook;
|
||||
|
||||
static void
|
||||
atapi_attach(void *notused)
|
||||
{
|
||||
int32_t ctlr, dev;
|
||||
int8_t model_buf[40+1];
|
||||
int8_t revision_buf[8+1];
|
||||
|
||||
/* now, run through atadevices and look for ATAPI devices */
|
||||
for (ctlr=0; ctlr<MAXATA && atadevices[ctlr]; ctlr++) {
|
||||
for (dev=0; dev<2; dev++) {
|
||||
struct ata_softc *scp = atadevices[ctlr];
|
||||
|
||||
if (scp->atapi_parm[dev]) {
|
||||
struct atapi_softc *atp;
|
||||
|
||||
atp = malloc(sizeof(struct atapi_softc), M_DEVBUF, M_NOWAIT);
|
||||
bzero(atp, sizeof(struct atapi_softc));
|
||||
atp->controller = scp;
|
||||
atp->atapi_parm = scp->atapi_parm[dev];
|
||||
atp->unit = (dev) ? ATA_SLAVE : ATA_MASTER;
|
||||
|
||||
switch (scp->atapi_parm[dev]->device_type) {
|
||||
#if NATAPICD > 0
|
||||
case ATAPI_TYPE_CDROM:
|
||||
if (acdattach(atp))
|
||||
goto notfound;
|
||||
break;
|
||||
#endif
|
||||
#if NATAPIFD > 0
|
||||
case ATAPI_TYPE_DIRECT:
|
||||
if (afdattach(atp))
|
||||
goto notfound;
|
||||
break;
|
||||
#endif
|
||||
#if NATAPIST > 0
|
||||
case ATAPI_TYPE_TAPE:
|
||||
if (astattach(atp))
|
||||
goto notfound;
|
||||
break;
|
||||
#endif
|
||||
notfound:
|
||||
default:
|
||||
free(atp, M_DEVBUF);
|
||||
bpack(scp->atapi_parm[dev]->model, model_buf,
|
||||
sizeof(model_buf));
|
||||
bpack(scp->atapi_parm[dev]->revision, revision_buf,
|
||||
sizeof(revision_buf));
|
||||
printf("atapi: <%s/%s> %s device at ata%d as %s "
|
||||
"- NO DRIVER!\n",
|
||||
model_buf, revision_buf,
|
||||
atapi_type(scp->atapi_parm[dev]->device_type),
|
||||
ctlr,
|
||||
(dev) ? "slave" : "master ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
config_intrhook_disestablish(atapi_attach_hook);
|
||||
}
|
||||
|
||||
int32_t
|
||||
atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
|
||||
int32_t count, int32_t flags,
|
||||
atapi_callback_t callback, void *driver, struct buf *bp)
|
||||
{
|
||||
struct atapi_request *request;
|
||||
int32_t error = 0;
|
||||
int32_t s = splbio();
|
||||
|
||||
if (!(request = malloc(sizeof(struct atapi_request), M_DEVBUF, M_NOWAIT))) {
|
||||
splx(s);
|
||||
return -1;
|
||||
}
|
||||
bzero(request, sizeof(struct atapi_request));
|
||||
request->device = atp;
|
||||
request->data = data;
|
||||
request->bytecount = count;
|
||||
request->flags = flags;
|
||||
if (callback) {
|
||||
request->callback = callback;
|
||||
request->bp = bp;
|
||||
request->driver = driver;
|
||||
}
|
||||
request->ccbsize = (atp->atapi_parm->cmdsize) ? 16 : 12;
|
||||
bcopy(ccb, request->ccb, request->ccbsize);
|
||||
|
||||
/* link onto controller queue */
|
||||
TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain);
|
||||
#ifdef ATAPI_DEBUG
|
||||
printf("atapi: trying to start %s command\n", atapi_cmd2str(ccb[0]));
|
||||
#endif
|
||||
/* try to start controller */
|
||||
if (!atp->controller->active)
|
||||
ata_start(atp->controller);
|
||||
|
||||
if (!callback) {
|
||||
/* wait for command to complete */
|
||||
tsleep((caddr_t)request, PRIBIO, "atprq", 0);
|
||||
#ifdef ATAPI_DEBUG
|
||||
printf("atapi: phew, got back from tsleep\n");
|
||||
#endif
|
||||
error = request->result;
|
||||
free(request, M_DEVBUF);
|
||||
}
|
||||
splx(s);
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
atapi_transfer(struct atapi_request *request)
|
||||
{
|
||||
struct atapi_softc *atp;
|
||||
int32_t timeout;
|
||||
int8_t int_reason; /* not needed really */
|
||||
|
||||
/* get device params */
|
||||
atp = request->device;
|
||||
|
||||
/* start ATAPI operation */
|
||||
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
|
||||
if (atapi_wait(atp->controller, 0) < 0) {
|
||||
printf ("atapi_transfer: timeout waiting to send PACKET command\n");
|
||||
/* now what ? SOS */
|
||||
}
|
||||
outb(atp->controller->ioaddr + ATA_PRECOMP, 0);
|
||||
outb(atp->controller->ioaddr + ATA_COUNT, 0);
|
||||
outb(atp->controller->ioaddr + ATA_SECTOR, 0);
|
||||
outb(atp->controller->ioaddr + ATA_CYL_LSB, request->bytecount);
|
||||
outb(atp->controller->ioaddr + ATA_CYL_MSB, request->bytecount >> 8);
|
||||
outb(atp->controller->ioaddr + ATA_CMD, ATA_C_PACKET_CMD);
|
||||
|
||||
/* wait for interrupt ?? not supported yet. */
|
||||
/* just return then and let atapi_interrupt handle it */
|
||||
|
||||
/* ready to write ATAPI command */
|
||||
timeout = 5000; /* might be less for fast devices */
|
||||
while (timeout--) {
|
||||
int_reason = inb(atp->controller->ioaddr + ATA_COUNT);
|
||||
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
|
||||
if (((int_reason & (ATA_I_CMD | ATA_I_IN)) |
|
||||
(atp->controller->status&(ATA_S_DRQ|ATA_S_BSY))) == ATAPI_P_CMDOUT)
|
||||
break;
|
||||
DELAY(20);
|
||||
}
|
||||
if (timeout <= 0) {
|
||||
atp->controller->error = inb(atp->controller->ioaddr + ATA_ERROR);
|
||||
printf("atapi_transfer: bad command phase\n");
|
||||
/* now what ?? SOS atapi-done & again */
|
||||
}
|
||||
|
||||
/* send actual command */
|
||||
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
|
||||
request->ccbsize / sizeof(int16_t));
|
||||
}
|
||||
|
||||
void
|
||||
atapi_interrupt(struct atapi_request *request)
|
||||
{
|
||||
struct atapi_softc *atp;
|
||||
int32_t length, reason, resid;
|
||||
|
||||
#ifdef ATAPI_DEBUG
|
||||
printf("atapi_interrupt: enter\n");
|
||||
#endif
|
||||
/* get device params */
|
||||
atp = request->device;
|
||||
|
||||
/* get drive status */
|
||||
if (atapi_wait(atp->controller, 0) < 0) {
|
||||
printf("atapi_interrupt: timeout waiting for status");
|
||||
/* maybe check sense code ?? SOS */
|
||||
return;
|
||||
}
|
||||
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
|
||||
atp->controller->error = inb(atp->controller->ioaddr + ATA_ERROR);
|
||||
|
||||
length = inb(atp->controller->ioaddr + ATA_CYL_LSB);
|
||||
length |= inb(atp->controller->ioaddr + ATA_CYL_MSB) << 8;
|
||||
reason = (inb(atp->controller->ioaddr + ATA_COUNT)&(ATA_I_CMD|ATA_I_IN)) |
|
||||
(atp->controller->status & ATA_S_DRQ);
|
||||
|
||||
#ifdef ATAPI_DEBUG
|
||||
printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
|
||||
#endif
|
||||
|
||||
switch (reason) {
|
||||
|
||||
case ATAPI_P_CMDOUT:
|
||||
printf("atapi_interrupt: command interrupt, not supported yet\n");
|
||||
#if notyet
|
||||
/* send actual command */
|
||||
if (!(atp->status & ATA_S_DRQ))
|
||||
printf("atapi_interrupt: command interrupt, but no DRQ\n");
|
||||
else
|
||||
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
|
||||
request->ccdsize / sizeof(int16_t));
|
||||
#endif
|
||||
return;
|
||||
|
||||
case ATAPI_P_WRITE:
|
||||
if (request->flags & A_READ) {
|
||||
printf("atapi_interrupt: trying to write on read buffer\n");
|
||||
break;
|
||||
}
|
||||
if (request->bytecount < length) {
|
||||
printf("atapi_interrupt: write data underrun %d/%d\n",
|
||||
length, request->bytecount);
|
||||
outsw(atp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)request->data), /* + donecount ?? */
|
||||
length / sizeof(int16_t));
|
||||
for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
|
||||
outw(atp->controller->ioaddr + ATA_DATA, 0);
|
||||
}
|
||||
else {
|
||||
outsw(atp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)request->data), /* + donecount ?? */
|
||||
length / sizeof(int16_t));
|
||||
}
|
||||
request->bytecount -= length;
|
||||
request->data += length;
|
||||
return;
|
||||
|
||||
case ATAPI_P_READ:
|
||||
if (!(request->flags & A_READ)) {
|
||||
printf("atapi_interrupt: trying to read on write buffer\n");
|
||||
break;
|
||||
}
|
||||
if (request->bytecount < length) {
|
||||
printf("atapi_interrupt: read data overrun %d/%d\n",
|
||||
length, request->bytecount);
|
||||
insw(atp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)request->data), /* + donecount ?? */
|
||||
length / sizeof(int16_t));
|
||||
for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
|
||||
inw(atp->controller->ioaddr + ATA_DATA);
|
||||
}
|
||||
else {
|
||||
insw(atp->controller->ioaddr + ATA_DATA,
|
||||
(void *)((int32_t)request->data), /* + donecount ?? */
|
||||
length / sizeof(int16_t));
|
||||
}
|
||||
request->bytecount -= length;
|
||||
request->data += length;
|
||||
return;
|
||||
|
||||
case ATAPI_P_ABORT:
|
||||
case ATAPI_P_DONE:
|
||||
request->result = 0;
|
||||
if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF)) {
|
||||
/* check sense !! SOS */
|
||||
request->result = atp->controller->error;
|
||||
}
|
||||
#ifdef ATAPI_DEBUG
|
||||
if (request->bytecount > 0) {
|
||||
printf("atapi_interrupt: %s size problem, %d bytes residue\n",
|
||||
(request->flags & A_READ) ? "read" : "write",
|
||||
request->bytecount);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
printf("atapi_interrupt: unknown transfer phase\n");
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
|
||||
#ifdef ATAPI_DEBUG
|
||||
printf("atapi_interrupt: error=%02x\n", request->result);
|
||||
#endif
|
||||
if (request->callback) {
|
||||
(request->callback)(request);
|
||||
free(request, M_DEVBUF);
|
||||
}
|
||||
else
|
||||
wakeup((caddr_t)request);
|
||||
atp->controller->active = ATA_IDLE;
|
||||
ata_start(atp->controller);
|
||||
}
|
||||
|
||||
void
|
||||
atapi_error(struct atapi_softc *atp, int32_t error)
|
||||
{
|
||||
printf("atapi: error = %02x\n", error);
|
||||
}
|
||||
|
||||
void
|
||||
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++);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
static int8_t *
|
||||
atapi_type(int32_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case ATAPI_TYPE_CDROM:
|
||||
return "CDROM";
|
||||
case ATAPI_TYPE_DIRECT:
|
||||
return "floppy";
|
||||
case ATAPI_TYPE_TAPE:
|
||||
return "tape";
|
||||
case ATAPI_TYPE_OPTICAL:
|
||||
return "optical";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static int8_t *
|
||||
atapi_cmd2str(u_int8_t cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case 0x00: return ("TEST_UNIT_READY");
|
||||
case 0x01: return ("REZERO_UNIT");
|
||||
case 0x03: return ("REQUEST_SENSE");
|
||||
case 0x04: return ("FORMAT_UNIT");
|
||||
case 0x1a: return ("TAPE_MODE_SENSE");
|
||||
case 0x1b: return ("START_STOP");
|
||||
case 0x1e: return ("PREVENT_ALLOW");
|
||||
case 0x25: return ("READ_CAPACITY");
|
||||
case 0x28: return ("READ_BIG");
|
||||
case 0x2a: return ("WRITE_BIG");
|
||||
case 0x35: return ("SYNCHRONIZE_CACHE");
|
||||
case 0x42: return ("READ_SUBCHANNEL");
|
||||
case 0x43: return ("READ_TOC");
|
||||
case 0x51: return ("READ_DISC_INFO");
|
||||
case 0x52: return ("READ_TRACK_INFO");
|
||||
case 0x53: return ("RESERVE_TRACK");
|
||||
case 0x54: return ("SEND_OPC_INFO");
|
||||
case 0x55: return ("MODE_SELECT");
|
||||
case 0x58: return ("REPAIR_TRACK");
|
||||
case 0x59: return ("READ_MASTER_CUE");
|
||||
case 0x5a: return ("MODE_SENSE");
|
||||
case 0x5b: return ("CLOSE_TRACK/SESSION");
|
||||
case 0x5c: return ("READ_BUFFER_CAPACITY");
|
||||
case 0x5d: return ("SEND_CUE_SHEET");
|
||||
case 0x47: return ("PLAY_MSF");
|
||||
case 0x4b: return ("PAUSE");
|
||||
case 0x48: return ("PLAY_TRACK");
|
||||
case 0xa1: return ("BLANK_CMD");
|
||||
case 0xa5: return ("PLAY_BIG");
|
||||
case 0xb4: return ("PLAY_CD");
|
||||
case 0xbd: return ("MECH_STATUS");
|
||||
case 0xbe: return ("READ_CD");
|
||||
default: {
|
||||
static int8_t buffer[16];
|
||||
sprintf(buffer, "Unknown 0x%02x", cmd);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
atapi_init(void)
|
||||
{
|
||||
/* register callback for when interrupts are enabled */
|
||||
if (!(atapi_attach_hook =
|
||||
(struct intr_config_hook *)malloc(sizeof(struct intr_config_hook),
|
||||
M_TEMP, M_NOWAIT))) {
|
||||
printf("atapi: malloc attach_hook failed\n");
|
||||
return;
|
||||
}
|
||||
bzero(atapi_attach_hook, sizeof(struct intr_config_hook));
|
||||
|
||||
atapi_attach_hook->ich_func = atapi_attach;
|
||||
if (config_intrhook_establish(atapi_attach_hook) != 0) {
|
||||
printf("atapi: config_intrhook_establish failed\n");
|
||||
free(atapi_attach_hook, M_TEMP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SYSINIT(atconf, SI_SUB_CONFIGURE, SI_ORDER_SECOND, atapi_init, NULL)
|
||||
#endif /* NATA */
|
180
sys/dev/ata/atapi-all.h
Normal file
180
sys/dev/ata/atapi-all.h
Normal file
@ -0,0 +1,180 @@
|
||||
/*-
|
||||
* 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-all.h,v 1.2 1999/03/01 12:11:01 sos Exp $
|
||||
*/
|
||||
|
||||
/* ATAPI misc defines */
|
||||
#define ATAPI_MAGIC_LSB 0x14
|
||||
#define ATAPI_MAGIC_MSB 0xeb
|
||||
#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN)
|
||||
#define ATAPI_P_WRITE (ATA_S_DRQ)
|
||||
#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD)
|
||||
#define ATAPI_P_ABORT 0
|
||||
#define ATAPI_P_DONE (ATA_I_IN | ATA_I_CMD)
|
||||
|
||||
/* error register bits */
|
||||
#define ATAPI_E_ILI 0x01 /* illegal length indication */
|
||||
#define ATAPI_E_EOM 0x02 /* end of media detected */
|
||||
#define ATAPI_E_ABRT 0x04 /* command aborted */
|
||||
#define ATAPI_E_MCR 0x08 /* media change requested */
|
||||
#define ATAPI_SK_MASK 0xf0 /* sense key mask */
|
||||
#define ATAPI_SK_NO_SENSE 0x00 /* no specific sense key info */
|
||||
#define ATAPI_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */
|
||||
#define ATAPI_SK_NOT_READY 0x20 /* no access to drive */
|
||||
#define ATAPI_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
|
||||
#define ATAPI_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */
|
||||
#define ATAPI_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */
|
||||
#define ATAPI_SK_UNIT_ATTENTION 0x60 /* media changed */
|
||||
#define ATAPI_SK_DATA_PROTECT 0x70 /* reading read-protected sec */
|
||||
#define ATAPI_SK_BLANK_CHECK 0x80 /* blank check */
|
||||
#define ATAPI_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */
|
||||
#define ATAPI_SK_COPY_ABORTED 0xa0 /* copy aborted */
|
||||
#define ATAPI_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
|
||||
#define ATAPI_SK_EQUAL 0xc0 /* equal */
|
||||
#define ATAPI_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */
|
||||
#define ATAPI_SK_MISCOMPARE 0xe0 /* data dont match the medium */
|
||||
#define ATAPI_SK_RESERVED 0xf0
|
||||
|
||||
/* ATAPI commands */
|
||||
#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
|
||||
#define ATAPI_REZERO_UNIT 0x01 /* reinit device */
|
||||
#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
|
||||
#define ATAPI_START_STOP 0x1b /* start/stop the media */
|
||||
#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */
|
||||
#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
|
||||
#define ATAPI_READ_BIG 0x28 /* read data */
|
||||
#define ATAPI_WRITE_BIG 0x2a /* write data */
|
||||
#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
|
||||
#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
|
||||
#define ATAPI_READ_TOC 0x43 /* get table of contents */
|
||||
#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
|
||||
#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
|
||||
#define ATAPI_PAUSE 0x4b /* stop/start audio operation */
|
||||
#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
|
||||
#define ATAPI_MODE_SELECT 0x55 /* set device parameters */
|
||||
#define ATAPI_MODE_SENSE 0x5a /* get device parameters */
|
||||
#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
|
||||
#define ATAPI_BLANK 0xa1 /* blank (erase) media */
|
||||
#define ATAPI_PLAY_BIG 0xa5 /* play by lba */
|
||||
#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */
|
||||
#define ATAPI_PLAY_CD 0xb4 /* universal play command */
|
||||
#define ATAPI_MECH_STATUS 0xbd /* get changer status */
|
||||
#define ATAPI_READ_CD 0xbe /* read data */
|
||||
|
||||
/* ATAPI device parameter information */
|
||||
struct atapi_params {
|
||||
u_int 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 */
|
||||
#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 */
|
||||
#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 */
|
||||
#define ATAPI_PROTO_ATAPI 2
|
||||
|
||||
int16_t reserved1[9];
|
||||
int8_t serial[20]; /* serial number */
|
||||
int16_t reserved2[3];
|
||||
int8_t revision[8]; /* firmware revision */
|
||||
int8_t model[40]; /* model name */
|
||||
int16_t reserved3[2];
|
||||
u_int8_t vendor_cap; /* vendor capabilities */
|
||||
u_int8_t dmaflag :1; /* DMA supported */
|
||||
u_int8_t lbaflag :1; /* LBA supported - always 1 */
|
||||
u_int8_t iordydis :1; /* IORDY can be disabled */
|
||||
u_int8_t iordyflag :1; /* IORDY supported */
|
||||
u_int8_t :1;
|
||||
u_int8_t ovlapflag :1; /* overlap supported */
|
||||
u_int8_t :1;
|
||||
u_int8_t idmaflag :1; /* interleaved DMA supported */
|
||||
int16_t reserved4;
|
||||
u_int16_t pio_timing; /* PIO cycle timing */
|
||||
u_int16_t dma_timing; /* DMA cycle timing */
|
||||
u_int16_t flags;
|
||||
#define ATAPI_FLAG_54_58 1 /* words 54-58 valid */
|
||||
#define ATAPI_FLAG_64_70 2 /* words 64-70 valid */
|
||||
|
||||
int16_t reserved5[8];
|
||||
u_int8_t swdma_flag; /* singleword DMA supported */
|
||||
u_int8_t swdma_active; /* singleword DMA active */
|
||||
u_int8_t mwdma_flag; /* multiword DMA supported */
|
||||
u_int8_t mwdma_active; /* multiword DMA active */
|
||||
u_int8_t apio_flag; /* advanced PIO supported */
|
||||
u_int8_t reserved6;
|
||||
u_int16_t mwdma_min; /* min. M/W DMA time/word ns */
|
||||
u_int16_t mwdma_dflt; /* rec. M/W DMA time ns */
|
||||
u_int16_t pio_nfctl_min; /* min. PIO cycle w/o flow */
|
||||
u_int16_t pio_iordy_min; /* min. PIO cycle IORDY flow */
|
||||
int16_t reserved7[2];
|
||||
u_int16_t rls_ovlap; /* rel time (us) for overlap */
|
||||
u_int16_t rls_service; /* rel time (us) for service */
|
||||
};
|
||||
|
||||
struct atapi_softc {
|
||||
struct ata_softc *controller; /* ptr to parent ctrl */
|
||||
struct atapi_params *atapi_parm; /* ata device params */
|
||||
int32_t unit; /* ATA_MASTER or ATA_SLAVE */
|
||||
u_int32_t flags; /* drive flags */
|
||||
};
|
||||
|
||||
typedef void atapi_callback_t(struct atapi_request *);
|
||||
|
||||
struct atapi_request {
|
||||
struct atapi_softc *device; /* ptr to parent device */
|
||||
void *driver; /* ptr to calling driver */
|
||||
u_int8_t ccb[16]; /* command control block */
|
||||
int32_t ccbsize; /* size of ccb (12 | 16) */
|
||||
int32_t flags;
|
||||
#define A_READ 0x0001
|
||||
|
||||
u_int32_t bytecount; /* bytes to transfer */
|
||||
u_int32_t result; /* result code */
|
||||
int8_t *data; /* pointer to data buf */
|
||||
struct buf *bp; /* associated buf ptr */
|
||||
atapi_callback_t *callback; /* ptr to callback func */
|
||||
TAILQ_ENTRY(atapi_request) chain; /* list management */
|
||||
};
|
||||
|
||||
void atapi_transfer(struct atapi_request *);
|
||||
void atapi_interrupt(struct atapi_request *);
|
||||
int atapi_queue_cmd(struct atapi_softc *, int8_t [], void *, int32_t, int32_t, atapi_callback_t, void *, struct buf *);
|
||||
void atapi_error(struct atapi_softc *, int32_t);
|
||||
void atapi_dump(int8_t *, void *, int32_t);
|
||||
|
1447
sys/dev/ata/atapi-cd.c
Normal file
1447
sys/dev/ata/atapi-cd.c
Normal file
File diff suppressed because it is too large
Load Diff
358
sys/dev/ata/atapi-cd.h
Normal file
358
sys/dev/ata/atapi-cd.h
Normal file
@ -0,0 +1,358 @@
|
||||
/*-
|
||||
* 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-cd.h,v 1.3 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
/*
|
||||
* CDROM Table Of Contents
|
||||
*/
|
||||
#define MAXTRK 99
|
||||
struct toc {
|
||||
struct ioc_toc_header hdr;
|
||||
struct cd_toc_entry tab[MAXTRK + 1];
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM Audio Control Parameters Page
|
||||
*/
|
||||
struct audiopage {
|
||||
/* Mode Page data header */
|
||||
u_int16_t data_length;
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_spec;
|
||||
u_int8_t unused[2];
|
||||
u_int16_t blk_desc_len;
|
||||
|
||||
/* Audio control page */
|
||||
u_int8_t page_code;
|
||||
#define ATAPI_CDROM_AUDIO_PAGE 0x0e
|
||||
#define ATAPI_CDROM_AUDIO_PAGE_MASK 0x4e
|
||||
|
||||
u_int8_t param_len;
|
||||
u_int8_t flags;
|
||||
#define CD_PA_SOTC 0x02
|
||||
#define CD_PA_IMMED 0x04
|
||||
|
||||
u_int8_t reserved3;
|
||||
u_int8_t reserved4;
|
||||
u_int8_t reserved5;
|
||||
u_int16_t lb_per_sec;
|
||||
struct port_control {
|
||||
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;
|
||||
} port[4];
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM Capabilities and Mechanical Status Page
|
||||
*/
|
||||
struct cappage {
|
||||
/* Mode data header */
|
||||
u_int16_t data_length;
|
||||
u_int8_t medium_type; /* Present media type */
|
||||
#define MST_TYPE_MASK_LOW 0x0f
|
||||
#define MST_FMT_NONE 0x00
|
||||
#define MST_DATA_120 0x01
|
||||
#define MST_AUDIO_120 0x02
|
||||
#define MST_COMB_120 0x03
|
||||
#define MST_PHOTO_120 0x04
|
||||
#define MST_DATA_80 0x05
|
||||
#define MST_AUDIO_80 0x06
|
||||
#define MST_COMB_80 0x07
|
||||
#define MST_PHOTO_80 0x08
|
||||
|
||||
#define MST_TYPE_MASK_HIGH 0x70
|
||||
#define MST_CDROM 0x00
|
||||
#define MST_CDR 0x10
|
||||
#define MST_CDRW 0x20
|
||||
|
||||
#define MST_NO_DISC 0x70
|
||||
#define MST_DOOR_OPEN 0x71
|
||||
#define MST_FMT_ERROR 0x72
|
||||
|
||||
u_int8_t dev_spec;
|
||||
u_int8_t unused[2];
|
||||
u_int16_t blk_desc_len;
|
||||
|
||||
/* Capabilities page */
|
||||
u_int8_t page_code;
|
||||
#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 :1;
|
||||
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_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 :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 :1;
|
||||
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: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_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 dlen :2;
|
||||
#define MST_DLEN_32 0
|
||||
#define MST_DLEN_16 1
|
||||
#define MST_DLEN_24 2
|
||||
#define MST_DLEN_24_I2S 3
|
||||
|
||||
u_int8_t :3;
|
||||
u_int8_t reserved4[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
#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 reserved0 :5;
|
||||
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 */
|
||||
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;
|
||||
} slot[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* CDROM Write Parameters Mode Page (Burners ONLY)
|
||||
*/
|
||||
struct write_param {
|
||||
/* Mode Page data header */
|
||||
u_int16_t data_length;
|
||||
u_int8_t medium_type;
|
||||
u_int8_t dev_spec;
|
||||
u_int8_t unused[2];
|
||||
u_int16_t blk_desc_len;
|
||||
|
||||
/* Write Parameters mode page */
|
||||
u_int8_t page_code;
|
||||
#define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x0e
|
||||
|
||||
u_int8_t page_length; /* 0x32 */
|
||||
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 reserved2_567 :3;
|
||||
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 */
|
||||
#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 */
|
||||
#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_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 */
|
||||
|
||||
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 reserved7_67 :2;
|
||||
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_int8_t media_catalog_number[16];
|
||||
u_int8_t isr_code[16];
|
||||
u_int8_t sub_hdr_byte0;
|
||||
u_int8_t sub_hdr_byte1;
|
||||
u_int8_t sub_hdr_byte2;
|
||||
u_int8_t sub_hdr_byte3;
|
||||
/*
|
||||
u_int8_t vendor_specific_byte0;
|
||||
u_int8_t vendor_specific_byte1;
|
||||
u_int8_t vendor_specific_byte2;
|
||||
u_int8_t vendor_specific_byte3;
|
||||
*/
|
||||
|
||||
} __attribute__((packed));
|
||||
/*
|
||||
* 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 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 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 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 buf_queue_head buf_queue; /* Queue of i/o requests */
|
||||
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;
|
||||
} 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 devstat *stats; /* devstat entry */
|
||||
#ifdef DEVFS
|
||||
void *ra_devfs_token;
|
||||
void *rc_devfs_token;
|
||||
void *a_devfs_token;
|
||||
void *c_devfs_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define CDRIOCBLANK _IO('c',100) /* Blank a CDRW disc */
|
||||
#define CDRIOCNEXTWRITEABLEADDR _IOR('c',101,int)
|
567
sys/dev/ata/atapi-tape.c
Normal file
567
sys/dev/ata/atapi-tape.c
Normal file
@ -0,0 +1,567 @@
|
||||
/*-
|
||||
* 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.c,v 1.5 1999/03/01 21:03:15 sos Exp sos $
|
||||
*/
|
||||
|
||||
#include "ata.h"
|
||||
#include "atapist.h"
|
||||
#include "opt_devfs.h"
|
||||
|
||||
#if NATA > 0 && NATAPIST > 0
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/buf.h>
|
||||
#include <sys/mtio.h>
|
||||
#include <sys/devicestat.h>
|
||||
#ifdef DEVFS
|
||||
#include <sys/devfsext.h>
|
||||
#endif
|
||||
#include <machine/clock.h>
|
||||
#include <dev/ata/ata-all.h>
|
||||
#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;
|
||||
|
||||
#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 };
|
||||
|
||||
static u_int32_t ast_total = 0;
|
||||
|
||||
#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 */
|
||||
#define F_DATA_WRITTEN 0x0004 /* Data has been written */
|
||||
#define F_FM_WRITTEN 0x0008 /* Filemark has been written */
|
||||
#define F_CTL_WARN 0x0010 /* Have we warned about CTL wrong? */
|
||||
|
||||
static struct ast_softc *asttab[NUNIT]; /* Drive info by unit number */
|
||||
static int32_t astnlun = 0; /* Number of config'd drives */
|
||||
|
||||
int32_t astattach(struct atapi_softc *);
|
||||
static int32_t ast_sense(struct ast_softc *);
|
||||
static void ast_describe(struct ast_softc *);
|
||||
static void ast_start(struct ast_softc *);
|
||||
static void ast_done(struct atapi_request *);
|
||||
static void ast_drvinit(void *);
|
||||
static int32_t ast_space_cmd(struct ast_softc *, u_int8_t, u_int32_t);
|
||||
static int32_t ast_write_filemark(struct ast_softc *, u_int8_t);
|
||||
static int32_t ast_erase(struct ast_softc *);
|
||||
static int32_t ast_load_unload(struct ast_softc *, u_int8_t);
|
||||
static int32_t ast_rewind(struct ast_softc *);
|
||||
|
||||
int32_t
|
||||
astattach(struct atapi_softc *atp)
|
||||
{
|
||||
struct ast_softc *stp;
|
||||
|
||||
if (astnlun >= NUNIT) {
|
||||
printf("ast: too many units\n");
|
||||
return -1;
|
||||
}
|
||||
stp = malloc(sizeof(struct ast_softc), M_TEMP, M_NOWAIT);
|
||||
if (!stp) {
|
||||
printf("ast: out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
bzero(stp, sizeof(struct ast_softc));
|
||||
bufq_init(&stp->buf_queue);
|
||||
stp->atp = atp;
|
||||
stp->lun = astnlun;
|
||||
stp->flags = F_MEDIA_CHANGED;
|
||||
|
||||
if (ast_sense(stp)) {
|
||||
free(stp, M_TEMP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_describe(stp);
|
||||
asttab[astnlun++] = stp;
|
||||
devstat_add_entry(&stp->stats, "ast", stp->lun, DEV_BSIZE,
|
||||
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 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
ast_sense(struct ast_softc *stp)
|
||||
{
|
||||
int32_t error, count;
|
||||
int8_t buffer[256];
|
||||
int8_t ccb[16] = { ATAPI_TAPE_MODE_SENSE,
|
||||
8, /* DBD = 1 no block descr */
|
||||
ATAPI_TAPE_CAP_PAGE,
|
||||
sizeof(buffer)>>8, sizeof(buffer) & 0xff,
|
||||
0, 0, 0, 0, 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(stp->atp, ccb, buffer, sizeof(buffer),
|
||||
A_READ, NULL, NULL, NULL)))
|
||||
break;
|
||||
}
|
||||
#ifdef AST_DEBUG
|
||||
atapi_dump("ast: sense", buffer, sizeof(buffer));
|
||||
#endif
|
||||
if (error)
|
||||
return error;
|
||||
bcopy(buffer, &stp->header, sizeof(struct ast_header));
|
||||
bcopy(buffer+sizeof(struct ast_header), &stp->cap,
|
||||
sizeof(struct ast_cappage));
|
||||
if (stp->cap.page_code != ATAPI_TAPE_CAP_PAGE)
|
||||
return 1;
|
||||
stp->cap.max_speed = ntohs(stp->cap.max_speed);
|
||||
stp->cap.max_defects = ntohs(stp->cap.max_defects);
|
||||
stp->cap.ctl = ntohs(stp->cap.ctl);
|
||||
stp->cap.speed = ntohs(stp->cap.speed);
|
||||
stp->cap.buffer_size = ntohs(stp->cap.buffer_size);
|
||||
stp->blksize = (stp->cap.blk512 ? 512 : (stp->cap.blk1024 ? 1024 : 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ast_describe(struct ast_softc *stp)
|
||||
{
|
||||
int8_t model_buf[40+1];
|
||||
int8_t revision_buf[8+1];
|
||||
|
||||
bpack(stp->atp->atapi_parm->model, model_buf, sizeof(model_buf));
|
||||
bpack(stp->atp->atapi_parm->revision, revision_buf, sizeof(revision_buf));
|
||||
printf("ast%d: <%s/%s> tape drive at ata%d as %s\n",
|
||||
stp->lun, model_buf, revision_buf,
|
||||
stp->atp->controller->unit,
|
||||
(stp->atp->unit == ATA_MASTER) ? "master" : "slave ");
|
||||
printf("ast%d: ", stp->lun);
|
||||
switch (stp->header.medium_type) {
|
||||
case 0x00: printf("Drive empty"); break;
|
||||
case 0x17: printf("Travan 1 (400 Mbyte) media"); break;
|
||||
case 0xb6: printf("Travan 4 (4 Gbyte) media"); break;
|
||||
default: printf("Unknown media (0x%x)", stp->header.medium_type);
|
||||
}
|
||||
if (stp->cap.readonly) printf(", readonly");
|
||||
if (stp->cap.reverse) printf(", reverse");
|
||||
if (stp->cap.eformat) printf(", eformat");
|
||||
if (stp->cap.qfa) printf(", qfa");
|
||||
if (stp->cap.lock) printf(", lock");
|
||||
if (stp->cap.locked) printf(", locked");
|
||||
if (stp->cap.prevent) printf(", prevent");
|
||||
if (stp->cap.eject) printf(", eject");
|
||||
if (stp->cap.disconnect) printf(", disconnect");
|
||||
if (stp->cap.ecc) printf(", ecc");
|
||||
if (stp->cap.compress) printf(", compress");
|
||||
if (stp->cap.blk512) printf(", 512b");
|
||||
if (stp->cap.blk1024) printf(", 1024b");
|
||||
if (stp->cap.slowb) printf(", slowb");
|
||||
printf("\nast%d: ", stp->lun);
|
||||
printf("Max speed=%dKb/s, ", stp->cap.max_speed);
|
||||
printf("Transfer limit=%d blocks, ", stp->cap.ctl);
|
||||
printf("Buffer size=%d blocks", stp->cap.buffer_size);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int
|
||||
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);
|
||||
if (stp->flags == F_OPEN)
|
||||
return EBUSY;
|
||||
if (ast_sense(stp))
|
||||
printf("ast%d: sense media type failed\n", stp->lun);
|
||||
stp->flags &= ~F_MEDIA_CHANGED;
|
||||
stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
|
||||
stp->flags |= F_OPEN;
|
||||
ast_total = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Flush buffers, some drives fail here, but they should report ctl = 0 */
|
||||
if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
|
||||
ast_write_filemark(stp, 0);
|
||||
|
||||
/* Write filemark if data written to tape */
|
||||
if ((stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
|
||||
ast_write_filemark(stp, WEOF_WRITE_MASK);
|
||||
|
||||
/* If minor is even rewind on close */
|
||||
if (!(minor(dev) & 0x01))
|
||||
ast_rewind(stp);
|
||||
|
||||
stp->flags &= ~F_OPEN;
|
||||
#ifdef AST_DEBUG
|
||||
printf("ast%d: %ud total bytes transferred\n", stp->lun, ast_total);
|
||||
#endif
|
||||
stp->flags &= ~F_CTL_WARN;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
astread(dev_t dev, struct uio *uio, int32_t ioflag)
|
||||
{
|
||||
return (physio(aststrategy, NULL, dev, 1, minphys, uio));
|
||||
}
|
||||
|
||||
static int
|
||||
astwrite(dev_t dev, struct uio *uio, int32_t ioflag)
|
||||
{
|
||||
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
|
||||
astioctl(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 ast_softc *stp;
|
||||
|
||||
if (lun >= astnlun || !(stp = asttab[lun]))
|
||||
return ENXIO;
|
||||
|
||||
switch (cmd) {
|
||||
case MTIOCGET:
|
||||
{
|
||||
struct mtget *g = (struct mtget *) addr;
|
||||
|
||||
bzero(g, sizeof(struct mtget));
|
||||
g->mt_type = 7;
|
||||
g->mt_density = 1;
|
||||
g->mt_blksiz = stp->blksize;
|
||||
g->mt_comp = stp->cap.compress;
|
||||
g->mt_density0 = 0; g->mt_density1 = 0;
|
||||
g->mt_density2 = 0; g->mt_density3 = 0;
|
||||
g->mt_blksiz0 = 0; g->mt_blksiz1 = 0;
|
||||
g->mt_blksiz2 = 0; g->mt_blksiz3 = 0;
|
||||
g->mt_comp0 = 0; g->mt_comp1 = 0;
|
||||
g->mt_comp2 = 0; g->mt_comp3 = 0;
|
||||
break;
|
||||
}
|
||||
case MTIOCTOP:
|
||||
{
|
||||
int32_t i;
|
||||
struct mtop *mt = (struct mtop *)addr;
|
||||
|
||||
switch ((int16_t) (mt->mt_op)) {
|
||||
case MTWEOF:
|
||||
for (i=0; i < mt->mt_count && !error; i++)
|
||||
error = ast_write_filemark(stp, WEOF_WRITE_MASK);
|
||||
break;
|
||||
case MTFSF:
|
||||
if (mt->mt_count)
|
||||
error = ast_space_cmd(stp, SP_FM, mt->mt_count);
|
||||
break;
|
||||
case MTBSF:
|
||||
if (mt->mt_count)
|
||||
error = ast_space_cmd(stp, SP_FM, -(mt->mt_count));
|
||||
break;
|
||||
case MTFSR:
|
||||
error = EINVAL; break;
|
||||
case MTBSR:
|
||||
error = EINVAL; break;
|
||||
case MTREW:
|
||||
error = ast_rewind(stp);
|
||||
break;
|
||||
case MTOFFL:
|
||||
if ((error = ast_rewind(stp)))
|
||||
break;
|
||||
error = ast_load_unload(stp, !LU_LOAD_MASK);
|
||||
break;
|
||||
case MTNOP:
|
||||
error = ast_write_filemark(stp, 0);
|
||||
break;
|
||||
case MTCACHE:
|
||||
error = EINVAL; break;
|
||||
case MTNOCACHE:
|
||||
error = EINVAL; break;
|
||||
case MTSETBSIZ:
|
||||
error = EINVAL; break;
|
||||
case MTSETDNSTY:
|
||||
error = EINVAL; break;
|
||||
case MTERASE:
|
||||
error = ast_erase(stp);
|
||||
break;
|
||||
case MTEOD:
|
||||
error = ast_space_cmd(stp, SP_EOD, 0);
|
||||
break;
|
||||
case MTCOMP:
|
||||
error = EINVAL; break;
|
||||
case MTRETENS:
|
||||
error = ast_load_unload(stp, LU_RETENSION_MASK|LU_LOAD_MASK);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
default:
|
||||
return(ENOTTY);
|
||||
}
|
||||
return(error);
|
||||
}
|
||||
|
||||
static int
|
||||
ast_space_cmd(struct ast_softc *stp, u_int8_t function, u_int32_t count)
|
||||
{
|
||||
int32_t error;
|
||||
int8_t ccb[16];
|
||||
|
||||
bzero(ccb, sizeof(ccb));
|
||||
ccb[0] = ATAPI_TAPE_SPACE_CMD;
|
||||
ccb[1] = function;
|
||||
ccb[2] = count>>16;
|
||||
ccb[3] = count>>8;
|
||||
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
|
||||
ast_write_filemark(struct ast_softc *stp, u_int8_t function)
|
||||
{
|
||||
int32_t error;
|
||||
int8_t ccb[16];
|
||||
|
||||
if (function) {
|
||||
if (stp->flags & F_FM_WRITTEN)
|
||||
stp->flags &= ~F_DATA_WRITTEN;
|
||||
else
|
||||
stp->flags |= F_FM_WRITTEN;
|
||||
}
|
||||
bzero(ccb, sizeof(ccb));
|
||||
ccb[0] = ATAPI_TAPE_WEOF;
|
||||
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
|
||||
ast_load_unload(struct ast_softc *stp, u_int8_t function)
|
||||
{
|
||||
int32_t error;
|
||||
int8_t ccb[16];
|
||||
|
||||
bzero(ccb, sizeof(ccb));
|
||||
ccb[0] = ATAPI_TAPE_LOAD_UNLOAD;
|
||||
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
|
||||
ast_erase(struct ast_softc *stp)
|
||||
{
|
||||
int32_t error;
|
||||
int8_t ccb[16];
|
||||
|
||||
if ((error = ast_rewind(stp)))
|
||||
return error;
|
||||
|
||||
bzero(ccb, sizeof(ccb));
|
||||
ccb[0] = ATAPI_TAPE_ERASE;
|
||||
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
|
||||
ast_rewind(struct ast_softc *stp)
|
||||
{
|
||||
int32_t error;
|
||||
int8_t ccb[16];
|
||||
|
||||
bzero(ccb, sizeof(ccb));
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ast_drvinit(void *unused)
|
||||
{
|
||||
static ast_devsw_installed = 0;
|
||||
|
||||
if (!ast_devsw_installed) {
|
||||
dev_t dev = makedev(CDEV_MAJOR, 0);
|
||||
|
||||
cdevsw_add(&dev, &ast_cdevsw, NULL);
|
||||
ast_devsw_installed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
SYSINIT(astdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, ast_drvinit, NULL)
|
||||
#endif /* NATA & NATAPIST */
|
112
sys/dev/ata/atapi-tape.h
Normal file
112
sys/dev/ata/atapi-tape.h
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
/* ATAPI tape commands not in std ATAPI command set */
|
||||
#define ATAPI_TAPE_REWIND 0x01
|
||||
#define ATAPI_TAPE_REQUEST_SENSE 0x03
|
||||
#define ATAPI_TAPE_READ_CMD 0x08
|
||||
#define ATAPI_TAPE_WRITE_CMD 0x0a
|
||||
#define ATAPI_TAPE_WEOF 0x10
|
||||
#define WEOF_WRITE_MASK 0x01
|
||||
#define ATAPI_TAPE_SPACE_CMD 0x11
|
||||
#define SP_FM 0x01
|
||||
#define SP_EOD 0x03
|
||||
#define ATAPI_TAPE_ERASE 0x19
|
||||
#define ATAPI_TAPE_MODE_SENSE 0x1a
|
||||
#define ATAPI_TAPE_LOAD_UNLOAD 0x1b
|
||||
#define LU_LOAD_MASK 0x01
|
||||
#define LU_RETENSION_MASK 0x02
|
||||
#define LU_EOT_MASK 0x04
|
||||
|
||||
#define DSC_POLL_INTERVAL 10
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 reserved1_67 :2;
|
||||
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 reserved4_1234 :4;
|
||||
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 reserved5_4 :1;
|
||||
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 reserved6_5 :1;
|
||||
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 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 reserved18;
|
||||
u_int8_t reserved19;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
};
|
||||
|
||||
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 ast_header header; /* MODE SENSE param header */
|
||||
struct ast_cappage cap; /* Capabilities page info */
|
||||
struct devstat stats; /* devstat entry */
|
||||
#ifdef DEVFS
|
||||
void *cdevs;
|
||||
void *bdevs;
|
||||
#endif
|
||||
};
|
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.559 1999/02/21 16:23:23 n_hibma Exp $
|
||||
# $Id: LINT,v 1.560 1999/02/22 18:19:57 des Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -1006,6 +1006,24 @@ controller aha0 at isa? port ? cam irq ?
|
||||
|
||||
#!CAM# controller aic0 at isa? port 0x340 bio irq 11
|
||||
|
||||
#
|
||||
# ATA and ATAPI devices
|
||||
# This is work in progress, use at your own risk.
|
||||
# It currently reuses the majors of wd.c and freinds.
|
||||
# It cannot co-exist with the old system in one kernel.
|
||||
# You only need one "controller ata0" for it to find all
|
||||
# PCI devices on modern machines.
|
||||
#controller ata0
|
||||
#device atadisk0 # ATA disk drives
|
||||
#device atapicd0 # ATAPI CDROM drives
|
||||
#device atapist0 # ATAPI tape drives
|
||||
#
|
||||
# If you need ISA only devices, this is the lines to add:
|
||||
#controller ata1 at isa? port "IO_WD1" bio irq 14
|
||||
#controller ata2 at isa? port "IO_WD2" bio irq 15
|
||||
#
|
||||
# All the controller lines can coexist, the driver will
|
||||
# find out which ones are there.
|
||||
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
|
@ -2,7 +2,7 @@
|
||||
# LINT -- config file for checking all the sources, tries to pull in
|
||||
# as much of the source tree as it can.
|
||||
#
|
||||
# $Id: LINT,v 1.559 1999/02/21 16:23:23 n_hibma Exp $
|
||||
# $Id: LINT,v 1.560 1999/02/22 18:19:57 des Exp $
|
||||
#
|
||||
# NB: You probably don't want to try running a kernel built from this
|
||||
# file. Instead, you should start from GENERIC, and add options from
|
||||
@ -1006,6 +1006,24 @@ controller aha0 at isa? port ? cam irq ?
|
||||
|
||||
#!CAM# controller aic0 at isa? port 0x340 bio irq 11
|
||||
|
||||
#
|
||||
# ATA and ATAPI devices
|
||||
# This is work in progress, use at your own risk.
|
||||
# It currently reuses the majors of wd.c and freinds.
|
||||
# It cannot co-exist with the old system in one kernel.
|
||||
# You only need one "controller ata0" for it to find all
|
||||
# PCI devices on modern machines.
|
||||
#controller ata0
|
||||
#device atadisk0 # ATA disk drives
|
||||
#device atapicd0 # ATAPI CDROM drives
|
||||
#device atapist0 # ATAPI tape drives
|
||||
#
|
||||
# If you need ISA only devices, this is the lines to add:
|
||||
#controller ata1 at isa? port "IO_WD1" bio irq 14
|
||||
#controller ata2 at isa? port "IO_WD2" bio irq 15
|
||||
#
|
||||
# All the controller lines can coexist, the driver will
|
||||
# find out which ones are there.
|
||||
|
||||
#
|
||||
# ST-506, ESDI, and IDE hard disks: `wdc' and `wd'
|
||||
|
@ -1,7 +1,7 @@
|
||||
# This file tells config what files go into building a kernel,
|
||||
# files marked standard are always included.
|
||||
#
|
||||
# $Id: files.i386,v 1.222 1999/02/11 07:11:00 gibbs Exp $
|
||||
# $Id: files.i386,v 1.223 1999/02/20 11:17:59 julian Exp $
|
||||
#
|
||||
# The long compile-with and dependency lines are required because of
|
||||
# limitations in config: backslash-newline doesn't work in strings, and
|
||||
@ -24,6 +24,11 @@ font8x16.o optional std8x16font \
|
||||
no-implicit-rule before-depend \
|
||||
clean "${STD8X16FONT}-8x16 font8x16.c"
|
||||
#
|
||||
dev/ata/ata-all.c optional ata device-driver
|
||||
dev/ata/atapi-all.c optional ata device-driver
|
||||
dev/ata/ata-disk.c optional atadisk device-driver
|
||||
dev/ata/atapi-cd.c optional atapicd device-driver
|
||||
dev/ata/atapi-tape.c optional atapist device-driver
|
||||
dev/fb/fb.c optional fb device-driver
|
||||
dev/fb/fb.c optional vga device-driver
|
||||
dev/fb/splash.c optional splash
|
||||
|
Loading…
Reference in New Issue
Block a user