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

Ten'th update to the new ATA/ATAPI driver:

It been awhile since the last major update, as a benefit there
are some cool things in this one (and new bugs probably :) )...

The ATA driver has grown "real" timeout support for all devices.
This means that it should be possible to get in contact with
(especially) lost ATAPI devices. It also means that the ATA
driver is now usable on notebooks as it will DTRT on resume.

An experimental hack at utilizing the Promise66's at UDMA66 is
in there, but I cant test it. If someone feels like sending
me one, give me a ping.

The ATAPI DMA enableling scheme has been changed, also better DMA
support for the Aladdin chipset has been implemented for ATAPI
devices. Note that the Aladdin apparently only can do DMA reads
on ATAPI devices, and the Promise cant do ATAPI DMA at all.
I have seen problems on some ATAPI devices that should be able
to run in DMA mode, so if you encounter problems with hanging
atapi devices during the probe, or during access, disable DMA
in atapi-all.c, and let me know. It might be nessesary to do this
via a "white list" for known good devices...

The ATAPI CDROM driver can now use eject/close without hanging and
the bug that caused reading beyond the end of a CD has been fixed.
Media change is also handled proberly. DVD drives are identified
and are usable as CDROM devices at least, I dont have the HW to
test this further, see above :).

The ATAPI tape driver has gotten some support for using the DSC
method for not blocking the IDE channel during read/write when
the device has full buffers. It knows about the OnStream DI-30
device, support is not completed yet, but it can function as a
primitive backup medium, without filemarks, and without bad media
handeling. This is because the OnStream device doesn't handle this
(like everybody else) in HW. It also now supports getting/setting
the record position on devices that supports it.

Some rather major cleanups and rearrangements as well (cvs -b diff
is your freind). I'm closing in on declaring this for beta code,
most of the infrastruture is in place by now.

As usual USE AT YOUR OWN RISK!!, this is still alpha level code.
This driver can hose your disk real bad if anything goes wrong, but
now you have been warned :)

But please tell me how it works for you!

Enjoy!

-Søren
This commit is contained in:
Søren Schmidt 1999-09-21 19:50:40 +00:00
parent 3a049969b5
commit 3427651043
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=51520
13 changed files with 2682 additions and 2125 deletions

View File

@ -29,16 +29,23 @@
*/
#include "ata.h"
#include "apm.h"
#if NATA > 0
#include "isa.h"
#include "pci.h"
#include "atadisk.h"
#include "atapicd.h"
#include "atapifd.h"
#include "atapist.h"
#include "opt_global.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/interrupt.h>
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/buf.h>
@ -49,25 +56,27 @@
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/clock.h>
#ifdef __i386__
#include <machine/smp.h>
#include <i386/isa/intr_machdep.h>
#endif
#if NPCI > 0
#include <pci/pcivar.h>
#include <pci/pcireg.h>
#endif
#include <isa/isavar.h>
#include <isa/isareg.h>
#include <machine/clock.h>
#ifdef __i386__
#include <machine/smp.h>
#include <i386/isa/intr_machdep.h>
#endif
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#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 */
#define MIN(a,b) ((a)>(b)?(b):(a))
#if SMP == 0
#define isa_apic_irq(x) x
#define isa_apic_irq(x) x
#endif
/* prototypes */
@ -129,7 +138,6 @@ ata_isaprobe(device_t dev)
*(int *)device_get_softc(dev) = lun;
return 0;
}
return ENXIO;
}
@ -171,11 +179,9 @@ static driver_t ata_isa_driver = {
};
DRIVER_MODULE(ata, isa, ata_isa_driver, ata_devclass, 0, 0);
#endif
#if NPCI > 0
static const char *
ata_pcimatch(device_t dev)
{
@ -199,20 +205,19 @@ ata_pcimatch(device_t dev)
return "Promise Ultra/66 IDE controller";
case 0x522910b9:
return "AcerLabs Aladdin IDE controller";
#if 0
case 0x05711106:
return "VIA Apollo IDE controller";
case 0x05711106: /* 82c586 */
case 0x05961106: /* 82c596 */
return "VIA Apollo IDE controller (generic mode)";
case 0x06401095:
return "CMD 640 IDE controller";
return "CMD 640 IDE controller (generic mode)";
case 0x06461095:
return "CMD 646 IDE controller";
return "CMD 646 IDE controller (generic mode)";
case 0xc6931080:
return "Cypress 82C693 IDE controller";
return "Cypress 82C693 IDE controller (generic mode)";
case 0x01021078:
return "Cyrix 5530 IDE controller";
#endif
return "Cyrix 5530 IDE controller (generic mode)";
default:
return "Unknown PCI IDE controller (using generic mode)";
return "Unknown PCI IDE controller (generic mode)";
}
}
return NULL;
@ -260,7 +265,7 @@ ata_pciattach(device_t dev)
iobase_2 = pci_read_config(dev, 0x18, 4) & 0xfffc;
altiobase_2 = pci_read_config(dev, 0x1c, 4) & 0xfffc;
irq1 = irq2 = pci_read_config(dev, PCI_INTERRUPT_REG, 4) & 0xff;
bmaddr_1 = pci_read_config(dev, 0x20, 4) & 0xfffc;
bmaddr_1 = pci_read_config(dev, 0x20, 4) & 0xfffc;
bmaddr_2 = bmaddr_1 + ATA_BM_OFFSET1;
outb(bmaddr_1 + 0x1f, inb(bmaddr_1 + 0x1f) | 0x01);
printf("ata-pci%d: Busmastering DMA supported\n", unit);
@ -290,22 +295,22 @@ ata_pciattach(device_t dev)
irq2 = pci_read_config(dev, PCI_INTERRUPT_REG, 4) & 0xff;
}
/* is this controller busmaster capable ? */
if (pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) {
/* is this controller busmaster capable ? */
if (pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) {
/* is busmastering support turned on ? */
if ((pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4) & 5) == 5) {
/* is there a valid port range to connect to ? */
if ((bmaddr_1 = pci_read_config(dev, 0x20, 4) & 0xfffc)) {
/* is there a valid port range to connect to ? */
if ((bmaddr_1 = pci_read_config(dev, 0x20, 4) & 0xfffc)) {
bmaddr_2 = bmaddr_1 + ATA_BM_OFFSET1;
printf("ata-pci%d: Busmastering DMA supported\n", unit);
}
else
}
else
printf("ata-pci%d: Busmastering DMA not configured\n",unit);
}
else
printf("ata-pci%d: Busmastering DMA not enabled\n", unit);
}
else
printf("ata-pci%d: Busmastering DMA not enabled\n", unit);
}
else
printf("ata-pci%d: Busmastering DMA not supported\n", unit);
}
@ -316,7 +321,7 @@ ata_pciattach(device_t dev)
if (iobase_1 == IO_WD1)
#ifdef __i386__
inthand_add(device_get_nameunit(dev), irq1, ataintr, scp,
&bio_imask, INTR_EXCL);
&bio_imask, INTR_EXCL);
#endif
#ifdef __alpha__
alpha_platform_setup_ide_intr(0, ataintr, scp);
@ -331,7 +336,7 @@ ata_pciattach(device_t dev)
if (!irq)
printf("ata_pciattach: Unable to alloc interrupt\n");
if (type == 0x4d33105a || type == 0x4d38105a)
if (type == 0x4d33105a || type == 0x4d38105a)
bus_setup_intr(dev, irq, INTR_TYPE_BIO, promise_intr, scp, &ih);
else
bus_setup_intr(dev, irq, INTR_TYPE_BIO, ataintr, scp, &ih);
@ -345,7 +350,7 @@ ata_pciattach(device_t dev)
if (iobase_2 == IO_WD2)
#ifdef __i386__
inthand_add(device_get_nameunit(dev), irq2, ataintr, scp,
&bio_imask, INTR_EXCL);
&bio_imask, INTR_EXCL);
#endif
#ifdef __alpha__
alpha_platform_setup_ide_intr(1, ataintr, scp);
@ -355,10 +360,10 @@ ata_pciattach(device_t dev)
int rid = 0;
void *ih;
if (type != 0x4d33105a && type != 0x4d38105a) {
irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
if (type != 0x4d33105a && type != 0x4d38105a) {
irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
RF_SHAREABLE | RF_ACTIVE);
if (!irq)
if (!irq)
printf("ata_pciattach: Unable to alloc interrupt\n");
bus_setup_intr(dev, irq, INTR_TYPE_BIO, ataintr, scp, &ih);
@ -405,7 +410,6 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr,
{
struct ata_softc *scp = atadevices[atanlun];
int32_t mask = 0;
int32_t timeout;
int32_t lun = atanlun;
u_int8_t status0, status1;
@ -433,79 +437,39 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr,
scp->altioaddr = altioaddr;
scp->active = ATA_IDLE;
#ifdef ATA_DEBUG
printf("ata%d: iobase=0x%04x altiobase=0x%04x\n",
scp->lun, scp->ioaddr, scp->altioaddr);
#endif
if (bootverbose)
printf("ata%d: iobase=0x%04x altiobase=0x%04x\n",
scp->lun, scp->ioaddr, scp->altioaddr);
/* 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);
DELAY(1);
status1 = inb(scp->ioaddr + ATA_STATUS);
if ((status0 & 0xf8) != 0xf8)
mask |= 0x01;
mask |= 0x01;
if ((status1 & 0xf8) != 0xf8)
mask |= 0x02;
#ifdef ATA_DEBUG
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
scp->lun, mask, status0, status1);
#endif
mask |= 0x02;
if (bootverbose)
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
scp->lun, mask, status0, status1);
if (!mask) {
free(scp, M_DEVBUF);
return 0;
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);
DELAY(1);
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",
scp->lun, mask, status0, status1);
#endif
ata_reset(scp, &mask);
if (!mask) {
free(scp, M_DEVBUF);
return 0;
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 &&
@ -519,28 +483,27 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr,
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 &&
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) {
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", scp->lun, scp->devices);
#endif
if (bootverbose)
printf("ata%d: devices = 0x%x\n", scp->lun, scp->devices);
if (!scp->devices) {
free(scp, M_DEVBUF);
return 0;
@ -550,10 +513,17 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr,
*unit = scp->lun;
scp->dev = dev;
if (bmaddr)
scp->bmaddr = bmaddr;
scp->bmaddr = bmaddr;
atadevices[scp->lun] = scp;
#ifndef ATA_STATIC_ID
atanlun++;
#endif
#if NAPM > 0
scp->resume_hook.ah_fun = (void *)ata_reinit;
scp->resume_hook.ah_arg = scp;
scp->resume_hook.ah_name = "ATA driver";
scp->resume_hook.ah_order = APM_MID_ORDER;
apm_hook_establish(APM_HOOK_RESUME, &scp->resume_hook);
#endif
return ATA_IOSIZE;
}
@ -561,29 +531,24 @@ ata_probe(int32_t ioaddr, int32_t altioaddr, int32_t bmaddr,
static void
ataintr(void *data)
{
struct ata_softc *scp;
struct atapi_request *atapi_request;
struct ad_request *ad_request;
u_int8_t status;
static int32_t intr_count = 0;
struct ata_softc *scp =(struct ata_softc *)data;
scp = (struct ata_softc *)data;
scp->status = inb(scp->ioaddr + ATA_STATUS);
/* find & call the responsible driver to process this interrupt */
switch (scp->active) {
#if NATADISK > 0
case ATA_ACTIVE_ATA:
if ((ad_request = TAILQ_FIRST(&scp->ata_queue)))
if (ad_interrupt(ad_request) == ATA_OP_CONTINUES)
if (ad_interrupt(scp->running) == ATA_OP_CONTINUES)
return;
break;
#endif
#if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0
case ATA_ACTIVE_ATAPI:
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue)))
if (atapi_interrupt(atapi_request) == ATA_OP_CONTINUES)
if (atapi_interrupt(scp->running) == ATA_OP_CONTINUES)
return;
break;
#endif
case ATA_WAIT_INTR:
wakeup((caddr_t)scp);
break;
@ -593,13 +558,18 @@ ataintr(void *data)
default:
case ATA_IDLE:
status = inb(scp->ioaddr + ATA_STATUS);
if (intr_count++ < 10)
printf("ata%d: unwanted interrupt %d status = %02x\n",
scp->lun, intr_count, status);
#ifdef ATA_DEBUG
{
static int32_t intr_count = 0;
if (intr_count++ < 10)
printf("ata%d: unwanted interrupt %d status = %02x\n",
scp->lun, intr_count, scp->status);
}
#endif
return;
}
scp->active = ATA_IDLE;
scp->running = NULL;
ata_start(scp);
}
@ -612,32 +582,141 @@ ata_start(struct ata_softc *scp)
#ifdef ATA_DEBUG
printf("ata_start: entered\n");
#endif
if (scp->active != ATA_IDLE) {
printf("ata: unwanted ata_start\n");
if (scp->active != ATA_IDLE)
return;
}
#if NATADISK > 0
/* find & call the responsible driver if anything on ATA queue */
if ((ad_request = TAILQ_FIRST(&scp->ata_queue))) {
TAILQ_REMOVE(&scp->ata_queue, ad_request, chain);
scp->active = ATA_ACTIVE_ATA;
ad_transfer(ad_request);
scp->running = ad_request;
ad_transfer(ad_request);
#ifdef ATA_DEBUG
printf("ata_start: started ata, leaving\n");
printf("ata_start: started ata, leaving\n");
#endif
return;
}
#endif
/* find & call the responsible driver if anything on ATAPI queue */
#if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0
/*
* find & call the responsible driver if anything on ATAPI queue.
* check for device busy by polling the DSC bit, if busy, check
* for requests to the other device on the channel (if any).
* if no request can be served, timeout a call to ata_start to
* try again in a moment. the timeout should probably scale
* so we dont use too much time polling for slow devices.
*/
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue))) {
scp->active = ATA_ACTIVE_ATAPI;
struct atapi_softc *atp = atapi_request->device;
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
DELAY(1);
if (!(inb(atp->controller->ioaddr + ATA_STATUS) & ATA_S_DSC)) {
while ((atapi_request = TAILQ_NEXT(atapi_request, chain))) {
if (atapi_request->device->unit != atp->unit) {
struct atapi_softc *tmpatp = atapi_request->device;
outb(tmpatp->controller->ioaddr + ATA_DRIVE,
ATA_D_IBM | tmpatp->unit);
DELAY(1);
if (!(inb(tmpatp->controller->ioaddr+ATA_STATUS)&ATA_S_DSC))
atapi_request = NULL;
break;
}
}
}
if (!atapi_request) {
timeout((timeout_t*)ata_start, scp, 1);
return;
}
TAILQ_REMOVE(&scp->atapi_queue, atapi_request, chain);
scp->active = ATA_ACTIVE_ATAPI;
scp->running = atapi_request;
atapi_transfer(atapi_request);
#ifdef ATA_DEBUG
printf("ata_start: started atapi, leaving\n");
printf("ata_start: started atapi, leaving\n");
#endif
return;
}
#endif
}
void
ata_reset(struct ata_softc *scp, int32_t *mask)
{
int32_t timeout;
int8_t status0, status1;
/* reset channel */
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(1);
inb(scp->ioaddr + ATA_STATUS);
outb(scp->altioaddr, ATA_A_IDS | ATA_A_RESET);
DELAY(10000);
outb(scp->altioaddr, ATA_A_IDS);
DELAY(10000);
inb(scp->ioaddr + ATA_ERROR);
DELAY(1);
outb(scp->altioaddr, ATA_A_4BIT);
DELAY(1);
/* wait for BUSY to go inactive */
for (timeout = 0; timeout < 300000; 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;
if (bootverbose)
printf("ata%d: mask=%02x status0=%02x status1=%02x\n",
scp->lun, *mask, status0, status1);
}
int32_t
ata_reinit(struct ata_softc *scp)
{
int32_t mask = 0;
printf("ata%d: resetting devices .. ", scp->lun);
scp->active = ATA_IDLE;
if (scp->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))
mask |= 0x01;
if (scp->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))
mask |= 0x02;
ata_reset(scp, &mask);
#if NATADISK > 0
if (scp->devices & (ATA_ATA_MASTER))
ad_reinit((struct ad_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATA_SLAVE))
ad_reinit((struct ad_softc *)scp->dev_softc[1]);
#endif
#if NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0
if (scp->devices & (ATA_ATAPI_MASTER))
atapi_reinit((struct atapi_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATAPI_SLAVE))
atapi_reinit((struct atapi_softc *)scp->dev_softc[1]);
#endif
printf("done\n");
ata_start(scp);
return 0;
}
int32_t
@ -646,14 +725,14 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
u_int8_t status;
u_int32_t timeout = 0;
while (timeout++ <= 500000) { /* timeout 5 secs */
while (timeout <= 5000000) { /* timeout 5 secs */
status = inb(scp->ioaddr + ATA_STATUS);
/* if drive fails status, reselect the drive just to be sure */
if (status == 0xff) {
printf("ata%d: %s: no status, reselecting device\n",
printf("ata%d: %s: no status, reselecting device\n",
scp->lun, device?"slave":"master");
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
outb(scp->ioaddr + ATA_DRIVE, ATA_D_IBM | device);
DELAY(1);
status = inb(scp->ioaddr + ATA_STATUS);
}
@ -665,11 +744,15 @@ ata_wait(struct ata_softc *scp, int32_t device, u_int8_t mask)
scp->error = inb(scp->ioaddr + ATA_ERROR);
if ((status & mask) == mask)
return (status & ATA_S_ERROR);
}
if (timeout > 1000)
}
if (timeout > 1000) {
timeout += 1000;
DELAY(1000);
else
}
else {
timeout += 10;
DELAY(10);
}
}
return -1;
}
@ -680,12 +763,15 @@ ata_command(struct ata_softc *scp, int32_t device, u_int32_t command,
u_int32_t count, u_int32_t feature, int32_t flags)
{
#ifdef ATA_DEBUG
printf("ata%d: ata_command: addr=%04x, device=%02x, cmd=%02x, c=%d, h=%d, s=%d, count=%d, flags=%02x\n", scp->lun, scp->ioaddr, device, command, cylinder, head, sector, count, flags);
printf("ata%d: ata_command: addr=%04x, device=%02x, cmd=%02x, "
"c=%d, h=%d, s=%d, count=%d, flags=%02x\n",
scp->lun, scp->ioaddr, device, command,
cylinder, head, sector, count, flags);
#endif
/* ready to issue command ? */
if (ata_wait(scp, device, 0) < 0) {
printf("ata%d: %s: timeout waiting to give command s=%02x e=%02x\n",
printf("ata%d-%s: timeout waiting to give command s=%02x e=%02x\n",
scp->lun, device?"slave":"master", scp->status, scp->error);
}
outb(scp->ioaddr + ATA_FEATURE, feature);
@ -700,8 +786,8 @@ printf("ata%d: ata_command: addr=%04x, device=%02x, cmd=%02x, c=%d, h=%d, s=%d,
switch (flags) {
case ATA_WAIT_INTR:
scp->active = ATA_WAIT_INTR;
outb(scp->ioaddr + ATA_CMD, command);
scp->active = ATA_WAIT_INTR;
outb(scp->ioaddr + ATA_CMD, command);
if (tsleep((caddr_t)scp, PRIBIO, "atacmd", 500)) {
printf("ata_command: timeout waiting for interrupt\n");
scp->active = ATA_IDLE;
@ -710,28 +796,45 @@ printf("ata%d: ata_command: addr=%04x, device=%02x, cmd=%02x, c=%d, h=%d, s=%d,
break;
case ATA_IGNORE_INTR:
scp->active = ATA_IGNORE_INTR;
outb(scp->ioaddr + ATA_CMD, command);
scp->active = ATA_IGNORE_INTR;
outb(scp->ioaddr + ATA_CMD, command);
break;
case ATA_IMMEDIATE:
default:
outb(scp->ioaddr + ATA_CMD, command);
outb(scp->ioaddr + ATA_CMD, command);
break;
}
#ifdef ATA_DEBUG
printf("ata_command: leaving\n");
printf("ata_command: leaving\n");
#endif
return 0;
}
int8_t *
ata_mode2str(int32_t mode)
{
switch (mode) {
case ATA_MODE_PIO:
return "PIO";
case ATA_MODE_DMA:
return "DMA";
case ATA_MODE_UDMA33:
return "UDMA33";
case ATA_MODE_UDMA66:
return "UDMA66";
default:
return "???";
}
}
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);
*p = ntohs(*p);
}
void
@ -740,10 +843,10 @@ btrim(int8_t *buf, int32_t len)
int8_t *p;
for (p = buf; p < buf+len; ++p)
if (!*p)
*p = ' ';
if (!*p)
*p = ' ';
for (p = buf + len - 1; p >= buf && *p == ' '; --p)
*p = 0;
*p = 0;
}
void
@ -758,8 +861,11 @@ bpack(int8_t *src, int8_t *dst, int32_t len)
blank = 0;
continue;
}
if (src[i] == ' ')
if (src[i] == ' ') {
blank = 1;
if (i == 0)
continue;
}
dst[j++] = src[i];
}
dst[j] = 0x00;

View File

@ -30,7 +30,7 @@
/* ATA register defines */
#define ATA_DATA 0x00 /* data register */
#define ATA_ERROR 0x01 /* (R) error register */
#define ATA_ERROR 0x01 /* (R) error register */
#define ATA_FEATURE 0x01 /* (W) feature register */
#define ATA_F_DMA 0x01 /* enable DMA */
#define ATA_F_OVL 0x02 /* enable overlap */
@ -42,24 +42,25 @@
#define ATA_I_RELEASE 0x04 /* released bus (1) */
#define ATA_I_TAGMASK 0xf8 /* tag mask */
#define ATA_SECTOR 0x03 /* sector # */
#define ATA_CYL_LSB 0x04 /* cylinder# LSB */
#define ATA_CYL_MSB 0x05 /* cylinder# MSB */
#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_LBA 0x40 /* use LBA adressing */
#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_ATAPI_RESET 0x08 /* reset ATAPI device */
#define ATA_C_READ 0x20 /* read command */
#define ATA_C_WRITE 0x30 /* write command */
#define ATA_C_PACKET_CMD 0xa0 /* packet command */
#define ATA_C_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
#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_READ_DMA 0xc8 /* read w/DMA command */
#define ATA_C_WRITE_DMA 0xca /* write w/DMA command */
#define ATA_C_PACKET_CMD 0xa0 /* packet command */
#define ATA_C_ATA_IDENTIFY 0xec /* get ATA params */
#define ATA_C_SETFEATURES 0xef /* features command */
#define ATA_C_FEA_SETXFER 0x03 /* set transfer mode */
@ -76,14 +77,14 @@
#define ATA_S_BSY 0x80 /* busy */
#define ATA_ALTPORT 0x206 /* alternate Status register */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_IDS 0x02 /* disable interrupts */
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
#define ATA_A_4BIT 0x08 /* 4 head bits */
/* misc defines */
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
#define ATA_IOSIZE 0x08
#define ATA_MASTER 0x00
#define ATA_SLAVE 0x10
#define ATA_IOSIZE 0x08
#define ATA_OP_FINISHED 0x00
#define ATA_OP_CONTINUES 0x01
@ -97,24 +98,26 @@
#define ATA_BMCMD_WRITE_READ 0x08
#define ATA_BMSTAT_PORT 0x02
#define ATA_BMSTAT_MASK 0x07
#define ATA_BMSTAT_ACTIVE 0x01
#define ATA_BMSTAT_ERROR 0x02
#define ATA_BMSTAT_INTERRUPT 0x04
#define ATA_BMSTAT_MASK 0x07
#define ATA_BMSTAT_DMA_MASTER 0x20
#define ATA_BMSTAT_DMA_SLAVE 0x40
#define ATA_BMDTP_PORT 0x04
#define ATA_WDMA2 0x22
#define ATA_UDMA2 0x42
/* structure for holding DMA address data */
struct ata_dmaentry {
u_int32_t base;
u_int32_t count;
u_int32_t base;
u_int32_t count;
};
/* ATA device DMA access modes */
#define ATA_WDMA2 0x22
#define ATA_UDMA2 0x42
#define ATA_UDMA4 0x44
/* structure describing an ATA device */
struct ata_softc {
int32_t unit; /* unit on this controller */
@ -123,13 +126,22 @@ struct ata_softc {
int32_t ioaddr; /* port addr */
int32_t altioaddr; /* alternate port addr */
int32_t bmaddr; /* bus master DMA port */
void *dev_softc[2]; /* ptr to devices softc's */
struct ata_dmaentry *dmatab[2]; /* DMA transfer tables */
int32_t mode[2]; /* transfer mode for devices */
#define ATA_MODE_PIO 0x00
#define ATA_MODE_DMA 0x01
#define ATA_MODE_UDMA33 0x02
#define ATA_MODE_UDMA66 0x04
int32_t flags; /* controller flags */
#define ATA_ATAPI_DMA_RO 0x01
int32_t devices; /* what is present */
#define ATA_ATA_MASTER 0x01
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
#define ATA_ATA_SLAVE 0x02
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
u_int8_t status; /* last controller status */
u_int8_t error; /* last controller error */
@ -141,8 +153,13 @@ struct ata_softc {
#define ATA_ACTIVE_ATA 0x3
#define ATA_ACTIVE_ATAPI 0x4
TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */
TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */
TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */
TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */
void *running; /* currently running request */
#if NAPM > 0
struct apmhook resume_hook; /* hook for apm */
#endif
};
#define MAXATA 8
@ -151,6 +168,8 @@ extern struct ata_softc *atadevices[];
/* public prototypes */
void ata_start(struct ata_softc *);
void ata_reset(struct ata_softc *, int32_t *);
int32_t ata_reinit(struct ata_softc *);
int32_t ata_wait(struct ata_softc *, int32_t, u_int8_t);
int32_t ata_command(struct ata_softc *, int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, u_int32_t, int32_t);
int32_t ata_dmainit(struct ata_softc *, int32_t, int32_t, int32_t, int32_t);
@ -158,10 +177,7 @@ int32_t ata_dmasetup(struct ata_softc *, int32_t, int8_t *, int32_t, int32_t);
void ata_dmastart(struct ata_softc *, int32_t);
int32_t ata_dmastatus(struct ata_softc *, int32_t);
int32_t ata_dmadone(struct ata_softc *, int32_t);
int8_t *ata_mode2str(int32_t);
void bswap(int8_t *, int32_t);
void btrim(int8_t *, int32_t);
void bpack(int8_t *, int8_t *, int32_t);
void ad_transfer(struct ad_request *);
int32_t ad_interrupt(struct ad_request *);

View File

@ -30,6 +30,8 @@
#include "ata.h"
#include "atadisk.h"
#include "apm.h"
#if NATA > 0 && NATADISK > 0
#include <sys/param.h>
@ -51,12 +53,15 @@
#include <vm/vm_object.h>
#include <machine/clock.h>
#include <machine/md_var.h>
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-disk.h>
static d_open_t adopen;
static d_strategy_t adstrategy;
static d_dump_t addump;
static d_dump_t addump;
static struct cdevsw ad_cdevsw = {
/* open */ adopen,
@ -83,54 +88,49 @@ static struct cdevsw addisk_cdevsw;
static struct cdevsw fakewd_cdevsw;
static struct cdevsw fakewddisk_cdevsw;
/* misc defines */
#define UNIT(dev) (minor(dev)>>3 & 0x1f) /* assume 8 minor # per unit */
#define NUNIT 16 /* max # of devices */
/* prototypes */
static void ad_attach(void *);
static int32_t ad_getparam(struct ad_softc *);
static void ad_start(struct ad_softc *);
static void ad_timeout(struct ad_request *);
static void ad_sleep(struct ad_softc *, int8_t *);
static int8_t ad_version(u_int16_t);
int32_t ad_timeout(char *data);
static void ad_drvinit(void);
/* internal vars */
static struct ad_softc *adtab[NUNIT];
static int32_t adnlun = 0; /* number of config'd drives */
static int32_t adnlun = 0; /* number of config'd drives */
static struct intr_config_hook *ad_attach_hook;
static __inline int
apiomode(struct ata_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->apiomodes & 2) == 2) return 4;
if ((ap->apiomodes & 1) == 1) return 3;
}
return -1;
if ((ap->atavalid & 2) == 2) {
if ((ap->apiomodes & 2) == 2) return 4;
if ((ap->apiomodes & 1) == 1) return 3;
}
return -1;
}
static __inline int
wdmamode(struct ata_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->wdmamodes & 4) == 4) return 2;
if ((ap->wdmamodes & 2) == 2) return 1;
if ((ap->wdmamodes & 1) == 1) return 0;
}
return -1;
if ((ap->atavalid & 2) == 2) {
if ((ap->wdmamodes & 4) == 4) return 2;
if ((ap->wdmamodes & 2) == 2) return 1;
if ((ap->wdmamodes & 1) == 1) return 0;
}
return -1;
}
static __inline int
udmamode(struct ata_params *ap)
{
if ((ap->atavalid & 4) == 4) {
if ((ap->udmamodes & 4) == 4) return 2;
if ((ap->udmamodes & 2) == 2) return 1;
if ((ap->udmamodes & 1) == 1) return 0;
}
return -1;
if ((ap->atavalid & 4) == 4) {
if ((ap->udmamodes & 4) == 4) return 2;
if ((ap->udmamodes & 2) == 2) return 1;
if ((ap->udmamodes & 1) == 1) return 0;
}
return -1;
}
static void
@ -144,23 +144,20 @@ ad_attach(void *notused)
/* now, run through atadevices and look for ATA disks */
for (ctlr=0; ctlr<MAXATA; ctlr++) {
if (!atadevices[ctlr]) continue;
if (!atadevices[ctlr]) continue;
for (dev=0; dev<2; dev++) {
if (atadevices[ctlr]->devices &
(dev ? ATA_ATA_SLAVE : ATA_ATA_MASTER)) {
#ifdef ATA_STATIC_ID
adnlun = dev + ctlr * 2;
#endif
adp = adtab[adnlun];
if (adp)
printf("ad%d: unit already attached\n", adnlun);
if (!(adp = malloc(sizeof(struct ad_softc),
if (!(adp = malloc(sizeof(struct ad_softc),
M_DEVBUF, M_NOWAIT))) {
printf("ad%d: failed to allocate driver storage\n", adnlun);
printf("ad%d: failed to allocate driver storage\n", adnlun);
continue;
}
bzero(adp, sizeof(struct ad_softc));
adp->controller = atadevices[ctlr];
bzero(adp, sizeof(struct ad_softc));
adp->controller = atadevices[ctlr];
adp->unit = (dev == 0) ? ATA_MASTER : ATA_SLAVE;
adp->lun = adnlun;
if (ad_getparam(adp)) {
@ -170,11 +167,11 @@ ad_attach(void *notused)
adp->cylinders = adp->ata_parm->cylinders;
adp->heads = adp->ata_parm->heads;
adp->sectors = adp->ata_parm->sectors;
adp->total_secs = adp->cylinders * adp->heads * adp->sectors;
if (adp->cylinders == 16383 &&
adp->total_secs = adp->cylinders * adp->heads * adp->sectors;
if (adp->cylinders == 16383 &&
adp->total_secs < adp->ata_parm->lbasize) {
adp->total_secs = adp->ata_parm->lbasize;
adp->cylinders = adp->total_secs/(adp->heads*adp->sectors);
adp->cylinders = adp->total_secs/(adp->heads*adp->sectors);
}
if (adp->ata_parm->atavalid & ATA_FLAG_54_58 &&
adp->ata_parm->lbasize)
@ -183,61 +180,64 @@ ad_attach(void *notused)
/* use multiple sectors/interrupt if device supports it */
adp->transfersize = DEV_BSIZE;
secsperint = min(adp->ata_parm->nsecperint, 16);
if (!ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI,
0, 0, 0, secsperint, 0, ATA_WAIT_INTR) &&
ata_wait(adp->controller, adp->unit, ATA_S_DRDY) >= 0)
adp->transfersize *= secsperint;
/* use DMA if drive & controller supports it */
if (!ata_dmainit(adp->controller, adp->unit,
apiomode(adp->ata_parm),
wdmamode(adp->ata_parm),
udmamode(adp->ata_parm)))
adp->flags |= AD_F_DMA_ENABLED;
if (!ata_dmainit(adp->controller, adp->unit,
apiomode(adp->ata_parm),
wdmamode(adp->ata_parm),
udmamode(adp->ata_parm)))
adp->flags |= AD_F_DMA_ENABLED;
/* use tagged queue if supported */
/* use tagged queueing if supported (not yet) */
if ((adp->num_tags = adp->ata_parm->queuelen & 0x1f))
adp->flags |= AD_F_TAG_ENABLED;
bpack(adp->ata_parm->model, model_buf, sizeof(model_buf));
/* store our softc */
adp->controller->dev_softc[(adp->unit==ATA_MASTER)?0:1] = adp;
bpack(adp->ata_parm->model, model_buf, sizeof(model_buf));
bpack(adp->ata_parm->revision, revision_buf,
sizeof(revision_buf));
if (bootverbose)
printf("ad%d: piomode=%d dmamode=%d udmamode=%d\n",
adnlun, apiomode(adp->ata_parm),
wdmamode(adp->ata_parm), udmamode(adp->ata_parm));
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,
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: piomode=%d, dmamode=%d, udmamode=%d\n",
adnlun,
apiomode(adp->ata_parm),
wdmamode(adp->ata_parm),
udmamode(adp->ata_parm));
printf("ad%d: %d secs/int, %d depth queue, %s mode\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, %s\n",
adnlun, adp->transfersize / DEV_BSIZE, adp->num_tags,
(adp->flags & AD_F_DMA_ENABLED) ? "DMA" :"PIO");
devstat_add_entry(&adp->stats, "ad", adnlun, DEV_BSIZE,
ata_mode2str(adp->controller->mode[
(adp->unit == ATA_MASTER) ? 0 : 1]));
devstat_add_entry(&adp->stats, "ad", adnlun, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
0x180);
dev1 = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw, &addisk_cdevsw);
dev1 = disk_create(adp->lun, &adp->disk, 0, &ad_cdevsw,
&addisk_cdevsw);
dev1->si_drv1 = adp;
dev1 = disk_create(adp->lun, &adp->disk, 0, &fakewd_cdevsw, &fakewddisk_cdevsw);
dev1 = disk_create(adp->lun, &adp->disk, 0, &fakewd_cdevsw,
&fakewddisk_cdevsw);
dev1->si_drv1 = adp;
bufq_init(&adp->queue);
adtab[adnlun++] = adp;
}
}
}
}
config_intrhook_disestablish(ad_attach_hook);
@ -261,7 +261,7 @@ ad_getparam(struct ad_softc *adp)
sizeof(buffer)/sizeof(int16_t));
ata_parm = malloc(sizeof(struct ata_params), M_DEVBUF, M_NOWAIT);
if (!ata_parm)
return -1;
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));
@ -274,15 +274,13 @@ ad_getparam(struct ad_softc *adp)
static int
adopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
struct ad_softc *adp;
int32_t lun;
struct ad_softc *adp = dev->si_drv1;
struct disklabel *dl;
adp = dev->si_drv1;
lun = adp->lun;
#ifdef AD_DEBUG
printf("adopen: lun=%d adnlun=%d\n", lun, adnlun);
printf("adopen: lun=%d adnlun=%d\n", adp->lun, adnlun);
#endif
dl = &adp->disk.d_label;
bzero(dl, sizeof *dl);
dl->d_secsize = DEV_BSIZE;
@ -292,55 +290,52 @@ printf("adopen: lun=%d adnlun=%d\n", lun, adnlun);
dl->d_secpercyl = adp->sectors * adp->heads;
dl->d_secperunit = adp->total_secs;
ad_sleep(adp, "adop2");
return 0;
}
static void
adstrategy(struct buf *bp)
{
struct ad_softc *adp;
struct ad_softc *adp = bp->b_dev->si_drv1;
int32_t s;
adp = bp->b_dev->si_drv1;
#ifdef AD_DEBUG
printf("adstrategy: entered count=%d\n", bp->b_bcount);
printf("adstrategy: entered count=%d\n", bp->b_bcount);
#endif
s = splbio();
bufqdisksort(&adp->queue, bp);
ad_start(adp);
splx(s);
#ifdef AD_DEBUG
printf("adstrategy: leaving\n");
printf("adstrategy: leaving\n");
#endif
}
int
addump(dev_t dev)
{
struct ad_softc *adp;
struct ad_softc *adp = dev->si_drv1;
struct ad_request request;
u_int count, blkno, secsize;
vm_offset_t addr = 0;
int error;
error = disk_dumpcheck(dev, &count, &blkno, &secsize);
if (error)
return (error);
if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
return error;
adp = dev->si_drv1;
if (!adp)
return ENXIO;
adp->flags &= ~AD_F_DMA_ENABLED;
while (count > 0) {
if (is_physical_memory(addr))
pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
trunc_page(addr), VM_PROT_READ, TRUE);
else
pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
trunc_page(0), VM_PROT_READ, TRUE);
if (is_physical_memory(addr))
pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
trunc_page(addr), VM_PROT_READ, TRUE);
else
pmap_enter(kernel_pmap, (vm_offset_t)CADDR1,
trunc_page(0), VM_PROT_READ, TRUE);
bzero(&request, sizeof(struct ad_request));
request.device = adp;
@ -348,27 +343,27 @@ addump(dev_t dev)
request.bytecount = PAGE_SIZE;
request.data = CADDR1;
while (request.bytecount > 0) {
while (request.bytecount > 0) {
ad_transfer(&request);
request.donecount += request.currentsize;
request.donecount += request.currentsize;
DELAY(20);
}
}
if (addr % (1024 * 1024) == 0) {
if (addr % (1024 * 1024) == 0) {
#ifdef HW_WDOG
if (wdog_tickler)
(*wdog_tickler)();
if (wdog_tickler)
(*wdog_tickler)();
#endif
printf("%ld ", (long)(count * DEV_BSIZE) / (1024 * 1024));
}
printf("%ld ", (long)(count * DEV_BSIZE) / (1024 * 1024));
}
blkno += howmany(PAGE_SIZE, secsize);
count -= howmany(PAGE_SIZE, secsize);
addr += PAGE_SIZE;
blkno += howmany(PAGE_SIZE, secsize);
count -= howmany(PAGE_SIZE, secsize);
addr += PAGE_SIZE;
}
if (ata_wait(adp->controller, adp->unit, ATA_S_DRDY | ATA_S_DSC) < 0)
printf("ad_dump: timeout waiting for final ready\n");
printf("ad_dump: timeout waiting for final ready\n");
return 0;
}
@ -380,13 +375,13 @@ ad_start(struct ad_softc *adp)
struct ad_request *request;
#ifdef AD_DEBUG
printf("ad_start:\n");
printf("ad_start:\n");
#endif
if (!bp)
return;
return;
if (!(request = malloc(sizeof(struct ad_request), M_DEVBUF, M_NOWAIT))) {
printf("ad_start: out of memory\n");
printf("ad_start: out of memory\n");
return;
}
@ -407,7 +402,7 @@ printf("ad_start:\n");
/* try to start controller */
if (adp->controller->active == ATA_IDLE)
ata_start(adp->controller);
ata_start(adp->controller);
}
void
@ -424,15 +419,18 @@ ad_transfer(struct ad_request *request)
blkno = request->blockaddr + (request->donecount / DEV_BSIZE);
#ifdef AD_DEBUG
printf("ad_transfer: blkno=%d\n", blkno);
printf("ad_transfer: blkno=%d\n", blkno);
#endif
if (request->donecount == 0) {
/* start timeout for this transfer */
request->timeout_handle = timeout((timeout_t*)ad_timeout, request, 300);
/* setup transfer parameters */
count = howmany(request->bytecount, DEV_BSIZE);
if (count > 256) {
count = 256;
printf("ad_transfer: count=%d not supported\n", count);
printf("ad_transfer: count=%d not supported\n", count);
}
if (adp->flags & AD_F_LBA_ENABLED) {
@ -441,16 +439,16 @@ ad_transfer(struct ad_request *request)
head = ((blkno >> 24) & 0xf) | ATA_D_LBA;
}
else {
secsprcyl = adp->sectors * adp->heads;
cylinder = blkno / secsprcyl;
head = (blkno % secsprcyl) / adp->sectors;
sector = (blkno % adp->sectors) + 1;
secsprcyl = adp->sectors * adp->heads;
cylinder = blkno / secsprcyl;
head = (blkno % secsprcyl) / adp->sectors;
sector = (blkno % adp->sectors) + 1;
}
/* setup first transfer length */
request->currentsize = min(request->bytecount, adp->transfersize);
request->currentsize = min(request->bytecount, adp->transfersize);
devstat_start_transaction(&adp->stats);
devstat_start_transaction(&adp->stats);
/* does this drive & transfer work with DMA ? */
request->flags &= ~AR_F_DMA_USED;
@ -461,14 +459,14 @@ ad_transfer(struct ad_request *request)
request->flags |= AR_F_DMA_USED;
cmd = request->flags & AR_F_READ ? ATA_C_READ_DMA : ATA_C_WRITE_DMA;
request->currentsize = request->bytecount;
}
}
/* does this drive support multi sector transfers ? */
else if (request->currentsize > DEV_BSIZE)
cmd = request->flags & AR_F_READ?ATA_C_READ_MULTI:ATA_C_WRITE_MULTI;
else
cmd = request->flags & AR_F_READ ? ATA_C_READ : ATA_C_WRITE;
ata_command(adp->controller, adp->unit, cmd, cylinder, head,
ata_command(adp->controller, adp->unit, cmd, cylinder, head,
sector, count, 0, ATA_IMMEDIATE);
}
@ -476,7 +474,7 @@ ad_transfer(struct ad_request *request)
if (request->flags & AR_F_DMA_USED) {
ata_dmastart(adp->controller, adp->unit);
#ifdef AD_DEBUG
printf("ad_transfer: return waiting for DMA interrupt\n");
printf("ad_transfer: return waiting for DMA interrupt\n");
#endif
return;
}
@ -487,26 +485,26 @@ ad_transfer(struct ad_request *request)
/* if this is a PIO read operation, return and wait for interrupt */
if (request->flags & AR_F_READ) {
#ifdef AD_DEBUG
printf("ad_transfer: return waiting for PIO read interrupt\n");
printf("ad_transfer: return waiting for PIO read interrupt\n");
#endif
return;
return;
}
/* ready to write PIO data ? */
if (ata_wait(adp->controller, adp->unit,
ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ) < 0) {
printf("ad_transfer: timeout waiting for DRQ");
}
printf("ad_transfer: timeout waiting for DRQ");
}
/* output the data */
#if 0
outsw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
#else
outsl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
#endif
request->bytecount -= request->currentsize;
#ifdef AD_DEBUG
@ -522,50 +520,50 @@ ad_interrupt(struct ad_request *request)
/* finish DMA transfer */
if (request->flags & AR_F_DMA_USED)
dma_stat = ata_dmadone(adp->controller, adp->unit);
dma_stat = ata_dmadone(adp->controller, adp->unit);
/* get drive status */
if (ata_wait(adp->controller, adp->unit, 0) < 0)
printf("ad_interrupt: timeout waiting for status");
printf("ad_interrupt: timeout waiting for status");
if (adp->controller->status & (ATA_S_ERROR | ATA_S_CORR) ||
(request->flags & AR_F_DMA_USED && dma_stat != ATA_BMSTAT_INTERRUPT)) {
oops:
printf("ad%d: status=%02x error=%02x\n",
adp->lun, adp->controller->status, adp->controller->error);
if (adp->controller->status & ATA_S_ERROR) {
printf("ad_interrupt: hard error\n");
request->flags |= AR_F_ERROR;
printf("ad_interrupt: hard error\n");
request->flags |= AR_F_ERROR;
}
if (adp->controller->status & ATA_S_CORR)
printf("ad_interrupt: soft error ECC corrected\n");
printf("ad_interrupt: soft error ECC corrected\n");
}
/* if this was a PIO read operation, get the data */
if (!(request->flags & AR_F_DMA_USED) &&
((request->flags & (AR_F_READ | AR_F_ERROR)) == AR_F_READ)) {
((request->flags & (AR_F_READ | AR_F_ERROR)) == AR_F_READ)) {
/* 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");
/* 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, adp->unit,
if (ata_wait(adp->controller, adp->unit,
ATA_S_DRDY | ATA_S_DSC | ATA_S_DRQ) != 0){
printf("ad_interrupt: read error detected late");
goto oops;
}
printf("ad_interrupt: read error detected late");
goto oops;
}
/* data ready, read in */
/* data ready, read in */
#if 0
insw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
insw(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int16_t));
#else
insl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
insl(adp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data + request->donecount),
request->currentsize / sizeof(int32_t));
#endif
request->bytecount -= request->currentsize;
request->bytecount -= request->currentsize;
#ifdef AD_DEBUG
printf("ad_interrupt: read in data\n");
#endif
@ -573,7 +571,7 @@ ad_interrupt(struct ad_request *request)
/* if this was a DMA operation finish up */
if ((request->flags & AR_F_DMA_USED) && !(request->flags & AR_F_ERROR))
request->bytecount -= request->currentsize;
request->bytecount -= request->currentsize;
/* finish up this tranfer, check for more work on this buffer */
if (adp->controller->active == ATA_ACTIVE_ATA) {
@ -584,23 +582,22 @@ ad_interrupt(struct ad_request *request)
else {
request->donecount += request->currentsize;
#ifdef AD_DEBUG
printf("ad_interrupt: %s cmd OK\n",
printf("ad_interrupt: %s cmd OK\n",
(request->flags & AR_F_READ) ? "read" : "write");
#endif
if (request->bytecount > 0) {
ad_transfer(request);
ad_transfer(request);
return ATA_OP_CONTINUES;
}
}
TAILQ_REMOVE(&adp->controller->ata_queue, request, chain);
request->bp->b_resid = request->bytecount;
devstat_end_transaction_buf(&adp->stats, request->bp);
biodone(request->bp);
devstat_end_transaction(&adp->stats, request->donecount,
DEVSTAT_TAG_NONE,
(request->flags & AR_F_READ) ?
DEVSTAT_READ : DEVSTAT_WRITE);
}
/* disarm timeout for this transfer */
untimeout((timeout_t *)ad_timeout, request, request->timeout_handle);
free(request, M_DEVBUF);
ad_start(adp);
#ifdef AD_DEBUG
@ -609,13 +606,40 @@ ad_interrupt(struct ad_request *request)
return ATA_OP_FINISHED;
}
static void
ad_timeout(struct ad_request *request)
{
struct ad_softc *adp = request->device;
printf("ata%d-%s: ad_timeout: lost disk contact - resetting\n",
adp->controller->lun,
(adp->unit == ATA_MASTER) ? "master" : "slave");
if (request->flags & AR_F_DMA_USED)
ata_dmadone(adp->controller, adp->unit);
ata_reinit(adp->controller);
}
void
ad_reinit(struct ad_softc *adp)
{
/* reinit disk parameters */
ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, 0, 0, 0,
adp->transfersize / DEV_BSIZE, 0, ATA_IMMEDIATE);
ata_wait(adp->controller, adp->unit, ATA_S_DRDY);
ata_dmainit(adp->controller, adp->unit, apiomode(adp->ata_parm),
wdmamode(adp->ata_parm), udmamode(adp->ata_parm));
}
static void
ad_sleep(struct ad_softc *adp, int8_t *mesg)
{
int32_t s = splbio();
int32_t s;
s = splbio();
while (adp->controller->active != ATA_IDLE)
tsleep((caddr_t)&adp->controller->active, PZERO - 1, mesg, 1);
tsleep((caddr_t)&adp->controller->active, PZERO - 1, mesg, 1);
splx(s);
}
@ -645,16 +669,16 @@ ad_drvinit(void)
/* 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))) {
M_TEMP, M_NOWAIT))) {
printf("ad: malloc attach_hook failed\n");
return;
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);
printf("ad: config_intrhook_establish failed\n");
free(ad_attach_hook, M_TEMP);
}
}

View File

@ -40,9 +40,9 @@ struct ata_params {
int16_t vendorunique0[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 */
#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 */
@ -52,15 +52,15 @@ struct ata_params {
int8_t vendorunique1;
int16_t usedmovsd; /* double word read/write? */
u_int8_t vendorcap; /* vendor capabilities */
u_int8_t dmaflag :1; /* DMA supported - always 1 */
u_int8_t lbaflag :1; /* LBA supported - always 1 */
u_int8_t iordydis :1; /* IORDY may be disabled */
u_int8_t iordyflag :1; /* IORDY supported */
u_int8_t :1;
u_int8_t standby :1; /* standby timer supported */
u_int8_t :1;
u_int8_t :1;
u_int8_t vendorcap; /* vendor capabilities */
u_int8_t dmaflag :1; /* DMA supported - always 1 */
u_int8_t lbaflag :1; /* LBA supported - always 1 */
u_int8_t iordydis :1; /* IORDY may be disabled */
u_int8_t iordyflag :1; /* IORDY supported */
u_int8_t :1;
u_int8_t standby :1; /* standby timer supported */
u_int8_t :1;
u_int8_t :1;
int16_t capvalidate; /* validation for above */
int8_t vendorunique3;
@ -69,8 +69,8 @@ struct ata_params {
int8_t odmamode; /* old DMA modes, not ATA-3 */
int16_t atavalid; /* fields valid */
#define ATA_FLAG_54_58 1 /* words 54-58 valid */
#define ATA_FLAG_64_70 2 /* words 64-70 valid */
#define ATA_FLAG_54_58 1 /* words 54-58 valid */
#define ATA_FLAG_64_70 2 /* words 64-70 valid */
int16_t currcyls;
int16_t currheads;
@ -81,19 +81,19 @@ struct ata_params {
int8_t multsectvalid;
int32_t lbasize;
int16_t sdmamodes; /* singleword DMA modes */
int16_t wdmamodes; /* multiword DMA modes */
int16_t apiomodes; /* advanced PIO modes */
int16_t sdmamodes; /* singleword DMA modes */
int16_t wdmamodes; /* multiword DMA modes */
int16_t apiomodes; /* advanced PIO modes */
u_int16_t mwdmamin; /* min. M/W DMA time/word ns */
u_int16_t mwdmarec; /* rec. M/W DMA time ns */
u_int16_t pioblind; /* min. PIO cycle w/o flow */
u_int16_t pioiordy; /* min. PIO cycle IORDY flow */
u_int16_t mwdmamin; /* min. M/W DMA time/word ns */
u_int16_t mwdmarec; /* rec. M/W DMA time ns */
u_int16_t pioblind; /* min. PIO cycle w/o flow */
u_int16_t pioiordy; /* min. PIO cycle IORDY flow */
int16_t reserved69;
int16_t reserved70;
u_int16_t rlsovlap; /* rel time (us) for overlap */
u_int16_t rlsservice; /* rel time (us) for service */
u_int16_t rlsovlap; /* rel time (us) for overlap */
u_int16_t rlsservice; /* rel time (us) for service */
int16_t reserved73;
int16_t reserved74;
int16_t queuelen;
@ -125,7 +125,7 @@ struct ad_softc {
int32_t unit; /* ATA_MASTER or ATA_SLAVE */
int32_t lun; /* logical unit number */
u_int16_t cylinders; /* disk geometry (probed) */
u_int8_t heads;
u_int8_t heads;
u_int8_t sectors;
u_int32_t total_secs; /* total # of sectors (LBA) */
u_int32_t transfersize; /* size of each transfer */
@ -137,18 +137,18 @@ struct ad_softc {
#define AD_F_DMA_ENABLED 0x0008
#define AD_F_TAG_ENABLED 0x0010
struct buf_queue_head queue; /* head of request queue */
struct devstat stats; /* devstat entry */
struct buf_queue_head queue; /* head of request queue */
struct devstat stats; /* devstat entry */
struct disk disk; /* disklabel/slice stuff */
};
struct ad_request {
struct ad_softc *device; /* ptr to parent device */
u_int32_t blockaddr; /* block number */
u_int32_t bytecount; /* bytes to transfer */
u_int32_t donecount; /* bytes transferred */
u_int32_t blockaddr; /* block number */
u_int32_t bytecount; /* bytes to transfer */
u_int32_t donecount; /* bytes transferred */
u_int32_t currentsize; /* size of current transfer */
u_int32_t result; /* result code */
struct callout_handle timeout_handle; /* handle for untimeout */
int32_t flags;
#define AR_F_READ 0x0001
#define AR_F_ERROR 0x0002
@ -159,3 +159,7 @@ struct ad_request {
u_int8_t tag; /* tag ID of this request */
TAILQ_ENTRY(ad_request) chain; /* list management */
};
void ad_transfer(struct ad_request *);
int32_t ad_interrupt(struct ad_request *);
void ad_reinit(struct ad_softc *);

View File

@ -30,24 +30,30 @@
#include "ata.h"
#include "pci.h"
#include "apm.h"
#if NATA > 0
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <vm/vm.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#if NPCI > 0
#include <pci/pcivar.h>
#include <pci/pcireg.h>
#endif
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#include <dev/ata/ata-all.h>
#ifdef __alpha__
#undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va)
#endif
/* misc defines */
@ -64,45 +70,43 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
if (!scp->bmaddr)
return -1;
#ifdef ATA_DEBUGDMA
#ifdef ATA_DMADEBUG
printf("ata%d: dmainit: ioaddr=0x%x altioaddr=0x%x, bmaddr=0x%x\n",
scp->lun, scp->ioaddr, scp->altioaddr, scp->bmaddr);
#endif
if (!(dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT)))
return -1;
return -1;
if (((uintptr_t)dmatab >> PAGE_SHIFT) ^
(((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) {
printf("ata_dmainit: dmatab crosses page boundary, no DMA\n");
free(dmatab, M_DEVBUF);
return -1;
printf("ata_dmainit: dmatab crosses page boundary, no DMA\n");
free(dmatab, M_DEVBUF);
return -1;
}
scp->dmatab[device ? 1 : 0] = dmatab;
scp->dmatab[(device == ATA_MASTER) ? 0 : 1] = dmatab;
type = pci_get_devid(scp->dev);
switch(type) {
switch (type = pci_get_devid(scp->dev)) {
case 0x71118086: /* Intel PIIX4 */
if (udmamode >= 2) {
int32_t mask48, new48;
int32_t mask48, new48;
printf("ata%d: %s: setting up UDMA2 mode on PIIX4 chip ",
scp->lun, (device) ? "slave" : "master");
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up UDMA2 mode on PIIX4 chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
devno = (scp->unit << 1) + (device ? 1 : 0);
devno = (scp->unit << 1) + ((device == ATA_MASTER) ? 0 : 1);
mask48 = (1 << devno) + (3 << (16 + (devno << 2)));
new48 = (1 << devno) + (2 << (16 + (devno << 2)));
pci_write_config(scp->dev, 0x48,
pci_write_config(scp->dev, 0x48,
(pci_read_config(scp->dev, 0x48, 4) &
~mask48) | new48, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA33;
return 0;
}
/* FALLTHROUGH */
@ -113,54 +117,54 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
/* if SITRE not set doit for both channels */
if (!((pci_read_config(scp->dev, 0x40, 4)>>(scp->unit<<8))&0x4000)){
new40 = pci_read_config(scp->dev, 0x40, 4);
new44 = pci_read_config(scp->dev, 0x44, 4);
if (!(new40 & 0x00004000)) {
new44 &= ~0x0000000f;
new44 |= ((new40&0x00003000)>>10)|((new40&0x00000300)>>8);
}
if (!(new40 & 0x40000000)) {
new44 &= ~0x000000f0;
new44 |= ((new40&0x30000000)>>22)|((new40&0x03000000)>>20);
}
new40 |= 0x40004000;
pci_write_config(scp->dev, 0x40, new40, 4);
pci_write_config(scp->dev, 0x44, new44, 4);
new40 = pci_read_config(scp->dev, 0x40, 4);
new44 = pci_read_config(scp->dev, 0x44, 4);
if (!(new40 & 0x00004000)) {
new44 &= ~0x0000000f;
new44 |= ((new40&0x00003000)>>10)|((new40&0x00000300)>>8);
}
if (!(new40 & 0x40000000)) {
new44 &= ~0x000000f0;
new44 |= ((new40&0x30000000)>>22)|((new40&0x03000000)>>20);
}
new40 |= 0x40004000;
pci_write_config(scp->dev, 0x40, new40, 4);
pci_write_config(scp->dev, 0x44, new44, 4);
}
printf("ata%d: %s: setting up WDMA2 mode on PIIX3/4 chip ",
scp->lun, (device) ? "slave" : "master");
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up WDMA2 mode on PIIX4 chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
if (device == ATA_MASTER) {
mask40 = 0x0000330f;
new40 = 0x00002307;
mask44 = 0;
new44 = 0;
} else {
mask40 = 0x000000f0;
new40 = 0x00000070;
mask44 = 0x0000000f;
new44 = 0x0000000b;
}
printf("OK\n");
if (device == ATA_MASTER) {
mask40 = 0x0000330f;
new40 = 0x00002307;
mask44 = 0;
new44 = 0;
} else {
mask40 = 0x000000f0;
new40 = 0x00000070;
mask44 = 0x0000000f;
new44 = 0x0000000b;
}
if (scp->unit) {
mask40 <<= 16;
new40 <<= 16;
mask44 <<= 4;
new44 <<= 4;
}
pci_write_config(scp->dev, 0x40,
(pci_read_config(scp->dev, 0x40, 4) &
~mask40) | new40, 4);
pci_write_config(scp->dev, 0x44,
(pci_read_config(scp->dev, 0x44, 4) &
~mask44) | new44, 4);
if (scp->unit) {
mask40 <<= 16;
new40 <<= 16;
mask44 <<= 4;
new44 <<= 4;
}
pci_write_config(scp->dev, 0x40,
(pci_read_config(scp->dev, 0x40, 4) & ~mask40) |
new40, 4);
pci_write_config(scp->dev, 0x44,
(pci_read_config(scp->dev, 0x44, 4) & ~mask44) |
new44, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_DMA;
return 0;
}
}
break;
case 0x12308086: /* Intel PIIX */
@ -169,89 +173,129 @@ ata_dmainit(struct ata_softc *scp, int32_t device,
case 0x4d33105a: /* Promise Ultra/33 / FastTrack controllers */
case 0x4d38105a: /* Promise Ultra/66 controllers */
/* the promise seems to have trouble with DMA on ATAPI devices */
/* the Promise can only do DMA on ATA disks not on ATAPI devices */
if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) ||
(device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE))
break;
devno = (scp->unit << 1) + (device ? 1 : 0);
if (udmamode >=2) {
printf("ata%d: %s: setting up UDMA2 mode on Promise chip ",
scp->lun, (device) ? "slave" : "master");
devno = (scp->unit << 1) + ((device == ATA_MASTER) ? 0 : 1);
if (udmamode >=4 && type == 0x4d38105a) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_UDMA4, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up UDMA4 mode on Promise chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004117f3, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA66;
return 0;
}
if (udmamode >=2) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up UDMA2 mode on Promise chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004127f3, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA33;
return 0;
}
else if (wdmamode >= 2 && apiomode >= 4) {
printf("ata%d: %s: setting up WDMA2 mode on Promise chip ",
scp->lun, (device) ? "slave" : "master");
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up WDMA2 mode on Promise chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004367f3, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_DMA;
return 0;
}
}
else {
printf("ata%d: %s: setting up PIO mode on Promise chip OK\n",
scp->lun, (device) ? "slave" : "master");
if (bootverbose)
printf("ata%d: %s: setting PIO mode on Promise chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave");
pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004fe924, 4);
}
break;
case 0x522910b9: /* AcerLabs Aladdin IV/V */
/* the Aladdin has to be setup specially for ATAPI devices */
if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) ||
(device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE)) {
int8_t word53 = pci_read_config(scp->dev, 0x53, 1);
/* if needed set atapi fifo & dma */
if ((udmamode >=2) || (wdmamode >= 2 && apiomode >= 4)) {
pci_write_config(scp->dev, 0x53, word53 | 0x03, 1);
scp->flags |= ATA_ATAPI_DMA_RO;
if (device == ATA_MASTER)
outb(scp->bmaddr + ATA_BMSTAT_PORT,
inb(scp->bmaddr + ATA_BMSTAT_PORT) |
ATA_BMSTAT_DMA_MASTER);
else
outb(scp->bmaddr + ATA_BMSTAT_PORT,
inb(scp->bmaddr + ATA_BMSTAT_PORT) |
ATA_BMSTAT_DMA_SLAVE);
}
else {
pci_write_config(scp->dev, 0x53, (word53 & ~0x01) | 0x02, 1);
}
}
if (udmamode >=2) {
int32_t word54 = pci_read_config(scp->dev, 0x54, 4);
printf("ata%d: %s: setting up UDMA2 mode on Aladdin chip ",
scp->lun, (device) ? "slave" : "master");
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up UDMA2 mode on Aladdin chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
word54 |= 0x5555;
word54 |= (0x0000000A << (16 + (scp->unit << 3) + (device << 2)));
word54 |= (0x0a << (16 + (scp->unit << 3) + (device << 2)));
pci_write_config(scp->dev, 0x54, word54, 4);
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_UDMA33;
return 0;
}
else if (wdmamode >= 2 && apiomode >= 4) {
printf("ata%d: %s: setting up WDMA2 mode on Aladdin chip ",
scp->lun, (device) ? "slave" : "master");
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up WDMA2 mode on Aladdin chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_DMA;
return 0;
}
break;
default: /* well, we have no support for this, but try anyways */
if ((wdmamode >= 2 && apiomode >= 4) || udmamode >= 2) {
printf("ata%d: %s: setting up generic WDMA2 mode ",
scp->lun, (device) ? "slave" : "master");
if (((wdmamode >= 2 && apiomode >= 4) || udmamode >= 2) &&
(inb(scp->bmaddr + ATA_BMSTAT_PORT) &
((device == ATA_MASTER) ?
ATA_BMSTAT_DMA_SLAVE : ATA_BMSTAT_DMA_MASTER))) {
error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0,
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR);
if (error) {
printf("failed\n");
ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_IGNORE_INTR);
if (bootverbose)
printf("ata%d: %s: %s setting up WDMA2 mode on generic chip\n",
scp->lun, (device == ATA_MASTER) ? "master" : "slave",
(error) ? "failed" : "success");
if (error)
break;
}
printf("OK\n");
scp->mode[(device == ATA_MASTER) ? 0 : 1] = ATA_MODE_DMA;
return 0;
}
}
@ -267,19 +311,21 @@ ata_dmasetup(struct ata_softc *scp, int32_t device,
u_int32_t dma_count, dma_base;
int32_t i = 0;
#ifdef ATA_DEBUGDMA
#ifdef ATA_DMADEBUG
printf("ata%d: dmasetup\n", scp->lun);
#endif
if (((uintptr_t)data & 1) || (count & 1))
return -1;
if (!count) {
#ifdef ATA_DMADEBUG
printf("ata%d: zero length DMA transfer attempt on %s\n",
scp->lun, (device ? "slave" : "master"));
scp->lun, ((device == ATA_MASTER) ? "master" : "slave"));
#endif
return -1;
}
dmatab = scp->dmatab[device ? 1 : 0];
dmatab = scp->dmatab[(device == ATA_MASTER) ? 0 : 1];
dma_base = vtophys(data);
dma_count = MIN(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK)));
data += dma_count;
@ -299,16 +345,16 @@ ata_dmasetup(struct ata_softc *scp, int32_t device,
data += MIN(count, PAGE_SIZE);
count -= MIN(count, PAGE_SIZE);
}
#ifdef ATA_DEBUGDMA
printf("ata_dmasetup: base=%08x count%08x\n",
dma_base, dma_count);
#ifdef ATA_DMADEBUG
printf("ata_dmasetup: base=%08x count%08x\n", dma_base, dma_count);
#endif
dmatab[i].base = dma_base;
dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT;
outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab));
#ifdef ATA_DEBUGDMA
printf("dmatab=%08x %08x\n", vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT));
#ifdef ATA_DMADEBUG
printf("dmatab=%08x %08x\n",
vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT));
#endif
outb(scp->bmaddr + ATA_BMCMD_PORT, flags ? ATA_BMCMD_WRITE_READ:0);
outb(scp->bmaddr + ATA_BMSTAT_PORT, (inb(scp->bmaddr + ATA_BMSTAT_PORT) |
@ -319,7 +365,7 @@ printf("dmatab=%08x %08x\n", vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT));
void
ata_dmastart(struct ata_softc *scp, int32_t device)
{
#ifdef ATA_DEBUGDMA
#ifdef ATA_DMADEBUG
printf("ata%d: dmastart\n", scp->lun);
#endif
outb(scp->bmaddr + ATA_BMCMD_PORT,
@ -329,7 +375,7 @@ ata_dmastart(struct ata_softc *scp, int32_t device)
int32_t
ata_dmadone(struct ata_softc *scp, int32_t device)
{
#ifdef ATA_DEBUGDMA
#ifdef ATA_DMADEBUG
printf("ata%d: dmadone\n", scp->lun);
#endif
outb(scp->bmaddr + ATA_BMCMD_PORT,
@ -340,7 +386,7 @@ ata_dmadone(struct ata_softc *scp, int32_t device)
int32_t
ata_dmastatus(struct ata_softc *scp, int32_t device)
{
#ifdef ATA_DEBUGDMA
#ifdef ATA_DMADEBUG
printf("ata%d: dmastatus\n", scp->lun);
#endif
return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
@ -350,14 +396,14 @@ ata_dmastatus(struct ata_softc *scp, int32_t device)
int32_t
ata_dmainit(struct ata_softc *scp, int32_t device,
int32_t piomode, int32_t wdmamode, int32_t udmamode)
int32_t piomode, int32_t wdmamode, int32_t udmamode)
{
return -1;
}
int32_t
ata_dmasetup(struct ata_softc *scp, int32_t device,
int8_t *data, int32_t count, int32_t flags)
int8_t *data, int32_t count, int32_t flags)
{
return -1;
}

View File

@ -32,8 +32,9 @@
#include "atapicd.h"
#include "atapist.h"
#include "atapifd.h"
#include "apm.h"
#if NATA > 0
#if NATA > 0 && (NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0)
#include <sys/param.h>
#include <sys/systm.h>
@ -42,17 +43,21 @@
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/devicestat.h>
#include <machine/clock.h>
#include <pci/pcivar.h>
#include <machine/clock.h>
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#include <dev/ata/ata-all.h>
#include <dev/ata/atapi-all.h>
/* prototypes */
static void atapi_attach(void *);
static int32_t atapi_getparam(struct atapi_softc *);
static void atapi_timeout(struct atapi_request *request);
static int8_t *atapi_type(int32_t);
static int8_t *atapi_cmd2str(u_int8_t);
static int8_t * atapi_skey2str(u_int8_t);
static int8_t *atapi_skey2str(u_int8_t);
static int32_t atapi_wait(struct atapi_softc *, u_int8_t);
static void atapi_init(void);
@ -67,8 +72,8 @@ static __inline int
apiomode(struct atapi_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->apiomodes & 2) == 2) return 4;
if ((ap->apiomodes & 1) == 1) return 3;
if ((ap->apiomodes & 2) == 2) return 4;
if ((ap->apiomodes & 1) == 1) return 3;
}
return -1;
}
@ -77,9 +82,9 @@ static __inline int
wdmamode(struct atapi_params *ap)
{
if ((ap->atavalid & 2) == 2) {
if ((ap->wdmamodes & 4) == 4) return 2;
if ((ap->wdmamodes & 2) == 2) return 1;
if ((ap->wdmamodes & 1) == 1) return 0;
if ((ap->wdmamodes & 4) == 4) return 2;
if ((ap->wdmamodes & 2) == 2) return 1;
if ((ap->wdmamodes & 1) == 1) return 0;
}
return -1;
}
@ -88,9 +93,9 @@ static __inline int
udmamode(struct atapi_params *ap)
{
if ((ap->atavalid & 4) == 4) {
if ((ap->udmamodes & 4) == 4) return 2;
if ((ap->udmamodes & 2) == 2) return 1;
if ((ap->udmamodes & 1) == 1) return 0;
if ((ap->udmamodes & 4) == 4) return 2;
if ((ap->udmamodes & 2) == 2) return 1;
if ((ap->udmamodes & 1) == 1) return 0;
}
return -1;
}
@ -105,69 +110,76 @@ atapi_attach(void *notused)
/* now, run through atadevices and look for ATAPI devices */
for (ctlr=0; ctlr<MAXATA; ctlr++) {
if (!atadevices[ctlr]) continue;
if (!atadevices[ctlr]) continue;
for (dev=0; dev<2; dev++) {
if (atadevices[ctlr]->devices &
(dev ? ATA_ATAPI_SLAVE : ATA_ATAPI_MASTER)) {
if (!(atp = malloc(sizeof(struct atapi_softc),
if (!(atp = malloc(sizeof(struct atapi_softc),
M_DEVBUF, M_NOWAIT))) {
printf("atapi: failed to allocate driver storage\n");
continue;
}
bzero(atp, sizeof(struct atapi_softc));
atp->controller = atadevices[ctlr];
atp->unit = (dev == 0) ? ATA_MASTER : ATA_SLAVE;
if (atapi_getparam(atp)) {
free(atp, M_DEVBUF);
continue;
}
printf("atapi: piomode=%d, dmamode=%d, udmamode=%d\n",
apiomode(atp->atapi_parm),
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm));
if (!(atp->atapi_parm->drqtype == ATAPI_DRQT_INTR) &&
!ata_dmainit(atp->controller, atp->unit,
apiomode(atp->atapi_parm),
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm)))
atp->flags |= ATAPI_F_DMA_ENABLED;
bzero(atp, sizeof(struct atapi_softc));
atp->controller = atadevices[ctlr];
atp->unit = (dev == 0) ? ATA_MASTER : ATA_SLAVE;
if (atapi_getparam(atp)) {
free(atp, M_DEVBUF);
continue;
}
if (bootverbose)
printf("ata%d-%s: piomode=%d dmamode=%d "
"udmamode=%d dmaflag=%d\n",
ctlr, (dev == ATA_MASTER) ? "master" : "slave",
apiomode(atp->atapi_parm),
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm),
atp->atapi_parm->dmaflag);
printf("atapi: %s transfer mode set\n",
(atp->flags & ATAPI_F_DMA_ENABLED) ? "DMA" :"PIO");
if (!(atp->atapi_parm->drqtype == ATAPI_DRQT_INTR) &&
!ata_dmainit(atp->controller, atp->unit,
(apiomode(atp->atapi_parm) < 0) ?
(atp->atapi_parm->dmaflag ? 4 : 0) :
apiomode(atp->atapi_parm),
(wdmamode(atp->atapi_parm) < 0) ?
(atp->atapi_parm->dmaflag ? 2 : 0) :
wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm)))
atp->flags |= ATAPI_F_DMA_ENABLED;
switch (atp->atapi_parm->device_type) {
#if NATAPICD > 0
case ATAPI_TYPE_CDROM:
if (acdattach(atp))
case ATAPI_TYPE_CDROM:
if (acdattach(atp))
goto notfound;
break;
break;
#endif
#if NATAPIFD > 0
case ATAPI_TYPE_DIRECT:
if (afdattach(atp))
case ATAPI_TYPE_DIRECT:
if (afdattach(atp))
goto notfound;
break;
break;
#endif
#if NATAPIST > 0
case ATAPI_TYPE_TAPE:
if (astattach(atp))
case ATAPI_TYPE_TAPE:
if (astattach(atp))
goto notfound;
break;
break;
#endif
notfound:
default:
bpack(atp->atapi_parm->model, model_buf, sizeof(model_buf));
bpack(atp->atapi_parm->model, model_buf, sizeof(model_buf));
bpack(atp->atapi_parm->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(atp->atapi_parm->device_type),
ctlr,
(dev) ? "slave" : "master ");
sizeof(revision_buf));
printf("ata%d-%s: <%s/%s> %s device - NO DRIVER!\n",
ctlr, (dev == ATA_MASTER) ? "master" : "slave",
model_buf, revision_buf,
atapi_type(atp->atapi_parm->device_type));
free(atp, M_DEVBUF);
atp = NULL;
}
}
/* store our softc */
atp->controller->dev_softc[(atp->unit==ATA_MASTER)?0:1] = atp;
}
}
}
config_intrhook_disestablish(atapi_attach_hook);
@ -176,26 +188,26 @@ atapi_attach(void *notused)
static int32_t
atapi_getparam(struct atapi_softc *atp)
{
struct atapi_params *atapi_parm;
struct atapi_params *atapi_parm;
int8_t buffer[DEV_BSIZE];
/* select drive */
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
DELAY(1);
ata_command(atp->controller, atp->unit, ATA_C_ATAPI_IDENTIFY,
0, 0, 0, 0, 0, ATA_WAIT_INTR);
0, 0, 0, 0, 0, ATA_WAIT_INTR);
if (atapi_wait(atp, ATA_S_DRQ))
return -1;
insw(atp->controller->ioaddr + ATA_DATA, buffer,
sizeof(buffer)/sizeof(int16_t));
sizeof(buffer)/sizeof(int16_t));
if (atapi_wait(atp, 0))
return -1;
if (!(atapi_parm = malloc(sizeof(struct atapi_params), M_DEVBUF, M_NOWAIT)))
return -1;
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));
(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));
@ -203,110 +215,146 @@ atapi_getparam(struct atapi_softc *atp)
return 0;
}
int32_t
atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
int32_t count, int32_t flags, int32_t timeout,
atapi_callback_t callback, void *driver, struct buf *bp)
int32_t
atapi_immed_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
int32_t count, int32_t flags, int32_t timeout)
{
struct atapi_request *request;
int32_t error = 0;
int32_t s;
int32_t error, s;
atp->last_cmd = ccb[0];
if (!(request = malloc(sizeof(struct atapi_request), M_DEVBUF, M_NOWAIT)))
return -1;
return ENOMEM;
bzero(request, sizeof(struct atapi_request));
request->device = atp;
request->data = data;
request->bytecount = count;
request->donecount = 0;
request->flags = flags;
if (callback) {
request->callback = callback;
request->bp = bp;
request->driver = driver;
}
request->timeout = timeout * hz;
request->ccbsize = (atp->atapi_parm->cmdsize) ? 16 : 12;
bcopy(ccb, request->ccb, request->ccbsize);
s = splbio();
/* link onto controller queue */
if (ccb[0] == ATAPI_REQUEST_SENSE)
TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain);
else
TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain);
TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain);
/* try to start controller */
if (atp->controller->active == ATA_IDLE)
ata_start(atp->controller);
ata_start(atp->controller);
splx(s);
/* wait for command to complete */
if (tsleep((caddr_t)request, PRIBIO, "atprq", timeout*100)) {
if (atp->controller->active != ATA_IDLE)
atp->controller->active = ATA_IDLE;
/* should we reset device here ? */
request->result |= 0xf0;
}
tsleep((caddr_t)request, PRIBIO, "atpim", 0);
#ifdef ATAPI_DEBUG
printf("atapi: phew, got back from tsleep with %s\n"
(request->result & 0xf0) == 0xf0 ? "timeout" : "wakeup"));
printf("atapi: phew, got back from tsleep\n");
#endif
if (callback) {
(request->callback)(request);
free(request, M_DEVBUF);
return 0;
}
error = request->result;
free(request, M_DEVBUF);
if (ccb[0] == ATAPI_REQUEST_SENSE)
return 0;
else
return atapi_error(atp, error);
return error;
}
int32_t
atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data,
int32_t count, int32_t flags, int32_t timeout,
atapi_callback_t callback, void *driver, struct buf *bp)
{
struct atapi_request *request;
int32_t error, s;
if (!(request = malloc(sizeof(struct atapi_request), M_DEVBUF, M_NOWAIT)))
return ENOMEM;
bzero(request, sizeof(struct atapi_request));
request->device = atp;
request->data = data;
request->bytecount = count;
request->donecount = 0;
request->flags = flags;
request->timeout = timeout * hz;
request->ccbsize = (atp->atapi_parm->cmdsize) ? 16 : 12;
bcopy(ccb, request->ccb, request->ccbsize);
if (callback) {
request->callback = callback;
request->bp = bp;
request->driver = driver;
}
s = splbio();
/* link onto controller queue */
TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain);
/* try to start controller */
if (atp->controller->active == ATA_IDLE)
ata_start(atp->controller);
splx(s);
/* 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;
if (request->callback) {
(request->callback)(request);
error = 0;
}
free(request, M_DEVBUF);
return atapi_error(atp, error);
}
void
atapi_transfer(struct atapi_request *request)
{
struct atapi_softc *atp;
int32_t timeout;
struct atapi_softc *atp = request->device;
int32_t timout;
int8_t reason;
/* get device params */
atp = request->device;
#ifdef ATAPI_DEBUG
printf("atapi: trying to start %s cmd\n", atapi_cmd2str(request->ccb[0]));
printf("atapi: starting %s ", atapi_cmd2str(request->ccb[0]));
atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb));
#endif
atp->cmd = request->ccb[0];
/* start timeout for this command */
request->timeout_handle = timeout((timeout_t *)atapi_timeout,
request, request->timeout);
/* if DMA enabled setup DMA hardware */
atp->flags &= ~ATAPI_F_DMA_USED;
if ((request->ccb[0]==ATAPI_READ_BIG || request->ccb[0]==ATAPI_WRITE_BIG) &&
(atp->flags & ATAPI_F_DMA_ENABLED) &&
!ata_dmasetup(atp->controller, atp->unit,
(void *)request->data, request->bytecount,
request->flags & A_READ)) {
atp->flags |= ATAPI_F_DMA_USED;
if ((atp->flags & ATAPI_F_DMA_ENABLED) &&
(request->ccb[0] == ATAPI_READ ||
request->ccb[0] == ATAPI_READ_BIG ||
((request->ccb[0] == ATAPI_WRITE ||
request->ccb[0] == ATAPI_WRITE_BIG) &&
!(atp->controller->flags & ATA_ATAPI_DMA_RO))) &&
!ata_dmasetup(atp->controller, atp->unit,
(void *)request->data, request->bytecount,
request->flags & A_READ)) {
atp->flags |= ATAPI_F_DMA_USED;
}
/* start ATAPI operation */
ata_command(atp->controller, atp->unit, ATA_C_PACKET_CMD,
request->bytecount, 0, 0, 0,
(atp->flags & ATAPI_F_DMA_USED) ? ATA_F_DMA : 0,
ATA_IMMEDIATE);
request->bytecount, 0, 0, 0,
(atp->flags & ATAPI_F_DMA_USED) ? ATA_F_DMA : 0,
ATA_IMMEDIATE);
if (atp->flags & ATAPI_F_DMA_USED)
ata_dmastart(atp->controller, atp->unit);
/* command interrupt device ? just return */
if (atp->atapi_parm->drqtype == ATAPI_DRQT_INTR)
return;
/* ready to write ATAPI command */
timeout = 5000; /* might be less for fast devices */
while (timeout--) {
timout = 5000; /* might be less for fast devices */
while (timout--) {
reason = inb(atp->controller->ioaddr + ATA_IREASON);
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
if (((reason & (ATA_I_CMD | ATA_I_IN)) |
@ -314,18 +362,15 @@ atapi_transfer(struct atapi_request *request)
break;
DELAY(20);
}
if (timeout <= 0) {
atp->controller->error = inb(atp->controller->ioaddr + ATA_ERROR);
printf("atapi_transfer: bad command phase\n");
/* now what ?? done & again ?? SOS */
if (timout <= 0) {
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
printf("atapi_transfer: device hanging on packet cmd\n");
return;
}
/* this seems to be needed for some (slow) devices */
DELAY(10);
if (atp->flags & ATAPI_F_DMA_USED)
ata_dmastart(atp->controller, atp->unit);
/* send actual command */
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
request->ccbsize / sizeof(int16_t));
@ -334,68 +379,67 @@ atapi_transfer(struct atapi_request *request)
int32_t
atapi_interrupt(struct atapi_request *request)
{
struct atapi_softc *atp;
struct atapi_softc *atp = request->device;
int32_t length, reason, resid, dma_stat = 0;
#ifdef ATAPI_DEBUG
printf("atapi_interrupt: enter\n");
printf("atapi_interrupt: enter\n");
#endif
/* get device params */
atp = request->device;
reason = (inb(atp->controller->ioaddr+ATA_IREASON) & (ATA_I_CMD|ATA_I_IN)) |
(atp->controller->status & ATA_S_DRQ);
if (reason == ATAPI_P_CMDOUT) {
if (!(atp->controller->status & ATA_S_DRQ)) {
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
printf("atapi_interrupt: command interrupt, but no DRQ\n");
goto op_finished;
}
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
request->ccbsize / sizeof(int16_t));
return ATA_OP_CONTINUES;
}
if (atp->flags & ATAPI_F_DMA_USED)
dma_stat = ata_dmadone(atp->controller, atp->unit);
dma_stat = ata_dmadone(atp->controller, atp->unit);
/* get drive status */
if (atapi_wait(atp, 0) < 0) {
printf("atapi_interrupt: timeout waiting for status");
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
wakeup((caddr_t)request);
return ATA_OP_FINISHED;
printf("atapi_interrupt: timeout waiting for status");
atp->flags &= ~ATAPI_F_DMA_USED;
request->result = inb(atp->controller->ioaddr + ATA_ERROR) | 0xf0;
goto op_finished;
}
if (atp->flags & ATAPI_F_DMA_USED) {
atp->flags &= ~ATAPI_F_DMA_USED;
if ((atp->controller->status & (ATA_S_ERROR | ATA_S_DWF)) ||
dma_stat != ATA_BMSTAT_INTERRUPT) {
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
}
else {
request->result = 0;
request->donecount = request->bytecount;
request->bytecount = 0;
}
goto op_finished;
}
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_IREASON)&(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);
printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
#endif
if (atp->flags & ATAPI_F_DMA_USED) {
if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF) &&
dma_stat != ATA_BMSTAT_INTERRUPT)
request->result = atp->controller->error;
else {
request->donecount = request->bytecount;
request->bytecount = 0;
request->result = 0;
}
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
atp->flags &= ~ATAPI_F_DMA_USED;
wakeup((caddr_t)request);
return ATA_OP_FINISHED;
}
switch (reason) {
case ATAPI_P_CMDOUT:
/* send ATAPI command */
if (!(atp->controller->status & ATA_S_DRQ))
printf("atapi_interrupt: command interrupt, but no DRQ\n");
else
outsw(atp->controller->ioaddr + ATA_DATA, request->ccb,
request->ccbsize / sizeof(int16_t));
return ATA_OP_CONTINUES;
case ATAPI_P_WRITE:
if (request->flags & A_READ) {
printf("atapi_interrupt: trying to write on read buffer\n");
break;
}
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
printf("ata%d-%s: %s trying to write on read buffer\n",
atp->controller->lun,
(atp->unit == ATA_MASTER) ? "master" : "slave",
atapi_cmd2str(atp->cmd));
goto op_finished;
}
if (request->bytecount < length) {
printf("atapi_interrupt: write data underrun %d/%d\n",
length, request->bytecount);
@ -411,7 +455,7 @@ printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
}
else {
outsw(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), length / sizeof(int16_t));
(void *)((uintptr_t)request->data), length / sizeof(int16_t));
}
request->bytecount -= length;
request->donecount += length;
@ -419,106 +463,166 @@ printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason);
return ATA_OP_CONTINUES;
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);
if (!(request->flags & A_READ)) {
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
printf("ata%d-%s: %s trying to read on write buffer\n",
atp->controller->lun,
(atp->unit == ATA_MASTER) ? "master" : "slave",
atapi_cmd2str(atp->cmd));
goto op_finished;
}
if (request->bytecount < length) {
printf("atapi_interrupt: read data overrun %d/%d\n",
length, request->bytecount);
#if 0
insw(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), length / sizeof(int16_t));
insw(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), length / sizeof(int16_t));
#else
insl(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), length / sizeof(int32_t));
insl(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), length / sizeof(int32_t));
#endif
for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
inw(atp->controller->ioaddr + ATA_DATA);
}
else {
insw(atp->controller->ioaddr + ATA_DATA,
(void *)((uintptr_t)request->data), 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 *)((uintptr_t)request->data), length / sizeof(int16_t));
}
request->bytecount -= length;
request->donecount += length;
request->data += length;
return ATA_OP_CONTINUES;
return ATA_OP_CONTINUES;
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;
break;
}
if (atp->controller->status & (ATA_S_ERROR | ATA_S_DWF))
request->result = inb(atp->controller->ioaddr + ATA_ERROR);
else
request->result = 0;
#ifdef ATAPI_DEBUG
if (request->bytecount > 0) {
if (request->bytecount > 0) {
printf("atapi_interrupt: %s size problem, %d bytes residue\n",
(request->flags & A_READ) ? "read" : "write",
request->bytecount);
}
#endif
break;
goto op_finished;
default:
printf("atapi_interrupt: unknown transfer phase %d\n", reason);
}
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
#ifdef ATAPI_DEBUG
printf("atapi_interrupt: error=0x%02x\n", request->result);
#endif
op_finished:
untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle);
wakeup((caddr_t)request);
#ifdef ATAPI_DEBUG
printf("atapi_interrupt: error=0x%02x\n", request->result);
#endif
return ATA_OP_FINISHED;
}
static void
atapi_timeout(struct atapi_request *request)
{
struct atapi_softc *atp = request->device;
printf("ata%d-%s: atapi_timeout: cmd=%s - resetting\n",
atp->controller->lun, (atp->unit == ATA_MASTER) ? "master" : "slave",
atapi_cmd2str(request->ccb[0]));
if (request->flags & ATAPI_F_DMA_USED)
ata_dmadone(atp->controller, atp->unit);
ata_reinit(atp->controller);
}
void
atapi_reinit(struct atapi_softc *atp)
{
/* reinit device parameters */
ata_dmainit(atp->controller, atp->unit,
(apiomode(atp->atapi_parm) < 0) ?
(atp->atapi_parm->dmaflag ? 4 : 0) : apiomode(atp->atapi_parm),
(wdmamode(atp->atapi_parm) < 0) ?
(atp->atapi_parm->dmaflag ? 2 : 0) : wdmamode(atp->atapi_parm),
udmamode(atp->atapi_parm));
}
int32_t
atapi_error(struct atapi_softc *atp, int32_t error)
{
struct atapi_reqsense sense;
int8_t cmd = atp->last_cmd;
int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, sizeof(sense),
0, 0, 0 ,0 ,0, 0, 0, 0, 0, 0, 0 };
int8_t cmd = atp->cmd;
switch ((error & 0xf0)) {
if (cmd == ATAPI_REQUEST_SENSE)
return 0;
switch ((error & ATAPI_SK_MASK)) {
case ATAPI_SK_RESERVED:
printf("atapi_error: %s - timeout error = %02x\n",
atapi_cmd2str(cmd), error & 0x0f);
printf("atapi_error: %s - timeout error = %02x\n",
atapi_cmd2str(cmd), error & ATAPI_E_MASK);
return EIO;
case ATAPI_SK_NO_SENSE:
if (error & 0x0f) {
printf("atapi_error: %s - error = %02x\n",
atapi_cmd2str(cmd), error & 0x0f);
return EIO;
}
return 0;
case ATAPI_SK_RECOVERED_ERROR:
printf("atapi_error: %s - recovered error\n", atapi_cmd2str(cmd));
printf("atapi_error: %s - recovered error\n", atapi_cmd2str(cmd));
return 0;
case ATAPI_SK_NOT_READY:
if (error & 0x0f)
break;
atp->flags |= ATAPI_F_MEDIA_CHANGED;
return EBUSY;
case ATAPI_SK_UNIT_ATTENTION:
return EAGAIN; /* misused */
atp->flags |= ATAPI_F_MEDIA_CHANGED;
return EIO;
}
bzero(&sense, sizeof(struct atapi_reqsense));
atapi_queue_cmd(atp, ccb, &sense, sizeof(struct atapi_reqsense),
A_READ, 10, NULL, NULL, NULL);
atapi_request_sense(atp, &sense);
printf("atapi_error: %s - %s skey=%01x asc=%02x ascq=%02x error=%02x\n",
atapi_cmd2str(cmd), atapi_skey2str(sense.sense_key),
sense.sense_key, sense.asc, sense.ascq, error & 0x0f);
sense.sense_key, sense.asc, sense.ascq, error & ATAPI_E_MASK);
return EIO;
}
int32_t
atapi_test_ready(struct atapi_softc *atp)
{
int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_immed_cmd(atp, ccb, NULL, 0, 0, 30);
}
int32_t
atapi_wait_ready(struct atapi_softc *atp, int32_t timeout)
{
int32_t error = 0, timout = timeout * hz;
while (timout > 0) {
error = atapi_test_ready(atp);
if ((error & ATAPI_SK_MASK) != ATAPI_SK_NOT_READY)
break;
#ifdef ATAPI_DEBUG
printf("atapi: waiting on error=%02x\n", error);
#endif
tsleep((caddr_t)&error, PRIBIO, "atpwt", 50);
timout -= 50;
}
return error;
}
void
atapi_request_sense(struct atapi_softc *atp, struct atapi_reqsense *sense)
{
int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, sizeof(sense),
0, 0, 0 ,0 ,0, 0, 0, 0, 0, 0, 0 };
bzero(sense, sizeof(struct atapi_reqsense));
atapi_immed_cmd(atp, ccb, sense, sizeof(struct atapi_reqsense),
A_READ, 10);
}
void
atapi_dump(int8_t *label, void *data, int32_t len)
{
@ -552,20 +656,22 @@ atapi_cmd2str(u_int8_t cmd)
{
switch (cmd) {
case 0x00: return ("TEST_UNIT_READY");
case 0x01: return ("REZERO_UNIT/TAPE_REWIND");
case 0x01: return ("REWIND");
case 0x03: return ("REQUEST_SENSE");
case 0x04: return ("FORMAT_UNIT");
case 0x08: return ("TAPE_READ");
case 0x0a: return ("TAPE_WRITE");
case 0x10: return ("TAPE_WEOF");
case 0x11: return ("TAPE_SPACE");
case 0x19: return ("TAPE_ERASE");
case 0x1a: return ("TAPE_MODE_SENSE");
case 0x1b: return ("START_STOP/TAPE_LOAD");
case 0x08: return ("READ");
case 0x0a: return ("WRITE");
case 0x10: return ("WEOF");
case 0x11: return ("SPACE");
case 0x15: return ("MODE_SELECT");
case 0x19: return ("ERASE");
case 0x1a: return ("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 0x34: return ("TAPE_READ_POSITION");
case 0x35: return ("SYNCHRONIZE_CACHE");
case 0x42: return ("READ_SUBCHANNEL");
case 0x43: return ("READ_TOC");
@ -573,10 +679,10 @@ atapi_cmd2str(u_int8_t cmd)
case 0x52: return ("READ_TRACK_INFO");
case 0x53: return ("RESERVE_TRACK");
case 0x54: return ("SEND_OPC_INFO");
case 0x55: return ("MODE_SELECT");
case 0x55: return ("MODE_SELECT_BIG");
case 0x58: return ("REPAIR_TRACK");
case 0x59: return ("READ_MASTER_CUE");
case 0x5a: return ("MODE_SENSE");
case 0x5a: return ("MODE_SENSE_BIG");
case 0x5b: return ("CLOSE_TRACK/SESSION");
case 0x5c: return ("READ_BUFFER_CAPACITY");
case 0x5d: return ("SEND_CUE_SHEET");
@ -623,35 +729,34 @@ atapi_skey2str(u_int8_t skey)
static int32_t
atapi_wait(struct atapi_softc *atp, u_int8_t mask)
{
u_int8_t status;
u_int32_t timeout = 0;
while (timeout++ <= 500000) { /* timeout 5 secs */
status = inb(atp->controller->ioaddr + ATA_STATUS);
while (timeout++ <= 500000) { /* timeout 5 secs */
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
/* if drive fails status, reselect the drive just to be sure */
if (status == 0xff) {
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
DELAY(1);
status = inb(atp->controller->ioaddr + ATA_STATUS);
}
if (!(status & ATA_S_BSY) && (status & ATA_S_DRDY))
break;
DELAY (10);
}
if (timeout <= 0)
return -1;
if (!mask)
return (status & ATA_S_ERROR);
/* if drive fails status, reselect the drive just to be sure */
if (atp->controller->status == 0xff) {
outb(atp->controller->ioaddr + ATA_DRIVE, ATA_D_IBM | atp->unit);
DELAY(1);
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
}
if (!(atp->controller->status & ATA_S_BSY) && (atp->controller->status & ATA_S_DRDY))
break;
DELAY (10);
}
if (timeout <= 0)
return -1;
if (!mask)
return (atp->controller->status & ATA_S_ERROR);
/* Wait 50 msec for bits wanted. */
for (timeout=5000; timeout>0; --timeout) {
status = inb(atp->controller->ioaddr + ATA_STATUS);
if ((status & mask) == mask)
return (status & ATA_S_ERROR);
DELAY (10);
}
return -1;
/* Wait 50 msec for bits wanted. */
for (timeout=5000; timeout>0; --timeout) {
atp->controller->status = inb(atp->controller->ioaddr + ATA_STATUS);
if ((atp->controller->status & mask) == mask)
return (atp->controller->status & ATA_S_ERROR);
DELAY (10);
}
return -1;
}
static void
@ -659,20 +764,20 @@ 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;
(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);
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 */
#endif /* NATA > 0 && (NATAPICD > 0 || NATAPIFD > 0 || NATAPIST > 0) */

View File

@ -29,8 +29,8 @@
*/
/* ATAPI misc defines */
#define ATAPI_MAGIC_LSB 0x14
#define ATAPI_MAGIC_MSB 0xeb
#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)
@ -38,92 +38,94 @@
#define ATAPI_P_DONE (ATA_I_IN | ATA_I_CMD)
/* error register bits */
#define ATAPI_E_MASK 0x0f /* error mask */
#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 /* write protect */
#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_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 /* write protect */
#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_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 tape commands not in std ATAPI command set */
#define ATAPI_TAPE_REWIND 0x01 /* tape rewind */
#define ATAPI_TAPE_READ_CMD 0x08 /* tape read data */
#define ATAPI_TAPE_WRITE_CMD 0x0a /* tape write data */
#define ATAPI_TAPE_WEOF 0x10 /* tape write EOF */
#define WEOF_WRITE_MASK 0x01
#define ATAPI_TAPE_SPACE_CMD 0x11 /* tape space command */
#define SP_FM 0x01
#define SP_EOD 0x03
#define ATAPI_TAPE_ERASE 0x19 /* tape erase */
#define ATAPI_TAPE_MODE_SENSE 0x1a /* tape mode sense */
#define ATAPI_TAPE_LOAD_UNLOAD 0x1b /* tape load/unload */
#define LU_LOAD_MASK 0x01
#define LU_RETENSION_MASK 0x02
#define LU_EOT_MASK 0x04
#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
#define ATAPI_REWIND 0x01 /* rewind */
#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
#define ATAPI_READ 0x08 /* read data */
#define ATAPI_WRITE 0x0a /* write data */
#define ATAPI_WEOF 0x10 /* write filemark */
#define WF_WRITE 0x01
#define ATAPI_SPACE 0x11 /* space command */
#define SP_FM 0x01
#define SP_EOD 0x03
#define ATAPI_MODE_SELECT 0x15 /* mode select */
#define ATAPI_ERASE 0x19 /* erase */
#define ATAPI_MODE_SENSE 0x1a /* mode sense */
#define ATAPI_START_STOP 0x1b /* start/stop unit */
#define SS_LOAD 0x01
#define SS_RETENSION 0x02
#define SS_EJECT 0x04
#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_LOCATE 0x2b /* locate to position */
#define ATAPI_READ_POSITION 0x34 /* read position */
#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */
#define ATAPI_READ_BUFFER 0x3c /* read device buffer */
#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 /* pause audio operation */
#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */
#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
#define ATAPI_BLANK 0xa1 /* blank the 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_int8_t cmdsize :2; /* packet command size */
u_int8_t cmdsize :2; /* packet command size */
#define ATAPI_PSIZE_12 0 /* 12 bytes */
#define ATAPI_PSIZE_16 1 /* 16 bytes */
u_int8_t :3;
u_int8_t drqtype :2; /* DRQ type */
#define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */
#define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */
#define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */
u_int8_t :3;
u_int8_t drqtype :2; /* DRQ type */
#define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */
#define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */
#define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */
u_int8_t removable :1; /* device is removable */
u_int8_t device_type :5; /* device type */
u_int8_t removable :1; /* device is removable */
u_int8_t device_type :5; /* device type */
#define ATAPI_TYPE_DIRECT 0 /* disk/floppy */
#define ATAPI_TYPE_TAPE 1 /* streaming tape */
#define ATAPI_TYPE_CDROM 5 /* CD-ROM device */
#define ATAPI_TYPE_TAPE 1 /* streaming tape */
#define ATAPI_TYPE_CDROM 5 /* CD-ROM device */
#define ATAPI_TYPE_OPTICAL 7 /* optical disk */
u_int8_t :1;
u_int8_t proto :2; /* command protocol */
#define ATAPI_PROTO_ATAPI 2
u_int8_t :1;
u_int8_t proto :2; /* command protocol */
#define ATAPI_PROTO_ATAPI 2
int16_t reserved1;
int16_t reserved2;
@ -144,13 +146,13 @@ struct atapi_params {
int16_t reserved48;
u_int8_t vendorcap; /* vendor capabilities */
u_int8_t dmaflag :1; /* DMA supported */
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 :1;
u_int8_t ovlapflag :1; /* overlap supported */
u_int8_t :1;
u_int8_t :1;
u_int8_t idmaflag :1; /* interleaved DMA supported */
int16_t capvalidate; /* validation for above */
@ -158,14 +160,14 @@ struct atapi_params {
u_int16_t dmatiming; /* DMA cycle timing */
u_int16_t atavalid; /* fields valid */
#define ATAPI_FLAG_54_58 1 /* words 54-58 valid */
#define ATAPI_FLAG_64_70 2 /* words 64-70 valid */
#define ATAPI_FLAG_54_58 1 /* words 54-58 valid */
#define ATAPI_FLAG_64_70 2 /* words 64-70 valid */
int16_t reserved54[8];
int16_t sdmamodes; /* singleword DMA modes */
int16_t wdmamodes; /* multiword DMA modes */
int16_t apiomodes; /* advanced PIO modes */
int16_t sdmamodes; /* singleword DMA modes */
int16_t wdmamodes; /* multiword DMA modes */
int16_t apiomodes; /* advanced PIO modes */
u_int16_t mwdmamin; /* min. M/W DMA time/word ns */
u_int16_t mwdmarec; /* rec. M/W DMA time ns */
@ -176,60 +178,65 @@ struct atapi_params {
int16_t reserved70;
u_int16_t rlsovlap; /* rel time (us) for overlap */
u_int16_t rlsservice; /* rel time (us) for service */
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 udmamodes; /* UltraDMA modes */
int16_t erasetime;
int16_t enherasetime;
int16_t apmlevel;
int16_t reserved92[34];
int16_t rmvcap;
int16_t securelevel;
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 udmamodes; /* UltraDMA modes */
int16_t erasetime;
int16_t enherasetime;
int16_t apmlevel;
int16_t reserved92[34];
int16_t rmvcap;
int16_t securelevel;
};
/* ATAPI REQUEST SENSE structure */
/* ATAPI request sense structure */
struct atapi_reqsense {
u_int8_t error_code :7; /* current or deferred errors */
u_int8_t valid :1; /* follows ATAPI spec */
u_int8_t segment; /* Segment number */
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 error_code :7; /* current or deferred errors */
u_int8_t valid :1; /* follows ATAPI spec */
u_int8_t segment; /* Segment number */
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 */
/* cmd information */
u_int32_t cmd_info __attribute__((packed));
u_int8_t sense_length; /* additional sense length (n-7) */
u_int32_t cmd_info __attribute__((packed));
u_int8_t sense_length; /* additional sense length (n-7) */
/* additional cmd specific info */
u_int32_t cmd_specific_info __attribute__((packed));
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_int32_t cmd_specific_info __attribute__((packed));
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 */
};
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 */
int8_t last_cmd; /* last cmd executed */
u_int32_t flags; /* drive flags */
struct ata_softc *controller; /* ptr to parent ctrl */
struct atapi_params *atapi_parm; /* ata device params */
int32_t unit; /* ATA_MASTER or ATA_SLAVE */
int8_t cmd; /* last cmd executed */
u_int32_t flags; /* drive flags */
#define ATAPI_F_MEDIA_CHANGED 0x0001
#define ATAPI_F_DMA_ENABLED 0x0002
#define ATAPI_F_DMA_USED 0x0004
#define ATAPI_F_DRQT_CMD 0x0008
};
typedef void atapi_callback_t(struct atapi_request *);
@ -239,13 +246,13 @@ struct atapi_request {
void *driver; /* ptr to calling driver */
u_int8_t ccb[16]; /* command control block */
int32_t ccbsize; /* size of ccb (12 | 16) */
u_int32_t bytecount; /* bytes to transfer */
u_int32_t donecount; /* bytes transferred */
u_int32_t result; /* result code */
int32_t flags;
u_int32_t bytecount; /* bytes to transfer */
u_int32_t donecount; /* bytes transferred */
int32_t timeout; /* timeout for this cmd */
struct callout_handle timeout_handle; /* handle for untimeout */
int32_t result; /* result of this cmd */
int32_t flags;
#define A_READ 0x0001
#define ATAPI_F_DMA_ENABLED 0x0002
#define ATAPI_F_DMA_USED 0x0004
int8_t *data; /* pointer to data buf */
struct buf *bp; /* associated buf ptr */
@ -255,7 +262,12 @@ struct atapi_request {
void atapi_transfer(struct atapi_request *);
int32_t atapi_interrupt(struct atapi_request *);
int32_t atapi_immed_cmd(struct atapi_softc *, int8_t *, void *, int32_t, int32_t, int32_t);
int32_t atapi_queue_cmd(struct atapi_softc *, int8_t [], void *, int32_t, int32_t, int32_t, atapi_callback_t, void *, struct buf *);
void atapi_reinit(struct atapi_softc *);
int32_t atapi_error(struct atapi_softc *, int32_t);
int32_t atapi_test_ready(struct atapi_softc *);
int32_t atapi_wait_ready(struct atapi_softc *, int32_t);
void atapi_request_sense(struct atapi_softc *, struct atapi_reqsense *);
void atapi_dump(int8_t *, void *, int32_t);

File diff suppressed because it is too large Load Diff

View File

@ -37,80 +37,86 @@ struct toc {
/* CDROM Audio Control Parameters Page */
struct audiopage {
/* Mode Page data header */
/* 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 */
/* audio control page */
u_int8_t page_code;
#define ATAPI_CDROM_AUDIO_PAGE 0x0e
#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
#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 channels:4;
#define CHANNEL_0 1
#define CHANNEL_1 2
#define CHANNEL_2 4
#define CHANNEL_3 8
u_int8_t volume;
u_int8_t volume;
} port[4];
};
/* CDROM Capabilities and Mechanical Status Page */
struct cappage {
/* Mode data header */
/* mode page data header */
u_int16_t data_length;
u_int8_t medium_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_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_CDR 0x10
#define MST_CDRW 0x20
#define MST_NO_DISC 0x70
#define MST_DOOR_OPEN 0x71
#define MST_FMT_ERROR 0x72
#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 */
/* 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 reserved2_37 :5;
u_int8_t read_packet :1; /* supports reading packet tracks */
u_int8_t read_dvdrom :1; /* supports DVD-ROM read */
u_int8_t read_dvdr :1; /* supports DVD-R read */
u_int8_t read_dvdram :1; /* supports DVD-RAM read */
u_int8_t reserved2_67 :2;
u_int8_t write_cdr :1; /* supports CD-R write */
u_int8_t write_cdrw :1; /* supports CD-RW write */
u_int8_t test_write :1; /* supports test writing */
u_int8_t reserved3_37 :5;
u_int8_t reserved3_3 :1;
u_int8_t write_dvdr :1; /* supports DVD-R write */
u_int8_t write_dvdram :1; /* supports DVD-RAM write */
u_int8_t reserved3_67 :2;
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 */
@ -133,33 +139,34 @@ struct cappage {
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
#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_read_speed; /* max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* number of discrete volume levels */
u_int16_t buf_size; /* internal buffer size in bytes/1024 */
u_int16_t cur_speed; /* current data rate in bytes/1000 */
u_int16_t cur_read_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
#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];
u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */
u_int16_t cur_write_speed; /* current data rate in bytes/1000 */
};
/* CDROM Changer mechanism status structure */
@ -184,34 +191,34 @@ struct changer {
u_int8_t slots; /* number of available slots */
u_int16_t table_length; /* slot table length */
struct {
u_int8_t changed :1; /* media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t changed :1; /* media has changed in this slot */
u_int8_t unused :6;
u_int8_t present :1; /* slot has a CD present */
u_int8_t reserved0;
u_int8_t reserved1;
u_int8_t reserved2;
} slot[32];
};
/* CDROM Write Parameters Mode Page (Burners ONLY) */
struct write_param {
/* Mode Page data header */
/* 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 */
/* write parameters page */
u_int8_t page_code;
#define ATAPI_CDROM_WRITE_PARAMETERS_PAGE 0x05
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
#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;
@ -225,28 +232,28 @@ struct write_param {
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
#define CDR_MSES_NONE 0x00
#define CDR_MSES_FINAL 0x01
#define CDR_MSES_RESERVED 0x02
#define CDR_MSES_MULTI 0x03
u_int8_t data_block_type :4; /* data block type code */
u_int8_t data_block_type :4; /* data block type code */
#define CDR_DB_RAW 0x0 /* 2352 bytes of raw data */
#define CDR_DB_RAW_PQ 0x1 /* 2368 bytes raw data + P/Q subchan */
#define CDR_DB_RAW_PW 0x2 /* 2448 bytes raw data + P-W subchan */
#define CDR_DB_RAW_PW_R 0x3 /* 2448 bytes raw data + P-W raw sub */
#define CDR_DB_RES_4 0x4 /* reserved */
#define CDR_DB_RES_5 0x5 /* reserved */
#define CDR_DB_RES_6 0x6 /* reserved */
#define CDR_DB_VS_7 0x7 /* vendor specific */
#define CDR_DB_ROM_MODE1 0x8 /* 2048 bytes Mode 1 (ISO/IEC 10149) */
#define CDR_DB_ROM_MODE2 0x9 /* 2336 bytes Mode 2 (ISO/IEC 10149) */
#define CDR_DB_XA_MODE1 0x10 /* 2048 bytes Mode 1 (CD-ROM XA 1) */
#define CDR_DB_XA_MODE2_F1 0x11 /* 2056 bytes Mode 2 (CD-ROM XA 1) */
#define CDR_DB_XA_MODE2_F2 0x12 /* 2324 bytes Mode 2 (CD-ROM XA 2) */
#define CDR_DB_XA_MODE2_MIX 0x13 /* 2332 bytes Mode 2 (CD-ROM XA 1/2) */
#define CDR_DB_RES_14 0x14 /* reserved */
#define CDR_DB_VS_15 0x15 /* vendor specific */
#define CDR_DB_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;
@ -268,12 +275,11 @@ struct write_param {
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;
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 */
@ -302,39 +308,47 @@ struct acd_track_info {
/* Structure describing an ATAPI CDROM device */
struct acd_softc {
struct atapi_softc *atp; /* controller structure */
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
#define F_BOPEN 0x0001 /* the block device is opened */
#define F_LOCKED 0x0002 /* this unit is locked */
#define F_WRITING 0x0004 /* this unit is writing */
#define F_TRACK_PREP 0x0010 /* track should be prep'ed */
#define F_TRACK_PREPED 0x0020 /* track has been prep'ed */
#define F_DISK_PREPED 0x0040 /* disk has been prep'ed */
#define F_WRITTEN 0x0080 /* medium has been written to */
int32_t refcnt; /* the number of raw opens */
struct buf_queue_head buf_queue; /* Queue of i/o requests */
struct toc toc; /* table of disc contents */
struct toc toc; /* table of disc contents */
struct {
u_int32_t volsize; /* volume size in blocks */
u_int32_t blksize; /* block size in bytes */
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 audiopage au; /* audio page info */
struct cappage cap; /* capabilities page info */
struct audiopage aumask; /* audio page mask */
struct { /* subchannel info */
u_int8_t void0;
u_int8_t audio_status;
u_int16_t data_length;
u_int8_t data_format;
u_int8_t control;
u_int8_t track;
u_int8_t indx;
u_int32_t abslba;
u_int32_t rellba;
u_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 */
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 */
u_int32_t next_writeable_addr; /* next writable address */
struct wormio_prepare_track preptrack; /* scratch region */
struct devstat *stats; /* devstat entry */
};
#define CDRIOCBLANK _IO('c',100) /* blank a CDRW disc */
#define CDRIOCNEXTWRITEABLEADDR _IOR('c',101,int)
#define CDRIOCBLANK _IO('c',100) /* blank a CDRW disc */
#define CDRIOCNEXTWRITEABLEADDR _IOR('c',101,int)

View File

@ -30,6 +30,7 @@
#include "ata.h"
#include "atapifd.h"
#include "apm.h"
#if NATA > 0 && NATAPIFD > 0
@ -40,22 +41,24 @@
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
#include <sys/diskslice.h>
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/devicestat.h>
#include <sys/cdio.h>
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <pci/pcivar.h>
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#include <dev/ata/ata-all.h>
#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-fd.h>
static d_open_t afdopen;
static d_close_t afdclose;
static d_ioctl_t afdioctl;
static d_strategy_t afdstrategy;
static d_open_t afdopen;
static d_close_t afdclose;
static d_ioctl_t afdioctl;
static d_strategy_t afdstrategy;
static struct cdevsw afd_cdevsw = {
/* open */ afdopen,
@ -78,46 +81,41 @@ static struct cdevsw afd_cdevsw = {
/* maxio */ 0,
/* bmaj */ 32,
};
static struct cdevsw afddisk_cdevsw;
#define NUNIT 8
#define UNIT(d) ((minor(d) >> 3) & 3)
#define F_OPEN 0x0001 /* the device is opened */
#define F_MEDIA_CHANGED 0x0002 /* the media have changed */
static struct afd_softc *afdtab[NUNIT]; /* drive info by unit number */
static int32_t afdnlun = 0; /* number of config'd drives */
/* prototypes */
int32_t afdattach(struct atapi_softc *);
static int32_t afd_sense(struct afd_softc *);
static void afd_describe(struct afd_softc *);
static void afd_start(struct afd_softc *);
static void afd_partial_done(struct atapi_request *);
static void afd_done(struct atapi_request *);
static int32_t afd_start_device(struct afd_softc *, int32_t);
static int32_t afd_lock_device(struct afd_softc *, int32_t);
static int32_t afd_eject(struct afd_softc *, int32_t);
static void afd_drvinit(void *);
static int32_t afd_start_stop(struct afd_softc *, int32_t);
static int32_t afd_prevent_allow(struct afd_softc *, int32_t);
/* internal vars */
static int32_t afdnlun = 0; /* number of config'd drives */
int32_t
afdattach(struct atapi_softc *atp)
{
struct afd_softc *fdp;
dev_t dev;
if (!afd_cdevsw.d_maxio)
afd_cdevsw.d_maxio = 254 * DEV_BSIZE;
if (afdnlun >= NUNIT) {
printf("afd: too many units\n");
return -1;
}
fdp = malloc(sizeof(struct afd_softc), M_TEMP, M_NOWAIT);
if (!fdp) {
printf("afd: out of memory\n");
return -1;
printf("afd: out of memory\n");
return -1;
}
bzero(fdp, sizeof(struct afd_softc));
bufq_init(&fdp->buf_queue);
fdp->atp = atp;
fdp->lun = afdnlun;
fdp->flags = F_MEDIA_CHANGED;
fdp->lun = afdnlun++;
fdp->atp->flags |= ATAPI_F_MEDIA_CHANGED;
if (afd_sense(fdp)) {
free(fdp, M_TEMP);
@ -128,46 +126,46 @@ afdattach(struct atapi_softc *atp)
fdp->transfersize = 64;
afd_describe(fdp);
afdtab[afdnlun++] = fdp;
devstat_add_entry(&fdp->stats, "afd", fdp->lun, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
0x174);
make_dev(&afd_cdevsw, dkmakeminor(fdp->lun, 0,0),
UID_ROOT, GID_OPERATOR, 0640, "rafd%d", fdp->lun);
make_dev(&afd_cdevsw, dkmakeminor(fdp->lun, 0,0),
UID_ROOT, GID_OPERATOR, 0640, "afd%d", fdp->lun);
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
0x174);
dev = disk_create(fdp->lun, &fdp->disk, 0, &afd_cdevsw, &afddisk_cdevsw);
dev->si_drv1 = fdp;
return 0;
}
static int32_t
afd_sense(struct afd_softc *fdp)
{
int32_t error, count;
int8_t buffer[256];
int8_t ccb[16] = { ATAPI_MODE_SENSE, 0, ATAPI_REWRITEABLE_CAP_PAGE,
int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
0, 0, 0, 0, sizeof(buffer)>>8, sizeof(buffer) & 0xff,
0, 0, 0, 0, 0, 0, 0 };
0, 0, 0, 0, 0, 0, 0 };
int32_t error, count;
bzero(buffer, sizeof(buffer));
/* get drive capabilities, some drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
if (!(error = atapi_queue_cmd(fdp->atp, ccb, buffer, sizeof(buffer),
A_READ, 30, NULL, NULL, NULL)))
break;
if (!(error = atapi_immed_cmd(fdp->atp, ccb, buffer, sizeof(buffer),
A_READ, 30))) {
error = atapi_error(fdp->atp, error);
break;
}
}
#ifdef AFD_DEBUG
atapi_dump("afd: sense", buffer, sizeof(buffer));
#endif
if (error)
return error;
return error;
bcopy(buffer, &fdp->header, sizeof(struct afd_header));
bcopy(buffer+sizeof(struct afd_header), &fdp->cap,
sizeof(struct afd_cappage));
if (fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
return 1;
return 1;
fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
return 0;
}
@ -181,15 +179,20 @@ afd_describe(struct afd_softc *fdp)
bpack(fdp->atp->atapi_parm->revision, revision_buf, sizeof(revision_buf));
printf("afd%d: <%s/%s> rewriteable drive at ata%d as %s\n",
fdp->lun, model_buf, revision_buf,
fdp->atp->controller->lun,
fdp->atp->controller->lun,
(fdp->atp->unit == ATA_MASTER) ? "master" : "slave ");
printf("afd%d: %luMB (%u sectors), %u cyls, %u heads, %u S/T, %u B/S\n",
afdnlun,
fdp->lun,
(fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
((1024L * 1024L) / fdp->cap.sector_size),
fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors,
fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
fdp->cap.sector_size);
printf("afd%d: %dKB/s,", fdp->lun, fdp->cap.transfer_rate/8);
if (fdp->transfersize)
printf(" transfer limit %d blks,", fdp->transfersize);
printf(" %s\n", ata_mode2str(fdp->atp->controller->mode[
(fdp->atp->unit == ATA_MASTER) ? 0 : 1]));
printf("afd%d: Medium: ", fdp->lun);
switch (fdp->header.medium_type) {
case MFD_2DD:
@ -213,97 +216,67 @@ afd_describe(struct afd_softc *fdp)
static int
afdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
struct afd_softc *fdp;
struct disklabel label;
int32_t lun = UNIT(dev);
struct afd_softc *fdp = dev->si_drv1;
struct disklabel *label;
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
fdp->flags &= ~F_MEDIA_CHANGED;
afd_lock_device(fdp, 1);
fdp->atp->flags &= ~ATAPI_F_MEDIA_CHANGED;
afd_prevent_allow(fdp, 1);
if (afd_sense(fdp))
printf("afd%d: sense media type failed\n", fdp->lun);
printf("afd%d: sense media type failed\n", fdp->lun);
/* build disklabel and initilize slice tables */
bzero(&label, sizeof label);
label.d_secsize = fdp->cap.sector_size;
label.d_nsectors = fdp->cap.sectors;
label.d_ntracks = fdp->cap.heads;
label.d_ncylinders = fdp->cap.cylinders;
label.d_secpercyl = fdp->cap.heads * fdp->cap.sectors;
label.d_secperunit = fdp->cap.heads * fdp->cap.sectors * fdp->cap.cylinders;
label = &fdp->disk.d_label;
bzero(label, sizeof *label);
label->d_secsize = fdp->cap.sector_size;
label->d_nsectors = fdp->cap.sectors;
label->d_ntracks = fdp->cap.heads;
label->d_ncylinders = fdp->cap.cylinders;
label->d_secpercyl = fdp->cap.heads * fdp->cap.sectors;
label->d_secperunit = label->d_secpercyl * fdp->cap.cylinders;
/* initialize slice tables. */
return dsopen(dev, fmt, 0, &fdp->slices, &label);
return 0;
}
static int
afdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct afd_softc *fdp;
struct afd_softc *fdp = dev->si_drv1;
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
dsclose(dev, fmt, fdp->slices);
if(!dsisopen(fdp->slices))
afd_lock_device(fdp, 0);
afd_prevent_allow(fdp, 0);
return 0;
}
static int
afdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
int32_t lun = UNIT(dev);
int32_t error = 0;
struct afd_softc *fdp;
if (lun >= afdnlun || !(fdp = afdtab[lun]))
return ENXIO;
error = dsioctl(dev, cmd, addr, flag, &fdp->slices);
if (error != ENOIOCTL)
return error;
struct afd_softc *fdp = dev->si_drv1;
switch (cmd) {
case CDIOCEJECT:
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return EBUSY;
return afd_eject(fdp, 0);
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return EBUSY;
return afd_eject(fdp, 0);
case CDIOCCLOSE:
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return 0;
return afd_eject(fdp, 1);
if ((fdp->flags & F_OPEN) && fdp->refcnt)
return 0;
return afd_eject(fdp, 1);
default:
return ENOTTY;
return ENOIOCTL;
}
}
static void
afdstrategy(struct buf *bp)
{
int32_t lun = UNIT(bp->b_dev);
struct afd_softc *fdp = afdtab[lun];
int32_t x;
struct afd_softc *fdp = bp->b_dev->si_drv1;
int32_t s;
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
}
if (dscheck(bp, fdp->slices) <= 0) {
biodone(bp);
return;
}
x = splbio();
s = splbio();
bufq_insert_tail(&fdp->buf_queue, bp);
afd_start(fdp);
splx(x);
splx(s);
}
static void
@ -315,16 +288,16 @@ afd_start(struct afd_softc *fdp)
int8_t *data_ptr;
if (!bp)
return;
return;
bufq_remove(&fdp->buf_queue, bp);
/* should reject all queued entries if media have changed. */
if (fdp->flags & F_MEDIA_CHANGED) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
if (fdp->atp->flags & ATAPI_F_MEDIA_CHANGED) {
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
}
lba = bp->b_blkno / (fdp->cap.sector_size / DEV_BSIZE);
@ -342,16 +315,16 @@ afd_start(struct afd_softc *fdp)
devstat_start_transaction(&fdp->stats);
while (fdp->transfersize && (count > fdp->transfersize)) {
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = fdp->transfersize>>8;
ccb[8] = fdp->transfersize;
ccb[2] = lba>>24;
ccb[3] = lba>>16;
ccb[4] = lba>>8;
ccb[5] = lba;
ccb[7] = fdp->transfersize>>8;
ccb[8] = fdp->transfersize;
atapi_queue_cmd(fdp->atp, ccb, data_ptr,
atapi_queue_cmd(fdp->atp, ccb, data_ptr,
fdp->transfersize * fdp->cap.sector_size,
(bp->b_flags & B_READ) ? A_READ : 0, 30,
(bp->b_flags & B_READ) ? A_READ : 0, 30,
afd_partial_done, fdp, bp);
count -= fdp->transfersize;
@ -367,7 +340,7 @@ afd_start(struct afd_softc *fdp)
ccb[8] = count;
atapi_queue_cmd(fdp->atp, ccb, data_ptr, count * fdp->cap.sector_size,
(bp->b_flags & B_READ) ? A_READ : 0, 30, afd_done, fdp, bp);
(bp->b_flags & B_READ) ? A_READ : 0, 30, afd_done, fdp, bp);
}
static void
@ -376,8 +349,8 @@ afd_partial_done(struct atapi_request *request)
struct buf *bp = request->bp;
if (request->result) {
bp->b_error = atapi_error(request->device, request->result);
bp->b_flags |= B_ERROR;
bp->b_error = atapi_error(request->device, request->result);
bp->b_flags |= B_ERROR;
}
bp->b_resid += request->bytecount;
}
@ -389,76 +362,61 @@ afd_done(struct atapi_request *request)
struct afd_softc *fdp = request->driver;
if (request->result || (bp->b_flags & B_ERROR)) {
bp->b_error = atapi_error(request->device, request->result);
bp->b_flags |= B_ERROR;
bp->b_error = atapi_error(request->device, request->result);
bp->b_flags |= B_ERROR;
}
else
bp->b_resid += request->bytecount;
devstat_end_transaction_buf(&fdp->stats, bp);
biodone(bp);
afd_start(fdp);
}
static int32_t
afd_start_device(struct afd_softc *fdp, int32_t start)
{
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL);
}
static int32_t
afd_lock_device(struct afd_softc *fdp, int32_t lock)
{
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL);
}
static int32_t
afd_eject(struct afd_softc *fdp, int32_t close)
{
int32_t error;
error = afd_start_device(fdp, 0);
if (error == EBUSY || error == EAGAIN) {
if (!close)
return 0;
if ((error = afd_start_device(fdp, 3)))
error = afd_start_stop(fdp, 0);
if (((fdp->atp->controller->error&ATAPI_SK_MASK)==ATAPI_SK_NOT_READY) ||
((fdp->atp->controller->error&ATAPI_SK_MASK)==ATAPI_SK_UNIT_ATTENTION)){
if (!close)
return 0;
if ((error = afd_start_stop(fdp, 3)))
return error;
return afd_lock_device(fdp, 1);
return afd_prevent_allow(fdp, 1);
}
if (error)
return error;
return error;
if (close)
return 0;
return 0;
tsleep((caddr_t) &lbolt, PRIBIO, "afdej1", 0);
tsleep((caddr_t) &lbolt, PRIBIO, "afdej2", 0);
if ((error = afd_lock_device(fdp, 0)))
if ((error = afd_prevent_allow(fdp, 0)))
return error;
fdp->flags |= F_MEDIA_CHANGED;
return afd_start_device(fdp, 2);
fdp->atp->flags |= ATAPI_F_MEDIA_CHANGED;
return afd_start_stop(fdp, 2);
}
static void
afd_drvinit(void *unused)
static int32_t
afd_start_stop(struct afd_softc *fdp, int32_t start)
{
static int32_t afd_devsw_installed = 0;
int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
if (!afd_devsw_installed) {
if (!afd_cdevsw.d_maxio)
afd_cdevsw.d_maxio = 254 * DEV_BSIZE;
cdevsw_add(&afd_cdevsw);
afd_devsw_installed = 1;
}
error = atapi_immed_cmd(fdp->atp, ccb, NULL, 0, 0, 10);
if (error)
return atapi_error(fdp->atp, error);
return atapi_error(fdp->atp, atapi_wait_ready(fdp->atp, 30));
}
SYSINIT(afddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, afd_drvinit, NULL)
static int32_t
afd_prevent_allow(struct afd_softc *fdp, int32_t lock)
{
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_error(fdp->atp, atapi_immed_cmd(fdp->atp, ccb, NULL, 0, 0,30));
}
#endif /* NATA & NATAPIFD */

View File

@ -40,47 +40,48 @@ struct afd_header {
#define MFD_HD_144 0x24
#define MFD_UHD 0x31
#define MFD_UNKNOWN 0x00
#define MFD_NO_DISC 0x70
#define MFD_DOOR_OPEN 0x71
#define MFD_FMT_ERROR 0x72
#define MFD_UNKNOWN 0x00
#define MFD_NO_DISC 0x70
#define MFD_DOOR_OPEN 0x71
#define MFD_FMT_ERROR 0x72
u_int8_t reserved0 :7;
u_int8_t wp :1; /* write protect */
u_int8_t reserved0 :7;
u_int8_t wp :1; /* write protect */
u_int8_t unused[4];
};
/* ATAPI Rewriteable drive Capabilities and Mechanical Status Page */
#define ATAPI_REWRITEABLE_CAP_PAGE 0x05
struct afd_cappage {
u_int8_t page_code :6;
u_int8_t reserved1_6 :1;
u_int8_t ps :1; /* page save supported */
u_int8_t page_length; /* page length */
u_int16_t transfer_rate; /* in kilobits per second */
u_int8_t heads; /* number of heads */
u_int8_t page_code :6;
#define ATAPI_REWRITEABLE_CAP_PAGE 0x05
u_int8_t reserved1_6 :1;
u_int8_t ps :1; /* page save supported */
u_int8_t page_length; /* page length */
u_int16_t transfer_rate; /* in kilobits per second */
u_int8_t heads; /* number of heads */
u_int8_t sectors; /* number of sectors per track */
u_int16_t sector_size; /* number of bytes per sector */
u_int16_t cylinders; /* number of cylinders */
u_int16_t sector_size; /* number of bytes per sector */
u_int16_t cylinders; /* number of cylinders */
u_int8_t reserved10[10];
u_int8_t motor_delay; /* motor off delay */
u_int8_t motor_delay; /* motor off delay */
u_int8_t reserved21[7];
u_int16_t rpm; /* rotations per minute */
u_int16_t rpm; /* rotations per minute */
u_int8_t reserved30[2];
};
struct afd_softc {
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
int32_t refcnt; /* the number of raw opens */
int32_t transfersize; /* max size of each transfer */
struct buf_queue_head buf_queue; /* queue of i/o requests */
struct afd_header header; /* capabilities page info */
struct afd_cappage cap; /* capabilities page info */
struct diskslices *slices; /* virtual drives */
struct devstat stats;
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
#define F_OPEN 0x0001 /* the device is opened */
int32_t refcnt; /* the number of raw opens */
int32_t transfersize; /* max size of each transfer */
struct buf_queue_head buf_queue; /* queue of i/o requests */
struct afd_header header; /* capabilities page info */
struct afd_cappage cap; /* capabilities page info */
struct disk disk; /* virtual drives */
struct devstat stats;
};

View File

@ -30,6 +30,7 @@
#include "ata.h"
#include "atapist.h"
#include "apm.h"
#if NATA > 0 && NATAPIST > 0
@ -42,16 +43,19 @@
#include <sys/mtio.h>
#include <sys/disklabel.h>
#include <sys/devicestat.h>
#include <machine/clock.h>
#include <pci/pcivar.h>
#include <machine/clock.h>
#if NAPM > 0
#include <machine/apm_bios.h>
#endif
#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_close_t astclose;
static d_ioctl_t astioctl;
static d_strategy_t aststrategy;
static d_open_t astopen;
static d_close_t astclose;
static d_ioctl_t astioctl;
static d_strategy_t aststrategy;
static struct cdevsw ast_cdevsw = {
/* open */ astopen,
@ -75,102 +79,114 @@ static struct cdevsw ast_cdevsw = {
/* bmaj */ -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 */
/* misc defines */
#define NUNIT 8
/* prototypes */
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_mode_sense(struct ast_softc *, u_int8_t, void *, int32_t);
static int32_t ast_mode_select(struct ast_softc *, void *, 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_read_position(struct ast_softc *, int32_t, struct ast_readposition *);
static int32_t ast_space(struct ast_softc *, u_int8_t, u_int32_t);
static int32_t ast_locate(struct ast_softc *, int32_t, int32_t);
static int32_t ast_prevent_allow(struct ast_softc *stp, int32_t lock);
static int32_t ast_load_unload(struct ast_softc *, u_int8_t);
static int32_t ast_rewind(struct ast_softc *);
static int32_t ast_erase(struct ast_softc *);
static void ast_drvinit(void *);
/* internal vars */
static int32_t astnlun = 0; /* number of config'd drives */
static u_int64_t ast_total = 0;
static int32_t ast_buffermode = 0;
int32_t
astattach(struct atapi_softc *atp)
{
struct ast_softc *stp;
struct ast_readposition position;
dev_t dev;
if (astnlun >= NUNIT) {
printf("ast: too many units\n");
return -1;
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;
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;
stp->atp->flags |= ATAPI_F_MEDIA_CHANGED;
if (ast_sense(stp)) {
free(stp, M_TEMP);
return -1;
}
ast_describe(stp);
asttab[astnlun++] = stp;
if (!strcmp(stp->atp->atapi_parm->model, " OnStream DI-30")) {
struct ast_transferpage transfer;
struct ast_identifypage identify;
stp->flags |= F_ONSTREAM;
bzero(&transfer, sizeof(struct ast_transferpage));
ast_mode_sense(stp, ATAPI_TAPE_TRANSFER_PAGE,
&transfer, sizeof(transfer));
#ifdef AST_DEBUG
printf("ast: rd32k=%d rd32k5=%d wr32k=%d wr32k5=%d stream=%d\n",
transfer.read32k, transfer.read32k5,
transfer.write32k, transfer.write32k5, transfer.streaming);
#endif
bzero(&identify, sizeof(struct ast_identifypage));
ast_mode_sense(stp, ATAPI_TAPE_IDENTIFY_PAGE,
&identify, sizeof(identify));
strncpy(identify.ident, "FBSD", 4);
ast_mode_select(stp, &identify, sizeof(identify));
}
ast_read_position(stp, 0, &position);
devstat_add_entry(&stp->stats, "ast", stp->lun, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
0x170);
make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0,0),
UID_ROOT, GID_OPERATOR, 0640, "rast%d", stp->lun);
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_SEQUENTIAL | DEVSTAT_TYPE_IF_IDE,
0x170);
dev = make_dev(&ast_cdevsw, dkmakeminor(stp->lun, 0, 0),
UID_ROOT, GID_OPERATOR, 0640, "rast%d", stp->lun);
dev->si_drv1 = stp;
return 0;
}
static int32_t
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 };
int32_t count, error;
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, 30, NULL, NULL, NULL)))
break;
if (!(error = ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE,
&stp->cap, sizeof(stp->cap))))
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;
if (error)
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));
if (stp->cap.blk32k)
stp->blksize = 32768;
if (stp->cap.blk1024)
stp->blksize = 1024;
if (stp->cap.blk512)
stp->blksize = 512;
return 0;
}
@ -184,14 +200,21 @@ ast_describe(struct ast_softc *stp)
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->lun,
stp->atp->controller->lun,
(stp->atp->unit == ATA_MASTER) ? "master" : "slave ");
printf("ast%d: ", stp->lun);
switch (stp->header.medium_type) {
printf("%dKB/s, ", stp->cap.max_speed);
printf("transfer limit %d blk%s, ", stp->cap.ctl, (stp->cap.ctl>1)?"s":"");
printf("%dKB buffer, ", (stp->cap.buffer_size * DEV_BSIZE) / 1024);
printf("%s\n", ata_mode2str(stp->atp->controller->mode[
(stp->atp->unit == ATA_MASTER) ? 0 : 1]));
printf("ast%d: ", stp->lun);
switch (stp->cap.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);
case 0xda: printf("OnStream ADR (15Gyte) media"); break;
default: printf("Unknown media (0x%x)", stp->cap.medium_type);
}
if (stp->cap.readonly) printf(", readonly");
if (stp->cap.reverse) printf(", reverse");
@ -206,29 +229,27 @@ ast_describe(struct ast_softc *stp)
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);
if (stp->cap.blk32k) printf(", 32kb");
printf("\n");
}
static int
astopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct ast_softc *stp;
struct ast_softc *stp = dev->si_drv1;
if (lun >= astnlun || !(stp = asttab[lun]))
return ENXIO;
if (stp->flags == F_OPEN)
return EBUSY;
return EBUSY;
if (stp->cap.lock)
ast_prevent_allow(stp, 1);
if (ast_sense(stp))
printf("ast%d: sense media type failed\n", stp->lun);
stp->flags &= ~F_MEDIA_CHANGED;
printf("ast%d: sense media type failed\n", stp->lun);
stp->flags &= ~(F_DATA_WRITTEN | F_FM_WRITTEN);
stp->flags |= F_OPEN;
stp->atp->flags &= ~ATAPI_F_MEDIA_CHANGED;
ast_total = 0;
return 0;
}
@ -236,122 +257,139 @@ astopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
static int
astclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p)
{
int32_t lun = UNIT(dev);
struct ast_softc *stp;
struct ast_softc *stp = dev->si_drv1;
if (lun >= astnlun || !(stp = asttab[lun]))
return ENXIO;
/* flush buffers, some drives fail here, but they should report ctl = 0 */
/* flush buffers, some drives fail here, they should report ctl = 0 */
if (stp->cap.ctl && (stp->flags & F_DATA_WRITTEN))
ast_write_filemark(stp, 0);
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 (!(stp->flags & F_ONSTREAM) &&
(stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
ast_write_filemark(stp, WF_WRITE);
/* if minor is even rewind on close */
if (!(minor(dev) & 0x01))
if (!(minor(dev) & 0x01))
ast_rewind(stp);
stp->flags &= ~F_OPEN;
if (stp->cap.lock)
ast_prevent_allow(stp, 0);
stp->flags &= ~(F_OPEN | F_CTL_WARN);
#ifdef AST_DEBUG
printf("ast%d: %ud total bytes transferred\n", stp->lun, ast_total);
printf("ast%d: %llu total bytes transferred\n", stp->lun, ast_total);
#endif
stp->flags &= ~F_CTL_WARN;
return 0;
}
static int
astioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
{
int32_t lun = UNIT(dev);
struct ast_softc *stp = dev->si_drv1;
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;
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;
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;
struct mtop *mt = (struct mtop *)addr;
switch ((int16_t) (mt->mt_op)) {
switch ((int16_t) (mt->mt_op)) {
case MTWEOF:
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 MTREW:
error = ast_rewind(stp);
error = ast_write_filemark(stp, WF_WRITE);
break;
case MTOFFL:
if ((error = ast_rewind(stp)))
break;
error = ast_load_unload(stp, !LU_LOAD_MASK);
case MTFSF:
if (mt->mt_count)
error = ast_space(stp, SP_FM, mt->mt_count);
break;
case MTNOP:
case MTBSF:
if (mt->mt_count)
error = ast_space(stp, SP_FM, -(mt->mt_count));
break;
case MTREW:
error = ast_rewind(stp);
break;
case MTOFFL:
error = ast_load_unload(stp, SS_EJECT);
break;
case MTNOP:
error = ast_write_filemark(stp, 0);
break;
case MTERASE:
error = ast_erase(stp);
break;
case MTEOD:
error = ast_space_cmd(stp, SP_EOD, 0);
break;
case MTRETENS:
error = ast_load_unload(stp, LU_RETENSION_MASK|LU_LOAD_MASK);
case MTERASE:
error = ast_erase(stp);
break;
case MTFSR:
case MTBSR:
case MTCACHE:
case MTNOCACHE:
case MTSETBSIZ:
case MTSETDNSTY:
case MTCOMP:
default:
error = EINVAL;
}
return error;
}
case MTEOD:
error = ast_space(stp, SP_EOD, 0);
break;
case MTRETENS:
error = ast_load_unload(stp, SS_RETENSION | SS_LOAD);
break;
case MTFSR:
case MTBSR:
case MTCACHE:
case MTNOCACHE:
case MTSETBSIZ:
case MTSETDNSTY:
case MTCOMP:
default:
error = EINVAL;
}
break;
}
case MTIOCRDSPOS:
{
struct ast_readposition position;
if ((error = ast_read_position(stp, 0, &position)))
break;
(u_int32_t *)addr = position.tape;
break;
}
case MTIOCRDHPOS:
{
struct ast_readposition position;
if ((error = ast_read_position(stp, 1, &position)))
break;
(u_int32_t *)addr = position.tape;
break;
}
case MTIOCSLOCATE:
error = ast_locate(stp, 0, *(u_int32_t *)addr);
break;
case MTIOCHLOCATE:
error = ast_locate(stp, 1, *(u_int32_t *)addr);
break;
default:
error = ENOTTY;
error = ENOTTY;
}
return error;
}
@ -359,41 +397,45 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
static void
aststrategy(struct buf *bp)
{
int32_t lun = UNIT(bp->b_dev);
struct ast_softc *stp = asttab[lun];
int32_t x;
struct ast_softc *stp = bp->b_dev->si_drv1;
int32_t s;
/* if it's a null transfer, return immediatly. */
if (bp->b_bcount == 0) {
bp->b_resid = 0;
biodone(bp);
return;
bp->b_resid = 0;
biodone(bp);
return;
}
if (!(bp->b_flags & B_READ) && stp->flags & F_WRITEPROTECT) {
bp->b_error = EPERM;
bp->b_flags |= B_ERROR;
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;
printf("ast%d: bad request, must be multiple of %d\n",
stp->lun, stp->blksize);
bp->b_error = EIO;
bp->b_flags |= B_ERROR;
biodone(bp);
return;
biodone(bp);
return;
}
/* warn about transfers bigger than the device suggests */
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);
printf("ast%d: WARNING: CTL exceeded %ld>%d\n",
stp->lun, bp->b_bcount, stp->blksize * stp->cap.ctl);
stp->flags |= F_CTL_WARN;
}
}
x = splbio();
ast_total += bp->b_bcount;
s = splbio();
bufq_insert_tail(&stp->buf_queue, bp);
ast_start(stp);
splx(x);
splx(s);
}
static void
@ -404,16 +446,28 @@ ast_start(struct ast_softc *stp)
int8_t ccb[16];
if (!bp)
return;
return;
bzero(ccb, sizeof(ccb));
if (bp->b_flags & B_READ) {
ccb[0] = ATAPI_READ;
if (!ast_buffermode) {
atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
ast_buffermode = 1;
}
}
else {
ccb[0] = ATAPI_WRITE;
if (!ast_buffermode) {
atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
ast_buffermode = 1;
}
}
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;
@ -430,75 +484,174 @@ ast_done(struct atapi_request *request)
{
struct buf *bp = request->bp;
struct ast_softc *stp = request->driver;
int32_t error = request->result;
devstat_end_transaction(&stp->stats, request->donecount,
DEVSTAT_TAG_NONE,
(bp->b_flags&B_READ) ? DEVSTAT_READ:DEVSTAT_WRITE);
if (request->result) {
bp->b_error = atapi_error(request->device, request->result);
bp->b_flags |= B_ERROR;
if (error) {
bp->b_error = atapi_error(request->device, error);
bp->b_flags |= B_ERROR;
}
else
else {
if (!(bp->b_flags & B_READ))
stp->flags |= F_DATA_WRITTEN;
bp->b_resid = request->bytecount;
ast_total += request->donecount;
}
devstat_end_transaction_buf(&stp->stats, bp);
biodone(bp);
ast_start(stp);
}
static int32_t
ast_space_cmd(struct ast_softc *stp, u_int8_t function, u_int32_t count)
ast_mode_sense(struct ast_softc *stp, u_int8_t page,
void *pagebuf, int32_t pagesize)
{
int8_t ccb[16] = { ATAPI_TAPE_SPACE_CMD, function,
count>>16, count>>8, count, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int8_t ccb[16] = { ATAPI_MODE_SENSE, 0x08, page, pagesize>>8, pagesize,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
error = atapi_immed_cmd(stp->atp, ccb, pagebuf, pagesize, A_READ, 10);
#ifdef AST_DEBUG
atapi_dump("ast: mode sense ", pagebuf, pagesize);
#endif
return atapi_error(stp->atp, error);
}
return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL);
static int32_t
ast_mode_select(struct ast_softc *stp, void *pagebuf, int32_t pagesize)
{
int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, pagesize>>8, pagesize,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#ifdef AST_DEBUG
printf("ast: modeselect pagesize=%d\n", pagesize);
atapi_dump("ast: mode select ", pagebuf, pagesize);
#endif
return atapi_immed_cmd(stp->atp, ccb, pagebuf, pagesize, 0, 10);
}
static int32_t
ast_write_filemark(struct ast_softc *stp, u_int8_t function)
{
int8_t ccb[16] = { ATAPI_TAPE_WEOF, 0, 0, 0, function, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int8_t ccb[16] = { ATAPI_WEOF, 0x01, 0, 0, function, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
if (function) {
if (stp->flags & F_FM_WRITTEN)
stp->flags &= ~F_DATA_WRITTEN;
else
stp->flags |= F_FM_WRITTEN;
ast_buffermode = 0;
if (stp->flags & F_ONSTREAM)
ccb[4] = 0x00; /* only flush buffers supported */
else {
if (function) {
if (stp->flags & F_FM_WRITTEN)
stp->flags &= ~F_DATA_WRITTEN;
else
stp->flags |= F_FM_WRITTEN;
}
}
return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL);
error = atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
if (error)
return atapi_error(stp->atp, error);
return atapi_error(stp->atp, atapi_wait_ready(stp->atp, 5*60));
}
static int32_t
ast_read_position(struct ast_softc *stp, int32_t hard,
struct ast_readposition *position)
{
int8_t ccb[16] = { ATAPI_READ_POSITION, (hard ? 0x01 : 0), 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
error = atapi_immed_cmd(stp->atp, ccb, position,
sizeof(struct ast_readposition), A_READ, 10);
#ifdef AST_DEBUG
printf("ast%d: BOP=%d EOP=%d host=%ld tape=%ld in buf=%d error=%02x\n",
stp->lun, position->bop, position->eop, ntohl(position->host),
ntohl(position->tape), position->blks_in_buf, error);
#endif
return atapi_error(stp->atp, error);
}
static int32_t
ast_space(struct ast_softc *stp, u_int8_t function, u_int32_t count)
{
int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
ast_buffermode = 0;
return atapi_error(stp->atp,
atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 60*60));
}
static int32_t
ast_locate(struct ast_softc *stp, int32_t hard, int32_t pos)
{
int8_t ccb[16] = { ATAPI_LOCATE, 0x01 | (hard ? 0x4 : 0), 0,
pos>>24, pos>>16, pos>>8, pos,
0, 0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
ast_buffermode = 0;
error = atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
if (error)
return atapi_error(stp->atp, error);
return atapi_error(stp->atp, atapi_wait_ready(stp->atp, 60*60));
}
static int32_t
ast_prevent_allow(struct ast_softc *stp, int32_t lock)
{
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_error(stp->atp, atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0,30));
}
static int32_t
ast_load_unload(struct ast_softc *stp, u_int8_t function)
{
int8_t ccb[16] = { ATAPI_TAPE_LOAD_UNLOAD, 0, 0, 0, function, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL);
}
static int32_t
ast_erase(struct ast_softc *stp)
{
int8_t ccb[16] = { ATAPI_START_STOP, 0x01, 0, 0, function, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
int8_t ccb[16] = { ATAPI_TAPE_ERASE, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
if ((error = ast_rewind(stp)))
return error;
return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL);
ast_buffermode = 0;
if ((function & SS_EJECT) && !stp->cap.eject)
return 0;
error = atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
if (error)
return atapi_error(stp->atp, error);
tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz);
if (function == SS_EJECT)
return 0;
return atapi_error(stp->atp, atapi_wait_ready(stp->atp, 60*60));
}
static int32_t
ast_rewind(struct ast_softc *stp)
{
int8_t ccb[16] = { ATAPI_TAPE_REWIND, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int8_t ccb[16] = { ATAPI_REWIND, 0x01, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL);
ast_buffermode = 0;
error = atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 10);
if (error)
return atapi_error(stp->atp, error);
return atapi_error(stp->atp, atapi_wait_ready(stp->atp, 60*60));
}
static int32_t
ast_erase(struct ast_softc *stp)
{
int8_t ccb[16] = { ATAPI_ERASE, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
int32_t error;
if ((error = ast_rewind(stp)))
return error;
ast_buffermode = 0;
return atapi_error(stp->atp,
atapi_immed_cmd(stp->atp, ccb, NULL, 0, 0, 60*60));
}
static void
@ -507,10 +660,10 @@ ast_drvinit(void *unused)
static int32_t ast_devsw_installed = 0;
if (!ast_devsw_installed) {
if (!ast_cdevsw.d_maxio)
ast_cdevsw.d_maxio = 254 * DEV_BSIZE;
cdevsw_add(&ast_cdevsw);
ast_devsw_installed = 1;
if (!ast_cdevsw.d_maxio)
ast_cdevsw.d_maxio = 254 * DEV_BSIZE;
cdevsw_add(&ast_cdevsw);
ast_devsw_installed = 1;
}
}

View File

@ -28,23 +28,25 @@
* $FreeBSD$
*/
/* 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 */
/* mode page data header */
u_int8_t data_length; /* total length of data */
u_int8_t medium_type; /* medium type (if any) */
u_int8_t reserved :4;
u_int8_t mode :3; /* buffering mode */
u_int8_t write_protect :1; /* media is writeprotected */
u_int8_t blk_desc_len; /* block Descriptor Length */
/* capabilities page */
u_int8_t page_code :6;
#define ATAPI_TAPE_CAP_PAGE 0x2a
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x12 */
u_int8_t reserved2;
u_int8_t reserved3;
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 */
@ -52,38 +54,109 @@ struct ast_cappage {
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 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 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 blk32k :1; /* supports 32kb block size */
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;
};
/* ATAPI OnStream ADR data transfer mode page (ADR unique) */
struct ast_transferpage {
/* mode page data 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 blk_desc_len; /* block Descriptor Length */
/* data transfer page */
u_int8_t page_code :6;
#define ATAPI_TAPE_TRANSFER_PAGE 0x30
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x02 */
u_int8_t reserved2;
u_int8_t read32k :1; /* 32k block size (data only) */
u_int8_t read32k5 :1; /* 32.5k block size (data & AUX) */
u_int8_t reserved3_23 :2;
u_int8_t write32k :1; /* 32k block size (data only) */
u_int8_t write32k5 :1; /* 32.5k block size (data & AUX) */
u_int8_t reserved3_6 :1;
u_int8_t streaming :1; /* streaming mode enable */
};
/* ATAPI OnStream ADR vendor identification mode page (ADR unique) */
struct ast_identifypage {
/* mode page data 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 blk_desc_len; /* block Descriptor Length */
/* data transfer page */
u_int8_t page_code :6;
#define ATAPI_TAPE_IDENTIFY_PAGE 0x36
u_int8_t reserved0_6 :1;
u_int8_t ps :1; /* parameters saveable */
u_int8_t page_length; /* page Length == 0x06 */
u_int8_t ident[4]; /* host id string */
u_int8_t reserved6;
u_int8_t reserved7;
};
/* ATAPI read position structure */
struct ast_readposition {
u_int8_t reserved0_05 :6;
u_int8_t eop :1; /* end of partition */
u_int8_t bop :1; /* beginning of partition */
u_int8_t reserved1;
u_int8_t reserved2;
u_int8_t reserved3;
u_int32_t host; /* frame address in buffer */
u_int32_t tape; /* frame address on tape */
u_int8_t reserved12;
u_int8_t reserved13;
u_int8_t reserved14;
u_int8_t blks_in_buf; /* blocks in buffer */
u_int8_t reserved16;
u_int8_t reserved17;
u_int8_t reserved18;
u_int8_t reserved19;
};
struct ast_softc {
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
struct atapi_softc *atp; /* controller structure */
int32_t lun; /* logical device unit */
int32_t flags; /* device state flags */
#define F_OPEN 0x0001 /* the device is opened */
#define F_CTL_WARN 0x0002 /* warned about CTL wrong? */
#define F_WRITEPROTECT 0x0004 /* media is writeprotected */
#define F_DATA_WRITTEN 0x0010 /* data has been written */
#define F_FM_WRITTEN 0x0020 /* filemark has been written */
#define F_ONSTREAM 0x0100 /* OnStream ADR device */
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 buf_queue_head buf_queue; /* queue of i/o requests */
struct atapi_params *param; /* drive parameters table */
struct ast_cappage cap; /* capabilities page info */
struct devstat stats; /* devstat entry */
};