diff options
| author | Søren Schmidt <sos@FreeBSD.org> | 1999-09-21 19:50:40 +0000 |
|---|---|---|
| committer | Søren Schmidt <sos@FreeBSD.org> | 1999-09-21 19:50:40 +0000 |
| commit | 3427651043774ff9d605336873d697b1721f94d0 (patch) | |
| tree | bc242236f188422387165dda7b3dd861aaa41d0d /sys | |
| parent | 3a049969b5cfa291d71c5f62d99603123aa9a074 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/dev/ata/ata-all.c | 406 | ||||
| -rw-r--r-- | sys/dev/ata/ata-all.h | 70 | ||||
| -rw-r--r-- | sys/dev/ata/ata-disk.c | 342 | ||||
| -rw-r--r-- | sys/dev/ata/ata-disk.h | 64 | ||||
| -rw-r--r-- | sys/dev/ata/ata-dma.c | 284 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-all.c | 599 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-all.h | 276 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-cd.c | 1437 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-cd.h | 214 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-fd.c | 292 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-fd.h | 59 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-tape.c | 563 | ||||
| -rw-r--r-- | sys/dev/ata/atapi-tape.h | 153 |
13 files changed, 2658 insertions, 2101 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 2c4b41f1583db..abbd8acd38f49 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -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,40 +513,42 @@ 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; } 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; diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 77160af2e91e9..96a333651dad8 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -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 *); - diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 6e10920c875b9..466d16c0705ea 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -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 @@ oops: /* 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 @@ oops: 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 @@ -610,12 +607,39 @@ oops: } 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); } } diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h index 2f017b21941b0..83747c2177b59 100644 --- a/sys/dev/ata/ata-disk.h +++ b/sys/dev/ata/ata-disk.h @@ -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 *); diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 04157008cf0f2..1069b01b9faaf 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -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; - - type = pci_get_devid(scp->dev); + scp->dmatab[(device == ATA_MASTER) ? 0 : 1] = dmatab; - 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); + 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_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) { - printf("ata%d: %s: setting up UDMA2 mode on Promise 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 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; } diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index 45f7087644eba..f7b51dcee342a 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -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 @@ notfound: 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_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, 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); -int32_t + s = splbio(); + + TAILQ_INSERT_HEAD(&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, "atpim", 0); + +#ifdef ATAPI_DEBUG + printf("atapi: phew, got back from tsleep\n"); +#endif + + error = request->result; + free(request, M_DEVBUF); + 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 = 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; + request->timeout = timeout * hz; + request->ccbsize = (atp->atapi_parm->cmdsize) ? 16 : 12; + bcopy(ccb, request->ccb, request->ccbsize); if (callback) { - request->callback = callback; + request->callback = callback; request->bp = bp; request->driver = driver; } - 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_TAIL(&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, "atprq", 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) { + error = request->result; + if (request->callback) { (request->callback)(request); - free(request, M_DEVBUF); - return 0; + error = 0; } - error = request->result; free(request, M_DEVBUF); - if (ccb[0] == ATAPI_REQUEST_SENSE) - return 0; - else - return atapi_error(atp, error); + 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; } - 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); -#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; + 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; - request->result = 0; + request->bytecount = 0; } - TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain); - atp->flags &= ~ATAPI_F_DMA_USED; - wakeup((caddr_t)request); - return ATA_OP_FINISHED; + goto op_finished; } + length = inb(atp->controller->ioaddr + ATA_CYL_LSB); + length |= inb(atp->controller->ioaddr + ATA_CYL_MSB) << 8; +#ifdef ATAPI_DEBUG + printf("atapi_interrupt: length=%d reason=0x%02x\n", length, reason); +#endif + 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); - +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); + printf("atapi_interrupt: error=0x%02x\n", request->result); #endif - - wakeup((caddr_t)request); 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; + + if (cmd == ATAPI_REQUEST_SENSE) + return 0; - switch ((error & 0xf0)) { + 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) */ diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h index f259b87a536c3..6843af3777209 100644 --- a/sys/dev/ata/atapi-all.h +++ b/sys/dev/ata/atapi-all.h @@ -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); diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index ab7a43f5f3acc..4cf3f2092b919 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -30,6 +30,7 @@ #include "ata.h" #include "atapicd.h" +#include "apm.h" #if NATA > 0 && NATAPICD > 0 @@ -47,6 +48,9 @@ #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-cd.h> @@ -78,44 +82,37 @@ static struct cdevsw acd_cdevsw = { /* bmaj */ 31 }; +/* misc defines */ #define NUNIT 16 /* max # of devices */ -#define F_BOPEN 0x0001 /* the block device is opened */ -#define F_MEDIA_CHANGED 0x0002 /* The media have changed since open */ -#define F_LOCKED 0x0004 /* this unit is locked (or should be) */ -#define F_TRACK_PREP 0x0008 /* track should be prep'ed */ -#define F_TRACK_PREPED 0x0010 /* track has been prep'ed */ -#define F_DISK_PREPED 0x0020 /* disk has been prep'ed */ -#define F_WRITTEN 0x0040 /* the medium has been written to */ - -static struct acd_softc *acdtab[NUNIT]; -static int32_t acdnlun = 0; /* number of configured drives */ - +/* prototypes */ int32_t acdattach(struct atapi_softc *); static struct acd_softc *acd_init_lun(struct atapi_softc *, int, struct devstat *); +static void acd_describe(struct acd_softc *); +static void lba2msf(int32_t, u_int8_t *, u_int8_t *, u_int8_t *); +static int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t); static void acd_start(struct acd_softc *); static void acd_done(struct atapi_request *); -static int32_t acd_test_unit_ready (struct acd_softc *); -static int32_t acd_lock_device (struct acd_softc *, int32_t); -static int32_t acd_start_device (struct acd_softc *, int32_t); -static int32_t acd_pause_device (struct acd_softc *, int32_t); -static int32_t acd_mode_sense (struct acd_softc *, u_int8_t, void *, int32_t); -static int32_t acd_mode_select (struct acd_softc *, void *, int32_t); static int32_t acd_read_toc(struct acd_softc *); -static void acd_describe(struct acd_softc *); static int32_t acd_setchan(struct acd_softc *, u_int8_t, u_int8_t, u_int8_t, u_int8_t); -static int32_t acd_eject(struct acd_softc *, int); static void acd_select_slot(struct acd_softc *); static int32_t acd_open_disk(struct acd_softc *, int); static int32_t acd_open_track(struct acd_softc *, struct wormio_prepare_track *); static int32_t acd_close_track(struct acd_softc *); static int32_t acd_close_disk(struct acd_softc *); static int32_t acd_read_track_info(struct acd_softc *, int, struct acd_track_info*); -static int32_t acd_blank_disk(struct acd_softc *); -static void lba2msf(int32_t, u_int8_t *, u_int8_t *, u_int8_t *); -static int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t); +static int32_t acd_eject(struct acd_softc *, int); +static int32_t acd_blank(struct acd_softc *); +static int32_t acd_prevent_allow(struct acd_softc *, int32_t); +static int32_t acd_start_stop(struct acd_softc *, int32_t); +static int32_t acd_pause_resume(struct acd_softc *, int32_t); +static int32_t acd_mode_sense(struct acd_softc *, u_int8_t, void *, int32_t); +static int32_t acd_mode_select(struct acd_softc *, void *, int32_t); static void acd_drvinit(void *); +/* internal vars */ +static int32_t acdnlun = 0; /* number of configured drives */ + int acdattach(struct atapi_softc *atp) { @@ -124,88 +121,89 @@ acdattach(struct atapi_softc *atp) int32_t error, count; if (acdnlun >= NUNIT) { - printf("acd: too many units\n"); - return -1; + printf("acd: too many units\n"); + return -1; } if ((cdp = acd_init_lun(atp, acdnlun, NULL)) == NULL) { - printf("acd: out of memory\n"); - return -1; + printf("acd: out of memory\n"); + return -1; } /* get drive capabilities, some drives needs this repeated */ for (count = 0 ; count < 5 ; count++) { if (!(error = acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE, &cdp->cap, sizeof(cdp->cap)))) - break; + break; } if (error) { free(cdp, M_TEMP); return -1; } - cdp->cap.max_speed = ntohs(cdp->cap.max_speed); + cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed); + cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed); + cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed); + cdp->cap.cur_write_speed = ntohs(cdp->cap.cur_write_speed); cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels); cdp->cap.buf_size = ntohs(cdp->cap.buf_size); - cdp->cap.cur_speed = ntohs(cdp->cap.cur_speed); acd_describe(cdp); /* if this is a changer device, allocate the neeeded lun's */ if (cdp->cap.mech == MST_MECH_CHANGER) { int8_t ccb[16] = { ATAPI_MECH_STATUS, - 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, sizeof(struct changer)>>8, sizeof(struct changer), - 0, 0, 0, 0, 0, 0 }; - - chp = malloc(sizeof(struct changer), M_TEMP, M_NOWAIT); - if (chp == NULL) { - printf("acd: out of memory\n"); - return 0; - } - bzero(chp, sizeof(struct changer)); - error = atapi_queue_cmd(cdp->atp, ccb, chp, sizeof(struct changer), - A_READ, 60, NULL, NULL, NULL); + 0, 0, 0, 0, 0, 0 }; + chp = malloc(sizeof(struct changer), M_TEMP, M_NOWAIT); + if (chp == NULL) { + printf("acd: out of memory\n"); + return 0; + } + bzero(chp, sizeof(struct changer)); + error = atapi_immed_cmd(cdp->atp, ccb, chp, sizeof(struct changer), + A_READ, 60); #ifdef ACD_DEBUG - printf("error=%02x curr=%02x slots=%d len=%d\n", - error, chp->current_slot, chp->slots, htons(chp->table_length)); + printf("error=%02x curr=%02x slots=%d len=%d\n", + error, chp->current_slot, chp->slots, htons(chp->table_length)); #endif - if (!error) { - struct acd_softc *tmpcdp = cdp; + if (!error) { + struct acd_softc *tmpcdp = cdp; int32_t count; int8_t string[16]; - chp->table_length = htons(chp->table_length); - for (count = 0; count < chp->slots && acdnlun < NUNIT; count++) { - if (count > 0) { - tmpcdp = acd_init_lun(atp, acdnlun, cdp->stats); + chp->table_length = htons(chp->table_length); + for (count = 0; count < chp->slots && acdnlun < NUNIT; count++) { + if (count > 0) { + tmpcdp = acd_init_lun(atp, acdnlun, cdp->stats); if (!tmpcdp) { - printf("acd: out of memory\n"); - return -1; - } - } - tmpcdp->slot = count; - tmpcdp->changer_info = chp; - printf("acd%d: changer slot %d %s\n", acdnlun, count, + printf("acd: out of memory\n"); + return -1; + } + } + tmpcdp->slot = count; + tmpcdp->changer_info = chp; + printf("acd%d: changer slot %d %s\n", acdnlun, count, (chp->slot[count].present ? "CD present" : "empty")); - acdtab[acdnlun++] = tmpcdp; - } - if (acdnlun >= NUNIT) { - printf("acd: too many units\n"); - return 0; - } + acdnlun++; + } + if (acdnlun >= NUNIT) { + printf("acd: too many units\n"); + return 0; + } sprintf(string, "acd%d-", cdp->lun); - devstat_add_entry(cdp->stats, string, tmpcdp->lun, DEV_BSIZE, - DEVSTAT_NO_ORDERED_TAGS, - DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, + devstat_add_entry(cdp->stats, string, tmpcdp->lun, DEV_BSIZE, + DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, 0x178); - } + } } else { - acdtab[acdnlun++] = cdp; - devstat_add_entry(cdp->stats, "acd", cdp->lun, DEV_BSIZE, - DEVSTAT_NO_ORDERED_TAGS, - DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, + devstat_add_entry(cdp->stats, "acd", cdp->lun, DEV_BSIZE, + DEVSTAT_NO_ORDERED_TAGS, + DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, 0x178); + acdnlun++; } return 0; } @@ -214,35 +212,40 @@ static struct acd_softc * acd_init_lun(struct atapi_softc *atp, int32_t lun, struct devstat *stats) { struct acd_softc *acd; + dev_t dev; if (!(acd = malloc(sizeof(struct acd_softc), M_TEMP, M_NOWAIT))) - return NULL; + return NULL; bzero(acd, sizeof(struct acd_softc)); bufq_init(&acd->buf_queue); acd->atp = atp; acd->lun = lun; - acd->flags = F_MEDIA_CHANGED; acd->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED); acd->block_size = 2048; acd->refcnt = 0; acd->slot = -1; acd->changer_info = NULL; + acd->atp->flags |= ATAPI_F_MEDIA_CHANGED; if (stats == NULL) { - if (!(acd->stats = malloc(sizeof(struct devstat), + if (!(acd->stats = malloc(sizeof(struct devstat), M_TEMP, M_NOWAIT))) - return NULL; + return NULL; bzero(acd->stats, sizeof(struct devstat)); } else acd->stats = stats; - make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0), - UID_ROOT, GID_OPERATOR, 0644, "racd%da", lun); - make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART), - UID_ROOT, GID_OPERATOR, 0644, "racd%dc", lun); - make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0), - UID_ROOT, GID_OPERATOR, 0644, "acd%da", lun); - make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART), - UID_ROOT, GID_OPERATOR, 0644, "acd%dc", lun); + dev = make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0), + UID_ROOT, GID_OPERATOR, 0644, "racd%da", lun); + dev->si_drv1 = acd; + dev = make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART), + UID_ROOT, GID_OPERATOR, 0644, "racd%dc", lun); + dev->si_drv1 = acd; + dev = make_dev(&acd_cdevsw, dkmakeminor(lun, 0, 0), + UID_ROOT, GID_OPERATOR, 0644, "acd%da", lun); + dev->si_drv1 = acd; + dev = make_dev(&acd_cdevsw, dkmakeminor(lun, 0, RAW_PART), + UID_ROOT, GID_OPERATOR, 0644, "acd%dc", lun); + dev->si_drv1 = acd; return acd; } @@ -257,125 +260,149 @@ acd_describe(struct acd_softc *cdp) bpack(cdp->atp->atapi_parm->model, model_buf, sizeof(model_buf)); bpack(cdp->atp->atapi_parm->revision, revision_buf, sizeof(revision_buf)); printf("acd%d: <%s/%s> CDROM drive at ata%d as %s\n", - cdp->lun, model_buf, revision_buf, - cdp->atp->controller->lun, - (cdp->atp->unit == ATA_MASTER) ? "master" : "slave "); + cdp->lun, model_buf, revision_buf, + cdp->atp->controller->lun, + (cdp->atp->unit == ATA_MASTER) ? "master" : "slave "); - printf("acd%d: drive speed ", cdp->lun); - if (cdp->cap.cur_speed != cdp->cap.max_speed) - printf("%d - ", cdp->cap.cur_speed * 1000 / 1024); - printf("%dKB/sec", cdp->cap.max_speed * 1000 / 1024); + if (cdp->cap.cur_read_speed) { + printf("acd%d: ", cdp->lun); + printf("read %dKB/s", cdp->cap.cur_read_speed * 1000 / 1024); + if (cdp->cap.max_read_speed) + printf(" (%dKB/s)", cdp->cap.max_read_speed * 1000 / 1024); + if ((cdp->cap.cur_write_speed) && + (cdp->cap.write_cdr || cdp->cap.write_cdrw || + cdp->cap.write_dvdr || cdp->cap.write_dvdram)) { + printf(" write %dKB/s", cdp->cap.cur_write_speed * 1000 / 1024); + if (cdp->cap.max_write_speed) + printf(" (%dKB/s)", cdp->cap.max_write_speed * 1000 / 1024); + } + } if (cdp->cap.buf_size) - printf(", %dKB cache", cdp->cap.buf_size); - if (cdp->atp->flags & ATAPI_F_DMA_ENABLED) - printf(", DMA"); - printf("\n"); + printf(", %dKB buffer", cdp->cap.buf_size); + printf(", %s\n", ata_mode2str(cdp->atp->controller->mode[ + (cdp->atp->unit == ATA_MASTER) ? 0 : 1])); printf("acd%d: supported read types:", cdp->lun); comma = 0; if (cdp->cap.read_cdr) { - printf(" CD-R"); comma = 1; + printf(" CD-R"); comma = 1; } if (cdp->cap.read_cdrw) { - printf("%s CD-RW", comma ? "," : ""); comma = 1; + printf("%s CD-RW", comma ? "," : ""); comma = 1; } if (cdp->cap.cd_da) { - printf("%s CD-DA", comma ? "," : ""); comma = 1; + printf("%s CD-DA", comma ? "," : ""); comma = 1; + } + if (cdp->cap.read_dvdrom) { + printf("%s DVD-ROM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.read_dvdr) { + printf("%s DVD-R", comma ? "," : ""); comma = 1; } - if (cdp->cap.method2) - printf("%s packet track", comma ? "," : ""); - if (cdp->cap.write_cdr || cdp->cap.write_cdrw) { - printf("\nacd%d: supported write types:", cdp->lun); - comma = 0; - if (cdp->cap.write_cdr) { - printf(" CD-R" ); comma = 1; + if (cdp->cap.read_dvdram) { + printf("%s DVD-RAM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.read_packet) + printf("%s packet", comma ? "," : ""); + + if (cdp->cap.write_cdr || cdp->cap.write_cdrw || + cdp->cap.write_dvdr || cdp->cap.write_dvdram) { + printf("\nacd%d: supported write types:", cdp->lun); + comma = 0; + if (cdp->cap.write_cdr) { + printf(" CD-R" ); comma = 1; } - if (cdp->cap.write_cdrw) { - printf("%s CD-RW", comma ? "," : ""); comma = 1; + if (cdp->cap.write_cdrw) { + printf("%s CD-RW", comma ? "," : ""); comma = 1; } - if (cdp->cap.test_write) { - printf("%s test write", comma ? "," : ""); comma = 1; + if (cdp->cap.write_dvdr) { + printf("%s DVD-R", comma ? "," : ""); comma = 1; } + if (cdp->cap.write_dvdram) { + printf("%s DVD-RAM", comma ? "," : ""); comma = 1; + } + if (cdp->cap.test_write) + printf("%s test write", comma ? "," : ""); } if (cdp->cap.audio_play) { - printf("\nacd%d: Audio: ", cdp->lun); - if (cdp->cap.audio_play) - printf("play"); - if (cdp->cap.max_vol_levels) - printf(", %d volume levels", cdp->cap.max_vol_levels); + printf("\nacd%d: Audio: ", cdp->lun); + if (cdp->cap.audio_play) + printf("play"); + if (cdp->cap.max_vol_levels) + printf(", %d volume levels", cdp->cap.max_vol_levels); } printf("\nacd%d: Mechanism: ", cdp->lun); switch (cdp->cap.mech) { case MST_MECH_CADDY: - mechanism = "caddy"; break; + mechanism = "caddy"; break; case MST_MECH_TRAY: - mechanism = "tray"; break; + mechanism = "tray"; break; case MST_MECH_POPUP: - mechanism = "popup"; break; + mechanism = "popup"; break; case MST_MECH_CHANGER: - mechanism = "changer"; break; + mechanism = "changer"; break; case MST_MECH_CARTRIDGE: - mechanism = "cartridge"; break; + mechanism = "cartridge"; break; default: - mechanism = 0; break; + mechanism = 0; break; } if (mechanism) - printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism); + printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism); else if (cdp->cap.eject) - printf("ejectable"); + printf("ejectable"); if (cdp->cap.mech != MST_MECH_CHANGER) { - printf("\nacd%d: Medium: ", cdp->lun); - switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { - case MST_CDROM: - printf("CD-ROM "); break; - case MST_CDR: - printf("CD-R "); break; - case MST_CDRW: - printf("CD-RW "); break; - case MST_DOOR_OPEN: - printf("door open"); break; - case MST_NO_DISC: - printf("no/blank disc inside"); break; - case MST_FMT_ERROR: - printf("medium format error"); break; + printf("\nacd%d: Medium: ", cdp->lun); + switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { + case MST_CDROM: + printf("CD-ROM "); break; + case MST_CDR: + printf("CD-R "); break; + case MST_CDRW: + printf("CD-RW "); break; + case MST_DOOR_OPEN: + printf("door open"); break; + case MST_NO_DISC: + printf("no/blank disc inside"); break; + case MST_FMT_ERROR: + printf("medium format error"); break; } - if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH) < MST_TYPE_MASK_HIGH) { - switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) { - case MST_DATA_120: - printf("120mm data disc loaded"); break; - case MST_AUDIO_120: - printf("120mm audio disc loaded"); break; - case MST_COMB_120: - printf("120mm data/audio disc loaded"); break; - case MST_PHOTO_120: - printf("120mm photo disc loaded"); break; - case MST_DATA_80: - printf("80mm data disc loaded"); break; - case MST_AUDIO_80: - printf("80mm audio disc loaded"); break; - case MST_COMB_80: - printf("80mm data/audio disc loaded"); break; - case MST_PHOTO_80: - printf("80mm photo disc loaded"); break; - case MST_FMT_NONE: - switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { - case MST_CDROM: + if ((cdp->cap.medium_type & MST_TYPE_MASK_HIGH) < MST_TYPE_MASK_HIGH) { + switch (cdp->cap.medium_type & MST_TYPE_MASK_LOW) { + case MST_DATA_120: + printf("120mm data disc loaded"); break; + case MST_AUDIO_120: + printf("120mm audio disc loaded"); break; + case MST_COMB_120: + printf("120mm data/audio disc loaded"); break; + case MST_PHOTO_120: + printf("120mm photo disc loaded"); break; + case MST_DATA_80: + printf("80mm data disc loaded"); break; + case MST_AUDIO_80: + printf("80mm audio disc loaded"); break; + case MST_COMB_80: + printf("80mm data/audio disc loaded"); break; + case MST_PHOTO_80: + printf("80mm photo disc loaded"); break; + case MST_FMT_NONE: + switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) { + case MST_CDROM: printf("unknown medium"); break; - case MST_CDR: - case MST_CDRW: - printf("blank medium"); break; - } - break; - default: - printf("unknown type=0x%x", cdp->cap.medium_type); break; - } + case MST_CDR: + case MST_CDRW: + printf("blank medium"); break; + } + break; + default: + printf("unknown type=0x%x", cdp->cap.medium_type); break; + } } } if (cdp->cap.lock) - printf(cdp->cap.locked ? ", locked" : ", unlocked"); + printf(cdp->cap.locked ? ", locked" : ", unlocked"); if (cdp->cap.prevent) - printf(", lock protected"); + printf(", lock protected"); printf("\n"); } @@ -399,333 +426,329 @@ msf2lba(u_int8_t m, u_int8_t s, u_int8_t f) static int acdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p) { - int32_t lun = dkunit(dev); - struct acd_softc *cdp; + struct acd_softc *cdp = dev->si_drv1; - if (lun >= acdnlun || !(cdp = acdtab[lun])) - return ENXIO; + if (cdp->flags & F_WRITING) + return EBUSY; + + if (flags & FWRITE) { + if ((cdp->flags & F_BOPEN) || cdp->refcnt) + return EBUSY; + else + cdp->flags |= F_WRITING; + } - dev->si_bsize_phys = 2048; + dev->si_bsize_phys = 2048; /* XXX SOS */ if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) { - acd_lock_device(cdp, 1); /* prevent user eject */ - cdp->flags |= F_LOCKED; + acd_prevent_allow(cdp, 1); /* prevent user eject */ + cdp->flags |= F_LOCKED; + if (!(flags & O_NONBLOCK) && acd_read_toc(cdp) && !(flags & FWRITE)) + printf("acd%d: read_toc failed\n", cdp->lun); } if (fmt == S_IFBLK) - cdp->flags |= F_BOPEN; + cdp->flags |= F_BOPEN; else - cdp->refcnt++; - - if (!(flags & O_NONBLOCK) && acd_read_toc(cdp) && !(flags & FWRITE)) - printf("acd%d: read_toc failed\n", lun); + cdp->refcnt++; return 0; } static int acdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p) { - int32_t lun = dkunit(dev); - struct acd_softc *cdp; + struct acd_softc *cdp = dev->si_drv1; - if (lun >= acdnlun || !(cdp = acdtab[lun])) - return ENXIO; - if (fmt == S_IFBLK) - cdp->flags &= ~F_BOPEN; + cdp->flags &= ~F_BOPEN; else - cdp->refcnt--; + cdp->refcnt--; /* are we the last open ?? */ if (!(cdp->flags & F_BOPEN) && !cdp->refcnt) { /* yup, do we need to close any written tracks */ - if ((flags & FWRITE) != 0) { - if ((cdp->flags & F_TRACK_PREPED) != 0) { - acd_close_track(cdp); - cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP); - } - } - acd_lock_device(cdp, 0); /* allow the user eject */ + if ((flags & FWRITE) != 0) { + if ((cdp->flags & F_TRACK_PREPED) != 0) { + acd_close_track(cdp); + cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP); + } + } + acd_prevent_allow(cdp, 0); /* allow the user eject */ } - cdp->flags &= ~F_LOCKED; + cdp->flags &= ~(F_LOCKED | F_WRITING); return 0; } static int acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) { - int32_t lun = dkunit(dev); - struct acd_softc *cdp = acdtab[lun]; + struct acd_softc *cdp = dev->si_drv1; int32_t error = 0; - if (cdp->flags & F_MEDIA_CHANGED) - switch (cmd) { - case CDIOCRESET: - acd_test_unit_ready(cdp); + if (cdp->atp->flags & ATAPI_F_MEDIA_CHANGED) + switch (cmd) { + case CDIOCRESET: + atapi_test_ready(cdp->atp); break; - - default: - acd_read_toc(cdp); - acd_lock_device(cdp, 1); - cdp->flags |= F_LOCKED; - break; - } + + default: + acd_read_toc(cdp); + acd_prevent_allow(cdp, 1); + cdp->flags |= F_LOCKED; + break; + } switch (cmd) { case CDIOCRESUME: - error = acd_pause_device(cdp, 1); + error = acd_pause_resume(cdp, 1); break; case CDIOCPAUSE: - error = acd_pause_device(cdp, 0); + error = acd_pause_resume(cdp, 0); break; case CDIOCSTART: - error = acd_start_device(cdp, 1); + error = acd_start_stop(cdp, 1); break; case CDIOCSTOP: - error = acd_start_device(cdp, 0); + error = acd_start_stop(cdp, 0); break; case CDIOCALLOW: - acd_select_slot(cdp); - cdp->flags &= ~F_LOCKED; - error = acd_lock_device(cdp, 0); + acd_select_slot(cdp); + cdp->flags &= ~F_LOCKED; + error = acd_prevent_allow(cdp, 0); break; case CDIOCPREVENT: - acd_select_slot(cdp); - cdp->flags |= F_LOCKED; - error = acd_lock_device(cdp, 1); + acd_select_slot(cdp); + cdp->flags |= F_LOCKED; + error = acd_prevent_allow(cdp, 1); break; case CDIOCRESET: - error = suser(p); - if (error) - break; - error = acd_test_unit_ready(cdp); + error = suser(p); + if (error) + break; + error = atapi_error(cdp->atp, atapi_test_ready(cdp->atp)); break; case CDIOCEJECT: - if ((cdp->flags & F_BOPEN) && cdp->refcnt) { - error = EBUSY; + if ((cdp->flags & F_BOPEN) && cdp->refcnt) { + error = EBUSY; break; } - error = acd_eject(cdp, 0); + error = acd_eject(cdp, 0); break; case CDIOCCLOSE: - if ((cdp->flags & F_BOPEN) && cdp->refcnt) - break; - error = acd_eject(cdp, 1); + if ((cdp->flags & F_BOPEN) && cdp->refcnt) + break; + error = acd_eject(cdp, 1); break; case CDIOREADTOCHEADER: - if (!cdp->toc.hdr.ending_track) { - error = EIO; + if (!cdp->toc.hdr.ending_track) { + error = EIO; break; } - bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr)); - break; + bcopy(&cdp->toc.hdr, addr, sizeof(cdp->toc.hdr)); + break; case CDIOREADTOCENTRYS: { - struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr; - struct toc *toc = &cdp->toc; - struct toc buf; - u_int32_t len; - u_int8_t starting_track = te->starting_track; + struct ioc_read_toc_entry *te = (struct ioc_read_toc_entry *)addr; + struct toc *toc = &cdp->toc; + struct toc buf; + u_int32_t len; + u_int8_t starting_track = te->starting_track; - if (!cdp->toc.hdr.ending_track) { - error = EIO; + if (!cdp->toc.hdr.ending_track) { + error = EIO; break; } - if (te->data_len < sizeof(toc->tab[0]) || + if (te->data_len < sizeof(toc->tab[0]) || (te->data_len % sizeof(toc->tab[0])) != 0 || (te->address_format != CD_MSF_FORMAT && te->address_format != CD_LBA_FORMAT)) { - error = EINVAL; + error = EINVAL; break; } - if (!starting_track) - starting_track = toc->hdr.starting_track; - else if (starting_track == 170) - starting_track = toc->hdr.ending_track + 1; - else if (starting_track < toc->hdr.starting_track || - starting_track > toc->hdr.ending_track + 1) { - error = EINVAL; + if (!starting_track) + starting_track = toc->hdr.starting_track; + else if (starting_track == 170) + starting_track = toc->hdr.ending_track + 1; + else if (starting_track < toc->hdr.starting_track || + starting_track > toc->hdr.ending_track + 1) { + error = EINVAL; break; } - len = ((toc->hdr.ending_track + 1 - starting_track) + 1) * + len = ((toc->hdr.ending_track + 1 - starting_track) + 1) * sizeof(toc->tab[0]); - if (te->data_len < len) - len = te->data_len; - if (len > sizeof(toc->tab)) { - error = EINVAL; + if (te->data_len < len) + len = te->data_len; + if (len > sizeof(toc->tab)) { + error = EINVAL; break; } - if (te->address_format == CD_MSF_FORMAT) { - struct cd_toc_entry *entry; + if (te->address_format == CD_MSF_FORMAT) { + struct cd_toc_entry *entry; - buf = cdp->toc; - toc = &buf; - entry = toc->tab + (toc->hdr.ending_track + 1 - - toc->hdr.starting_track) + 1; - while (--entry >= toc->tab) - lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute, - &entry->addr.msf.second, &entry->addr.msf.frame); - } - error = copyout(toc->tab + starting_track - toc->hdr.starting_track, - te->data, len); + buf = cdp->toc; + toc = &buf; + entry = toc->tab + (toc->hdr.ending_track + 1 - + toc->hdr.starting_track) + 1; + while (--entry >= toc->tab) + lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute, + &entry->addr.msf.second, &entry->addr.msf.frame); + } + error = copyout(toc->tab + starting_track - toc->hdr.starting_track, + te->data, len); break; - } + } case CDIOREADTOCENTRY: { - struct ioc_read_toc_single_entry *te = - (struct ioc_read_toc_single_entry *)addr; - struct toc *toc = &cdp->toc; - struct toc buf; - u_int8_t track = te->track; + struct ioc_read_toc_single_entry *te = + (struct ioc_read_toc_single_entry *)addr; + struct toc *toc = &cdp->toc; + struct toc buf; + u_int8_t track = te->track; - if (!cdp->toc.hdr.ending_track) { - error = EIO; + if (!cdp->toc.hdr.ending_track) { + error = EIO; break; } - if (te->address_format != CD_MSF_FORMAT && + if (te->address_format != CD_MSF_FORMAT && te->address_format != CD_LBA_FORMAT) { - error = EINVAL; + error = EINVAL; break; } - if (!track) - track = toc->hdr.starting_track; - else if (track == 170) - track = toc->hdr.ending_track + 1; - else if (track < toc->hdr.starting_track || - track > toc->hdr.ending_track + 1) { - error = EINVAL; + if (!track) + track = toc->hdr.starting_track; + else if (track == 170) + track = toc->hdr.ending_track + 1; + else if (track < toc->hdr.starting_track || + track > toc->hdr.ending_track + 1) { + error = EINVAL; break; } - if (te->address_format == CD_MSF_FORMAT) { - struct cd_toc_entry *entry; + if (te->address_format == CD_MSF_FORMAT) { + struct cd_toc_entry *entry; - buf = cdp->toc; - toc = &buf; - entry = toc->tab + (track - toc->hdr.starting_track); - lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute, - &entry->addr.msf.second, &entry->addr.msf.frame); - } - bcopy(toc->tab + track - toc->hdr.starting_track, - &te->entry, sizeof(struct cd_toc_entry)); - } + buf = cdp->toc; + toc = &buf; + entry = toc->tab + (track - toc->hdr.starting_track); + lba2msf(ntohl(entry->addr.lba), &entry->addr.msf.minute, + &entry->addr.msf.second, &entry->addr.msf.frame); + } + bcopy(toc->tab + track - toc->hdr.starting_track, + &te->entry, sizeof(struct cd_toc_entry)); + } break; case CDIOCREADSUBCHANNEL: { - struct ioc_read_subchannel *args = - (struct ioc_read_subchannel *)addr; - struct cd_sub_channel_info data; - u_int32_t len = args->data_len; - int32_t abslba, rellba; + struct ioc_read_subchannel *args = + (struct ioc_read_subchannel *)addr; + struct cd_sub_channel_info data; + u_int32_t len = args->data_len; + int32_t abslba, rellba; int8_t ccb[16] = { ATAPI_READ_SUBCHANNEL, 0, 0x40, 1, 0, 0, 0, sizeof(cdp->subchan)>>8, sizeof(cdp->subchan), 0, 0, 0, 0, 0, 0, 0 }; - if (len > sizeof(data) || - len < sizeof(struct cd_sub_channel_header)) { - error = EINVAL; + if (len > sizeof(data) || + len < sizeof(struct cd_sub_channel_header)) { + error = EINVAL; break; } - if ((error = atapi_queue_cmd(cdp->atp, ccb, &cdp->subchan, - sizeof(cdp->subchan), A_READ, 10, - NULL, NULL, NULL))) - break; - -#ifdef ACD_DEBUG - atapi_dump("acd: subchan", &cdp->subchan, sizeof(cdp->subchan)); -#endif - - abslba = cdp->subchan.abslba; - rellba = cdp->subchan.rellba; - if (args->address_format == CD_MSF_FORMAT) { - lba2msf(ntohl(abslba), - &data.what.position.absaddr.msf.minute, - &data.what.position.absaddr.msf.second, - &data.what.position.absaddr.msf.frame); - lba2msf(ntohl(rellba), - &data.what.position.reladdr.msf.minute, - &data.what.position.reladdr.msf.second, - &data.what.position.reladdr.msf.frame); - } else { - data.what.position.absaddr.lba = abslba; - data.what.position.reladdr.lba = rellba; - } - data.header.audio_status = cdp->subchan.audio_status; - data.what.position.control = cdp->subchan.control & 0xf; - data.what.position.addr_type = cdp->subchan.control >> 4; - data.what.position.track_number = cdp->subchan.track; - data.what.position.index_number = cdp->subchan.indx; - error = copyout(&data, args->data, len); + if ((error = atapi_immed_cmd(cdp->atp, ccb, &cdp->subchan, + sizeof(cdp->subchan), A_READ, 10))) { + error = atapi_error(cdp->atp, error); + break; + } + abslba = cdp->subchan.abslba; + rellba = cdp->subchan.rellba; + if (args->address_format == CD_MSF_FORMAT) { + lba2msf(ntohl(abslba), + &data.what.position.absaddr.msf.minute, + &data.what.position.absaddr.msf.second, + &data.what.position.absaddr.msf.frame); + lba2msf(ntohl(rellba), + &data.what.position.reladdr.msf.minute, + &data.what.position.reladdr.msf.second, + &data.what.position.reladdr.msf.frame); + } else { + data.what.position.absaddr.lba = abslba; + data.what.position.reladdr.lba = rellba; + } + data.header.audio_status = cdp->subchan.audio_status; + data.what.position.control = cdp->subchan.control & 0xf; + data.what.position.addr_type = cdp->subchan.control >> 4; + data.what.position.track_number = cdp->subchan.track; + data.what.position.index_number = cdp->subchan.indx; + error = copyout(&data, args->data, len); break; - } + } case CDIOCPLAYMSF: { - struct ioc_play_msf *args = (struct ioc_play_msf *)addr; - int8_t ccb[16] = { ATAPI_PLAY_MSF, 0, 0, + struct ioc_play_msf *args = (struct ioc_play_msf *)addr; + int8_t ccb[16] = { ATAPI_PLAY_MSF, 0, 0, args->start_m, args->start_s, args->start_f, args->end_m, args->end_s, args->end_f, - 0, 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0, 0 }; - error = atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 10, - NULL, NULL,NULL); + error = atapi_error(cdp->atp, + atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10)); break; - } + } case CDIOCPLAYBLOCKS: { - struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr; + struct ioc_play_blocks *args = (struct ioc_play_blocks *)addr; int8_t ccb[16] = { ATAPI_PLAY_BIG, 0, - args->blk>>24, args->blk>>16, args->blk>>8, + args->blk>>24, args->blk>>16, args->blk>>8, args->blk, args->len>>24, args->len>>16, args->len>>8, args->len, - 0, 0, 0, 0, 0, 0 }; + 0, 0, 0, 0, 0, 0 }; - error = atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 10, - NULL, NULL, NULL); + error = atapi_error(cdp->atp, + atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10)); break; - } + } case CDIOCPLAYTRACKS: { - struct ioc_play_track *args = (struct ioc_play_track *)addr; - u_int32_t start, len; - int32_t t1, t2; + struct ioc_play_track *args = (struct ioc_play_track *)addr; + u_int32_t start, len; + int32_t t1, t2; int8_t ccb[16]; - if (!cdp->toc.hdr.ending_track) { - error = EIO; + if (!cdp->toc.hdr.ending_track) { + error = EIO; break; } - if (args->end_track < cdp->toc.hdr.ending_track + 1) - ++args->end_track; - if (args->end_track > cdp->toc.hdr.ending_track + 1) - args->end_track = cdp->toc.hdr.ending_track + 1; - t1 = args->start_track - cdp->toc.hdr.starting_track; - t2 = args->end_track - cdp->toc.hdr.starting_track; - if (t1 < 0 || t2 < 0) { - error = EINVAL; + if (args->end_track < cdp->toc.hdr.ending_track + 1) + ++args->end_track; + if (args->end_track > cdp->toc.hdr.ending_track + 1) + args->end_track = cdp->toc.hdr.ending_track + 1; + t1 = args->start_track - cdp->toc.hdr.starting_track; + t2 = args->end_track - cdp->toc.hdr.starting_track; + if (t1 < 0 || t2 < 0) { + error = EINVAL; break; } - start = ntohl(cdp->toc.tab[t1].addr.lba); - len = ntohl(cdp->toc.tab[t2].addr.lba) - start; + start = ntohl(cdp->toc.tab[t1].addr.lba); + len = ntohl(cdp->toc.tab[t2].addr.lba) - start; bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_PLAY_BIG; @@ -738,10 +761,10 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) ccb[8] = len>>8; ccb[9] = len; - error = atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 10, - NULL, NULL, NULL); + error = atapi_error(cdp->atp, + atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10)); break; - } + } case CDIOCREADAUDIO: { @@ -763,7 +786,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) if (args->address_format == CD_LBA_FORMAT) lba = args->address.lba; else if (args->address_format == CD_MSF_FORMAT) - lba = msf2lba(args->address.msf.minute, + lba = msf2lba(args->address.msf.minute, args->address.msf.second, args->address.msf.frame); else { @@ -774,18 +797,18 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) #ifndef CD_BUFFER_BLOCKS #define CD_BUFFER_BLOCKS 13 #endif - if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, + if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_TEMP,M_NOWAIT))) { - error = ENOMEM; + error = ENOMEM; break; } bzero(ccb, sizeof(ccb)); - while (frames > 0) { - int32_t size; - u_int8_t blocks; + while (frames > 0) { + int32_t size; + u_int8_t blocks; - blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames; - size = blocks * 2352; + blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames; + size = blocks * 2352; ccb[0] = ATAPI_READ_CD; ccb[1] = 4; @@ -795,97 +818,97 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) ccb[5] = lba; ccb[8] = blocks; ccb[9] = 0xf0; - if ((error = atapi_queue_cmd(cdp->atp, ccb, buffer, size, + if ((error = atapi_queue_cmd(cdp->atp, ccb, buffer, size, A_READ, 30, NULL, NULL, NULL))) - break; + break; - if ((error = copyout(buffer, ubuf, size))) - break; - - ubuf += size; - frames -= blocks; - lba += blocks; - } - free(buffer, M_TEMP); + if ((error = copyout(buffer, ubuf, size))) + break; + + ubuf += size; + frames -= blocks; + lba += blocks; + } + free(buffer, M_TEMP); if (args->address_format == CD_LBA_FORMAT) args->address.lba = lba; else if (args->address_format == CD_MSF_FORMAT) - lba2msf(lba, &args->address.msf.minute, + lba2msf(lba, &args->address.msf.minute, &args->address.msf.second, &args->address.msf.frame); - break; - } + break; + } case CDIOCGETVOL: { - struct ioc_vol *arg = (struct ioc_vol *)addr; + struct ioc_vol *arg = (struct ioc_vol *)addr; if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, - &cdp->au, sizeof(cdp->au)))) - break; + &cdp->au, sizeof(cdp->au)))) + break; - if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) { - error = EIO; + if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) { + error = EIO; break; } - arg->vol[0] = cdp->au.port[0].volume; - arg->vol[1] = cdp->au.port[1].volume; - arg->vol[2] = cdp->au.port[2].volume; - arg->vol[3] = cdp->au.port[3].volume; - break; - } + arg->vol[0] = cdp->au.port[0].volume; + arg->vol[1] = cdp->au.port[1].volume; + arg->vol[2] = cdp->au.port[2].volume; + arg->vol[3] = cdp->au.port[3].volume; + break; + } case CDIOCSETVOL: { - struct ioc_vol *arg = (struct ioc_vol *)addr; + struct ioc_vol *arg = (struct ioc_vol *)addr; if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, - &cdp->au, sizeof(cdp->au)))) - break; - if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) { - error = EIO; + &cdp->au, sizeof(cdp->au)))) + break; + if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) { + error = EIO; break; } if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE_MASK, - &cdp->aumask, sizeof(cdp->aumask)))) - break; - cdp->au.data_length = 0; - cdp->au.port[0].channels = CHANNEL_0; - cdp->au.port[1].channels = CHANNEL_1; - cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume; - cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume; - cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume; - cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume; + &cdp->aumask, sizeof(cdp->aumask)))) + break; + cdp->au.data_length = 0; + cdp->au.port[0].channels = CHANNEL_0; + cdp->au.port[1].channels = CHANNEL_1; + cdp->au.port[0].volume = arg->vol[0] & cdp->aumask.port[0].volume; + cdp->au.port[1].volume = arg->vol[1] & cdp->aumask.port[1].volume; + cdp->au.port[2].volume = arg->vol[2] & cdp->aumask.port[2].volume; + cdp->au.port[3].volume = arg->vol[3] & cdp->aumask.port[3].volume; error = acd_mode_select(cdp, &cdp->au, sizeof(cdp->au)); break; - } + } case CDIOCSETPATCH: { - struct ioc_patch *arg = (struct ioc_patch *)addr; + struct ioc_patch *arg = (struct ioc_patch *)addr; - error = acd_setchan(cdp, arg->patch[0], arg->patch[1], - arg->patch[2], arg->patch[3]); + error = acd_setchan(cdp, arg->patch[0], arg->patch[1], + arg->patch[2], arg->patch[3]); break; - } + } case CDIOCSETMONO: - error = acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0,0); + error = acd_setchan(cdp, CHANNEL_0|CHANNEL_1, CHANNEL_0|CHANNEL_1, 0,0); break; case CDIOCSETSTEREO: - error = acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0); + error = acd_setchan(cdp, CHANNEL_0, CHANNEL_1, 0, 0); break; case CDIOCSETMUTE: - error = acd_setchan(cdp, 0, 0, 0, 0); + error = acd_setchan(cdp, 0, 0, 0, 0); break; case CDIOCSETLEFT: - error = acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0); + error = acd_setchan(cdp, CHANNEL_0, CHANNEL_0, 0, 0); break; case CDIOCSETRIGHT: - error = acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0); + error = acd_setchan(cdp, CHANNEL_1, CHANNEL_1, 0, 0); break; case CDRIOCNEXTWRITEABLEADDR: @@ -899,79 +922,79 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) error = EINVAL; break; } - cdp->next_writeable_lba = track_info.next_writeable_addr; + cdp->next_writeable_addr = track_info.next_writeable_addr; *(int*)addr = track_info.next_writeable_addr; } break; case WORMIOCPREPDISK: - { - struct wormio_prepare_disk *w = (struct wormio_prepare_disk *)addr; + { + struct wormio_prepare_disk *w = (struct wormio_prepare_disk *)addr; - if (w->dummy != 0 && w->dummy != 1) - error = EINVAL; - else { - error = acd_open_disk(cdp, w->dummy); - if (error == 0) { - cdp->flags |= F_DISK_PREPED; - cdp->dummy = w->dummy; - cdp->speed = w->speed; - } - } - break; - } + if (w->dummy != 0 && w->dummy != 1) + error = EINVAL; + else { + error = acd_open_disk(cdp, w->dummy); + if (error == 0) { + cdp->flags |= F_DISK_PREPED; + cdp->dummy = w->dummy; + cdp->speed = w->speed; + } + } + break; + } case WORMIOCPREPTRACK: - { - struct wormio_prepare_track *w =(struct wormio_prepare_track *)addr; + { + struct wormio_prepare_track *w =(struct wormio_prepare_track *)addr; - if (w->audio != 0 && w->audio != 1) - error = EINVAL; - else if (w->audio == 0 && w->preemp) - error = EINVAL; - else if ((cdp->flags & F_DISK_PREPED) == 0) { - error = EINVAL; - printf("acd%d: sequence error (PREP_TRACK)\n", cdp->lun); - } else { - cdp->flags |= F_TRACK_PREP; - cdp->preptrack = *w; - } - break; - } + if (w->audio != 0 && w->audio != 1) + error = EINVAL; + else if (w->audio == 0 && w->preemp) + error = EINVAL; + else if ((cdp->flags & F_DISK_PREPED) == 0) { + error = EINVAL; + printf("acd%d: sequence error (PREP_TRACK)\n", cdp->lun); + } else { + cdp->flags |= F_TRACK_PREP; + cdp->preptrack = *w; + } + break; + } case WORMIOCFINISHTRACK: - if ((cdp->flags & F_TRACK_PREPED) != 0) - error = acd_close_track(cdp); - cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP); - break; + if ((cdp->flags & F_TRACK_PREPED) != 0) + error = acd_close_track(cdp); + cdp->flags &= ~(F_TRACK_PREPED | F_TRACK_PREP); + break; case WORMIOCFIXATION: - { - struct wormio_fixation *w = (struct wormio_fixation *)addr; + { + struct wormio_fixation *w = (struct wormio_fixation *)addr; - if ((cdp->flags & F_WRITTEN) == 0) - error = EINVAL; - else if (w->toc_type < 0 /* WORM_TOC_TYPE_AUDIO */ || - w->toc_type > 4 /* WORM_TOC_TYPE_CDI */ ) - error = EINVAL; - else if (w->onp != 0 && w->onp != 1) - error = EINVAL; - else { - /* no fixation needed if dummy write */ - if (cdp->dummy == 0) - error = acd_close_disk(cdp); - cdp->flags &= - ~(F_WRITTEN|F_DISK_PREPED|F_TRACK_PREP|F_TRACK_PREPED); - } - break; - } + if ((cdp->flags & F_WRITTEN) == 0) + error = EINVAL; + else if (w->toc_type < 0 /* WORM_TOC_TYPE_AUDIO */ || + w->toc_type > 4 /* WORM_TOC_TYPE_CDI */ ) + error = EINVAL; + else if (w->onp != 0 && w->onp != 1) + error = EINVAL; + else { + /* no fixation needed if dummy write */ + if (cdp->dummy == 0) + error = acd_close_disk(cdp); + cdp->flags &= + ~(F_WRITTEN|F_DISK_PREPED|F_TRACK_PREP|F_TRACK_PREPED); + } + break; + } case CDRIOCBLANK: - error = acd_blank_disk(cdp); + error = acd_blank(cdp); break; default: - error = ENOTTY; + error = ENOTTY; } return error; } @@ -979,24 +1002,23 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) static void acdstrategy(struct buf *bp) { - int32_t lun = dkunit(bp->b_dev); - struct acd_softc *cdp = acdtab[lun]; - int32_t x; + struct acd_softc *cdp = bp->b_dev->si_drv1; + int32_t s; #ifdef NOTYET /* allow write only on CD-R/RW media */ /* all for now SOS */ if (!(bp->b_flags & B_READ) && !(writeable_media)) { - bp->b_error = EROFS; - bp->b_flags |= B_ERROR; - biodone(bp); - return; + bp->b_error = EROFS; + bp->b_flags |= B_ERROR; + biodone(bp); + return; } #endif if (bp->b_bcount == 0) { - bp->b_resid = 0; - biodone(bp); - return; + bp->b_resid = 0; + biodone(bp); + return; } /* check for valid blocksize SOS */ @@ -1004,10 +1026,10 @@ acdstrategy(struct buf *bp) bp->b_pblkno = bp->b_blkno; bp->b_resid = bp->b_bcount; - x = splbio(); + s = splbio(); bufqdisksort(&cdp->buf_queue, bp); acd_start(cdp); - splx(x); + splx(s); } static void @@ -1018,42 +1040,43 @@ acd_start(struct acd_softc *cdp) int8_t ccb[16]; if (!bp) - return; + return; bufq_remove(&cdp->buf_queue, bp); - /* should reject all queued entries if media have changed. */ - if (cdp->flags & F_MEDIA_CHANGED) { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - return; + /* reject all queued entries if media changed */ + if (cdp->atp->flags & ATAPI_F_MEDIA_CHANGED) { + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return; } + acd_select_slot(cdp); if ((bp->b_flags & B_READ) == B_WRITE) { - if ((cdp->flags & F_TRACK_PREPED) == 0) { - if ((cdp->flags & F_TRACK_PREP) == 0) { - printf("acd%d: sequence error\n", cdp->lun); - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - biodone(bp); - return; - } else { - if (acd_open_track(cdp, &cdp->preptrack) != 0) { - biodone(bp); - return; - } - cdp->flags |= F_TRACK_PREPED; - } - } + if ((cdp->flags & F_TRACK_PREPED) == 0) { + if ((cdp->flags & F_TRACK_PREP) == 0) { + printf("acd%d: sequence error\n", cdp->lun); + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + biodone(bp); + return; + } else { + if (acd_open_track(cdp, &cdp->preptrack) != 0) { + biodone(bp); + return; + } + cdp->flags |= F_TRACK_PREPED; + } + } } bzero(ccb, sizeof(ccb)); if (bp->b_flags & B_READ) { - lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE); + lba = bp->b_blkno / (cdp->block_size / DEV_BSIZE); ccb[0] = ATAPI_READ_BIG; } else { - lba = cdp->next_writeable_lba + (bp->b_offset / cdp->block_size); + lba = cdp->next_writeable_addr + (bp->b_offset / cdp->block_size); ccb[0] = ATAPI_WRITE_BIG; } count = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size; @@ -1072,7 +1095,7 @@ acd_start(struct acd_softc *cdp) devstat_start_transaction(cdp->stats); atapi_queue_cmd(cdp->atp, ccb, bp->b_data, bp->b_bcount, - (bp->b_flags&B_READ)?A_READ : 0, 30, acd_done, cdp, bp); + (bp->b_flags&B_READ)?A_READ : 0, 30, acd_done, cdp, bp); } static void @@ -1080,89 +1103,35 @@ acd_done(struct atapi_request *request) { struct buf *bp = request->bp; struct acd_softc *cdp = request->driver; + int32_t error = request->result; - devstat_end_transaction(cdp->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 & ATAPI_SK_MASK) == ATAPI_SK_UNIT_ATTENTION) { + struct toc buf = cdp->toc; + + acd_read_toc(cdp); + if (memcmp(&buf, &cdp->toc, sizeof(struct toc))) + cdp->atp->flags |= ATAPI_F_MEDIA_CHANGED; + else { + error = atapi_immed_cmd(cdp->atp, request->ccb, request->data, + request->bytecount, request->flags, 30); + if (cdp->flags & F_LOCKED) + acd_prevent_allow(cdp, 1); + } + } + if (error) { + bp->b_error = atapi_error(request->device, error); + bp->b_flags |= B_ERROR; + } else { - bp->b_resid = request->bytecount; - if ((bp->b_flags & B_READ) == B_WRITE) - cdp->flags |= F_WRITTEN; + bp->b_resid = request->bytecount; + if ((bp->b_flags & B_READ) == B_WRITE) + cdp->flags |= F_WRITTEN; } + devstat_end_transaction_buf(&cdp->stats, bp); biodone(bp); acd_start(cdp); } -static int32_t -acd_test_unit_ready(struct acd_softc *cdp) -{ - 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_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); -} - -static int32_t -acd_lock_device(struct acd_softc *cdp, 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(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); -} - -static int32_t -acd_start_device(struct acd_softc *cdp, 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(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); -} - -static int32_t -acd_pause_device(struct acd_softc *cdp, int32_t pause) -{ - int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, 0, 0, 0, 0, pause, - 0, 0, 0, 0, 0, 0, 0 }; - - return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); -} - -static int32_t -acd_mode_sense(struct acd_softc *cdp, u_int8_t page, - void *pagebuf, int32_t pagesize) -{ - int32_t error; - int8_t ccb[16] = { ATAPI_MODE_SENSE, 0, page, 0, 0, 0, 0, - pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; - - error = atapi_queue_cmd(cdp->atp, ccb, pagebuf, pagesize, A_READ, 30, - NULL, NULL, NULL); -#ifdef ACD_DEBUG - atapi_dump("acd: mode sense ", pagebuf, pagesize); -#endif - return error; -} - -static int32_t -acd_mode_select(struct acd_softc *cdp, void *pagebuf, int32_t pagesize) -{ - int8_t ccb[16] = { ATAPI_MODE_SELECT, 0x10, 0, 0, 0, 0, 0, - pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; - -#ifdef ACD_DEBUG - printf("acd: modeselect pagesize=%d\n", pagesize); - atapi_dump("acd: mode select ", pagebuf, pagesize); -#endif - return atapi_queue_cmd(cdp->atp, ccb, pagebuf, pagesize, 0, 30, - NULL, NULL, NULL); -} - static int32_t acd_read_toc(struct acd_softc *cdp) { @@ -1175,71 +1144,64 @@ acd_read_toc(struct acd_softc *cdp) acd_select_slot(cdp); - error = acd_test_unit_ready(cdp); - if (error == EAGAIN) { - cdp->flags |= F_MEDIA_CHANGED; - cdp->flags &= ~(F_WRITTEN | F_TRACK_PREP | F_TRACK_PREPED); - error = acd_test_unit_ready(cdp); + error = atapi_test_ready(cdp->atp); + if ((error & ATAPI_SK_MASK) == ATAPI_SK_UNIT_ATTENTION) { + cdp->flags &= ~(F_WRITTEN | F_TRACK_PREP | F_TRACK_PREPED); + cdp->atp->flags |= ATAPI_F_MEDIA_CHANGED; + error = atapi_test_ready(cdp->atp); } if (error) - return error; + return atapi_error(cdp->atp, error); - cdp->flags &= ~F_MEDIA_CHANGED; + cdp->atp->flags &= ~ATAPI_F_MEDIA_CHANGED; len = sizeof(struct ioc_toc_header) + sizeof(struct cd_toc_entry); ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (atapi_queue_cmd(cdp->atp, ccb, &cdp->toc, len, A_READ, 30, - NULL, NULL, NULL)){ - bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + if (atapi_immed_cmd(cdp->atp, ccb, &cdp->toc, len, A_READ, 30)) { + bzero(&cdp->toc, sizeof(cdp->toc)); + return 0; } ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1; if (ntracks <= 0 || ntracks > MAXTRK) { - bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + bzero(&cdp->toc, sizeof(cdp->toc)); + return 0; } - len = sizeof(struct ioc_toc_header) + ntracks * sizeof(struct cd_toc_entry); + len = sizeof(struct ioc_toc_header)+(ntracks+1)*sizeof(struct cd_toc_entry); bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_READ_TOC; ccb[7] = len>>8; ccb[8] = len; - if (atapi_queue_cmd(cdp->atp, ccb, &cdp->toc, len, A_READ, 30, - NULL, NULL, NULL)){ - bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + if (atapi_immed_cmd(cdp->atp, ccb, &cdp->toc, len, A_READ, 30)) { + bzero(&cdp->toc, sizeof(cdp->toc)); + return 0; } cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len); bzero(ccb, sizeof(ccb)); ccb[0] = ATAPI_READ_CAPACITY; - if (atapi_queue_cmd(cdp->atp, ccb, &cdp->info, sizeof(cdp->info), - A_READ, 30, NULL, NULL, NULL)) - bzero(&cdp->info, sizeof(cdp->info)); - - cdp->toc.tab[ntracks].control = cdp->toc.tab[ntracks - 1].control; - cdp->toc.tab[ntracks].addr_type = cdp->toc.tab[ntracks - 1].addr_type; - cdp->toc.tab[ntracks].track = 170; - cdp->toc.tab[ntracks].addr.lba = cdp->info.volsize; + if (atapi_immed_cmd(cdp->atp, ccb, &cdp->info, sizeof(cdp->info), + A_READ, 30)) + bzero(&cdp->info, sizeof(cdp->info)); cdp->info.volsize = ntohl(cdp->info.volsize); cdp->info.blksize = ntohl(cdp->info.blksize); #ifdef ACD_DEBUG if (cdp->info.volsize && cdp->toc.hdr.ending_track) { - printf("acd%d: ", cdp->lun); - if (cdp->toc.tab[0].control & 4) - printf("%dMB ", cdp->info.volsize / 512); - else - printf("%d:%d audio ", cdp->info.volsize / 75 / 60, - cdp->info.volsize / 75 % 60); - printf("(%d sectors (%d bytes)), %d tracks\n", + printf("acd%d: ", cdp->lun); + if (cdp->toc.tab[0].control & 4) + printf("%dMB ", cdp->info.volsize / 512); + else + printf("%d:%d audio ", cdp->info.volsize / 75 / 60, + cdp->info.volsize / 75 % 60); + printf("(%d sectors (%d bytes)), %d tracks\n", cdp->info.volsize, cdp->info.blksize, - cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1); + cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1); } #endif return 0; @@ -1253,9 +1215,9 @@ acd_setchan(struct acd_softc *cdp, if ((error = acd_mode_sense(cdp, ATAPI_CDROM_AUDIO_PAGE, &cdp->au, sizeof(cdp->au)))) - return error; + return error; if (cdp->au.page_code != ATAPI_CDROM_AUDIO_PAGE) - return EIO; + return EIO; cdp->au.data_length = 0; cdp->au.port[0].channels = c0; cdp->au.port[1].channels = c1; @@ -1264,84 +1226,59 @@ acd_setchan(struct acd_softc *cdp, return acd_mode_select(cdp, &cdp->au, sizeof(cdp->au)); } -static int32_t -acd_eject(struct acd_softc *cdp, int32_t close) -{ - int32_t error; - - acd_select_slot(cdp); - - error = acd_start_device(cdp, 0); - - if (error == EBUSY || error == EAGAIN) { - if (!close) - return 0; - if ((error = acd_start_device(cdp, 3))) - return error; - acd_read_toc(cdp); - acd_lock_device(cdp, 1); - cdp->flags |= F_LOCKED; - return 0; - } - if (error) - return error; - if (close) - return 0; - - tsleep((caddr_t) &lbolt, PRIBIO, "acdej1", 0); - tsleep((caddr_t) &lbolt, PRIBIO, "acdej2", 0); - acd_lock_device(cdp, 0); - cdp->flags &= ~F_LOCKED; - cdp->flags |= F_MEDIA_CHANGED; - cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED); - return acd_start_device(cdp, 2); -} - static void acd_select_slot(struct acd_softc *cdp) { int8_t ccb[16]; if (cdp->slot < 0 || cdp->changer_info->current_slot == cdp->slot) - return; + return; /* unlock (might not be needed but its cheaper than asking) */ - acd_lock_device(cdp, 0); + acd_prevent_allow(cdp, 0); bzero(ccb, sizeof(ccb)); /* unload the current media from player */ ccb[0] = ATAPI_LOAD_UNLOAD; + ccb[1] = 0x01; ccb[4] = 2; ccb[8] = cdp->changer_info->current_slot; - atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); + atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10); + atapi_wait_ready(cdp->atp, 30); /* load the wanted slot */ ccb[0] = ATAPI_LOAD_UNLOAD; + ccb[1] = 0x01; ccb[4] = 3; ccb[8] = cdp->slot; - atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); + atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10); + atapi_wait_ready(cdp->atp, 30); cdp->changer_info->current_slot = cdp->slot; /* lock the media if needed */ if (cdp->flags & F_LOCKED) - acd_lock_device(cdp, 1); + acd_prevent_allow(cdp, 1); } static int32_t acd_open_disk(struct acd_softc *cdp, int32_t test) { - cdp->next_writeable_lba = 0; + cdp->next_writeable_addr = 0; return 0; } static int32_t acd_close_disk(struct acd_softc *cdp) { - int8_t ccb[16] = { ATAPI_CLOSE_TRACK, 0, 0x02, 0, 0, 0, 0, 0, + int8_t ccb[16] = { ATAPI_CLOSE_TRACK, 0x01, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; - return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 600, NULL, NULL, NULL); + error = atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 10); + if (error) + return atapi_error(cdp->atp, error); + return atapi_error(cdp->atp, atapi_wait_ready(cdp->atp, 10*60)); } static int32_t @@ -1352,7 +1289,7 @@ acd_open_track(struct acd_softc *cdp, struct wormio_prepare_track *ptp) if ((error = acd_mode_sense(cdp, ATAPI_CDROM_WRITE_PARAMETERS_PAGE, ¶m, sizeof(param)))) - return error; + return error; param.page_code = 0x05; param.page_length = 0x32; param.test_write = cdp->dummy ? 1 : 0; @@ -1364,51 +1301,55 @@ acd_open_track(struct acd_softc *cdp, struct wormio_prepare_track *ptp) case 0: /* case CDR_DATA: */ cdp->block_size = 2048; - param.track_mode = CDR_TMODE_DATA; - param.data_block_type = CDR_DB_ROM_MODE1; - param.session_format = CDR_SESS_CDROM; + param.track_mode = CDR_TMODE_DATA; + param.data_block_type = CDR_DB_ROM_MODE1; + param.session_format = CDR_SESS_CDROM; break; default: /* case CDR_AUDIO: */ cdp->block_size = 2352; if (ptp->preemp) - param.track_mode = CDR_TMODE_AUDIO; + param.track_mode = CDR_TMODE_AUDIO; else - param.track_mode = 0; - param.data_block_type = CDR_DB_RAW; - param.session_format = CDR_SESS_CDROM; + param.track_mode = 0; + param.data_block_type = CDR_DB_RAW; + param.session_format = CDR_SESS_CDROM; break; /* case CDR_MODE2: - param.track_mode = CDR_TMODE_DATA; - param.data_block_type = CDR_DB_ROM_MODE2; - param.session_format = CDR_SESS_CDROM; + param.track_mode = CDR_TMODE_DATA; + param.data_block_type = CDR_DB_ROM_MODE2; + param.session_format = CDR_SESS_CDROM; break; case CDR_XA1: - param.track_mode = CDR_TMODE_DATA; - param.data_block_type = CDR_DB_XA_MODE1; - param.session_format = CDR_SESS_CDROM_XA; + param.track_mode = CDR_TMODE_DATA; + param.data_block_type = CDR_DB_XA_MODE1; + param.session_format = CDR_SESS_CDROM_XA; break; case CDR_XA2: - param.track_mode = CDR_TMODE_DATA; - param.data_block_type = CDR_DB_XA_MODE2_F1; - param.session_format = CDR_SESS_CDROM_XA; + param.track_mode = CDR_TMODE_DATA; + param.data_block_type = CDR_DB_XA_MODE2_F1; + param.session_format = CDR_SESS_CDROM_XA; break; case CDR_CDI: - param.track_mode = CDR_TMODE_DATA; - param.data_block_type = CDR_DB_XA_MODE2_F1; - param.session_format = CDR_SESS_CDI; + param.track_mode = CDR_TMODE_DATA; + param.data_block_type = CDR_DB_XA_MODE2_F1; + param.session_format = CDR_SESS_CDI; break; } */ } +#if 0 + param.multi_session = CDR_MSES_MULTI; +#else param.multi_session = CDR_MSES_NONE; +#endif param.fp = 0; param.packet_size = 0; return acd_mode_select(cdp, ¶m, sizeof(param)); @@ -1417,26 +1358,41 @@ acd_open_track(struct acd_softc *cdp, struct wormio_prepare_track *ptp) static int32_t acd_close_track(struct acd_softc *cdp) { - int8_t ccb[16] = { ATAPI_SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; + int8_t ccb1[16] = { ATAPI_SYNCHRONIZE_CACHE, 0x02, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + int8_t ccb2[16] = { ATAPI_CLOSE_TRACK, 0x01, 0x01, 0, 0, 0xff, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; + + error = atapi_immed_cmd(cdp->atp, ccb1, NULL, 0, 0, 10); + if (error) + return atapi_error(cdp->atp, error); + + error = atapi_error(cdp->atp, atapi_wait_ready(cdp->atp, 5*60)); + if (error) + return atapi_error(cdp->atp, error); + + error = atapi_immed_cmd(cdp->atp, ccb2, NULL, 0, 0, 10); + if (error) + return atapi_error(cdp->atp, error); - return atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 600, NULL, NULL, NULL); + return atapi_error(cdp->atp, atapi_wait_ready(cdp->atp, 5*60)); } static int32_t acd_read_track_info(struct acd_softc *cdp, int32_t lba, struct acd_track_info *info) { - int32_t error; int8_t ccb[16] = { ATAPI_READ_TRACK_INFO, 1, lba>>24, lba>>16, lba>>8, lba, 0, - sizeof(*info)>>8, sizeof(*info), - 0, 0, 0, 0, 0, 0, 0 }; + sizeof(*info)>>8, sizeof(*info), + 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; - if ((error = atapi_queue_cmd(cdp->atp, ccb, info, sizeof(*info), - A_READ, 30, NULL, NULL, NULL))) - return error; + if ((error = atapi_immed_cmd(cdp->atp, ccb, info, sizeof(*info), + A_READ, 30))) + return atapi_error(cdp->atp, error); info->track_start_addr = ntohl(info->track_start_addr); info->next_writeable_addr = ntohl(info->next_writeable_addr); info->free_blocks = ntohl(info->free_blocks); @@ -1445,17 +1401,105 @@ acd_read_track_info(struct acd_softc *cdp, return 0; } -static int32_t -acd_blank_disk(struct acd_softc *cdp) +static int32_t +acd_eject(struct acd_softc *cdp, int32_t close) { int32_t error; + + acd_select_slot(cdp); + error = acd_start_stop(cdp, 0); + if (((cdp->atp->controller->error&ATAPI_SK_MASK)==ATAPI_SK_NOT_READY) || + ((cdp->atp->controller->error&ATAPI_SK_MASK)==ATAPI_SK_UNIT_ATTENTION)){ + if (!close) + return 0; + if ((error = acd_start_stop(cdp, 3))) + return error; + acd_read_toc(cdp); + acd_prevent_allow(cdp, 1); + cdp->flags |= F_LOCKED; + return 0; + } + if (error) + return error; + if (close) + return 0; + + tsleep((caddr_t) &lbolt, PRIBIO, "acdej1", 0); + tsleep((caddr_t) &lbolt, PRIBIO, "acdej2", 0); + acd_prevent_allow(cdp, 0); + cdp->flags &= ~F_LOCKED; + cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED); + cdp->atp->flags |= ATAPI_F_MEDIA_CHANGED; + return acd_start_stop(cdp, 2); +} + +static int32_t +acd_blank(struct acd_softc *cdp) +{ int8_t ccb[16] = { ATAPI_BLANK, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; - error = atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL); - cdp->flags |= F_MEDIA_CHANGED; + error = atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0, 60*60); cdp->flags &= ~(F_WRITTEN|F_TRACK_PREP|F_TRACK_PREPED); - return error; + cdp->atp->flags |= ATAPI_F_MEDIA_CHANGED; + return atapi_error(cdp->atp, error); +} + +static int32_t +acd_prevent_allow(struct acd_softc *cdp, 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(cdp->atp, atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0,30)); +} + +static int32_t +acd_start_stop(struct acd_softc *cdp, 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_error(cdp->atp, atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0,30)); +} + +static int32_t +acd_pause_resume(struct acd_softc *cdp, int32_t pause) +{ + int8_t ccb[16] = { ATAPI_PAUSE, 0, 0, 0, 0, 0, 0, 0, pause, + 0, 0, 0, 0, 0, 0, 0 }; + + return atapi_error(cdp->atp, atapi_immed_cmd(cdp->atp, ccb, NULL, 0, 0,30)); +} + +static int32_t +acd_mode_sense(struct acd_softc *cdp, u_int8_t page, + void *pagebuf, int32_t pagesize) +{ + int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, page, 0, 0, 0, 0, + pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; + + error = atapi_immed_cmd(cdp->atp, ccb, pagebuf, pagesize, A_READ, 10); +#ifdef ACD_DEBUG + atapi_dump("acd: mode sense ", pagebuf, pagesize); +#endif + return atapi_error(cdp->atp, error); +} + +static int32_t +acd_mode_select(struct acd_softc *cdp, void *pagebuf, int32_t pagesize) +{ + int8_t ccb[16] = { ATAPI_MODE_SELECT_BIG, 0x10, 0, 0, 0, 0, 0, + pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 }; + +#ifdef ACD_DEBUG + printf("acd: modeselect pagesize=%d\n", pagesize); + atapi_dump("acd: mode select ", pagebuf, pagesize); +#endif + return atapi_error(cdp->atp, atapi_immed_cmd(cdp->atp, ccb, + pagebuf, pagesize, 0, 30)); } static void @@ -1464,11 +1508,12 @@ acd_drvinit(void *unused) static int32_t acd_devsw_installed = 0; if (!acd_devsw_installed) { - if (!acd_cdevsw.d_maxio) - acd_cdevsw.d_maxio = 254 * DEV_BSIZE; - cdevsw_add(&acd_cdevsw); - acd_devsw_installed = 1; + if (!acd_cdevsw.d_maxio) + acd_cdevsw.d_maxio = 254 * DEV_BSIZE; + cdevsw_add(&acd_cdevsw); + acd_devsw_installed = 1; } } + SYSINIT(acddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, acd_drvinit, NULL) #endif /* NATA && NATAPICD */ diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 6afa00d10ac8b..8ec06f82ba4ad 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -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) diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 5c98107afe5f3..0220c582c57b3 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -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; - - if (lun >= afdnlun || !(fdp = afdtab[lun])) - return ENXIO; + struct afd_softc *fdp = dev->si_drv1; - 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 */ diff --git a/sys/dev/ata/atapi-fd.h b/sys/dev/ata/atapi-fd.h index 02b60eb610912..a1d30a485fba6 100644 --- a/sys/dev/ata/atapi-fd.h +++ b/sys/dev/ata/atapi-fd.h @@ -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; }; diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index 7c6427f24c0f4..ad41aaf3ce525 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -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; - - if (lun >= astnlun || !(stp = asttab[lun])) - return ENXIO; + struct ast_softc *stp = dev->si_drv1; - /* 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; + error = ast_write_filemark(stp, WF_WRITE); + break; - case MTFSF: + case MTFSF: if (mt->mt_count) - error = ast_space_cmd(stp, SP_FM, mt->mt_count); - break; + error = ast_space(stp, SP_FM, mt->mt_count); + break; - case MTBSF: + case MTBSF: if (mt->mt_count) - error = ast_space_cmd(stp, SP_FM, -(mt->mt_count)); - break; + error = ast_space(stp, SP_FM, -(mt->mt_count)); + break; - case MTREW: - error = ast_rewind(stp); + case MTREW: + error = ast_rewind(stp); break; - case MTOFFL: - if ((error = ast_rewind(stp))) - break; - error = ast_load_unload(stp, !LU_LOAD_MASK); + case MTOFFL: + error = ast_load_unload(stp, SS_EJECT); break; - case MTNOP: + case MTNOP: error = ast_write_filemark(stp, 0); - break; + break; - case MTERASE: - error = ast_erase(stp); + case MTERASE: + error = ast_erase(stp); break; - case MTEOD: - error = ast_space_cmd(stp, SP_EOD, 0); - break; + case MTEOD: + error = ast_space(stp, SP_EOD, 0); + break; - case MTRETENS: - error = ast_load_unload(stp, LU_RETENSION_MASK|LU_LOAD_MASK); + 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; - } - return error; - } + 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_load_unload(struct ast_softc *stp, u_int8_t function) +ast_read_position(struct ast_softc *stp, int32_t hard, + struct ast_readposition *position) { - int8_t ccb[16] = { ATAPI_TAPE_LOAD_UNLOAD, 0, 0, 0, function, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; + 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; - return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 30, NULL, NULL, NULL); + 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_erase(struct ast_softc *stp) +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; - 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; + 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_queue_cmd(stp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL); + 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_START_STOP, 0x01, 0, 0, function, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + int32_t error; + + 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; + + 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; - return atapi_queue_cmd(stp->atp, ccb, NULL, 0, 0, 60*60, NULL, NULL, NULL); + 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; } } diff --git a/sys/dev/ata/atapi-tape.h b/sys/dev/ata/atapi-tape.h index 209f79dec0707..b2b7bd4ca13e6 100644 --- a/sys/dev/ata/atapi-tape.h +++ b/sys/dev/ata/atapi-tape.h @@ -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 */ }; |
