diff options
author | sos <sos@FreeBSD.org> | 2004-03-15 12:03:48 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2004-03-15 12:03:48 +0000 |
commit | dc99d6d221faeb25117b57ba2bcdb8aca0e539a0 (patch) | |
tree | 31a9d6667678aa55b9fa75ad9df738b13820030f /sys/dev/ata | |
parent | a745e2bbf146ec1885fcb077a44b9983794dac64 (diff) | |
download | FreeBSD-src-dc99d6d221faeb25117b57ba2bcdb8aca0e539a0.zip FreeBSD-src-dc99d6d221faeb25117b57ba2bcdb8aca0e539a0.tar.gz |
Add support for detaching PCI controllers.
This adds support for cardbus ATA/SATA controllers. I get roughly the
same transfer speeds as on true PCI controllers. Nice to be able to add
a couble of "real" disks to a laptop :)
Diffstat (limited to 'sys/dev/ata')
-rw-r--r-- | sys/dev/ata/ata-all.c | 19 | ||||
-rw-r--r-- | sys/dev/ata/ata-all.h | 2 | ||||
-rw-r--r-- | sys/dev/ata/ata-chipset.c | 92 | ||||
-rw-r--r-- | sys/dev/ata/ata-lowlevel.c | 4 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.c | 68 | ||||
-rw-r--r-- | sys/dev/ata/ata-pci.h | 8 | ||||
-rw-r--r-- | sys/dev/ata/ata-queue.c | 33 |
7 files changed, 129 insertions, 97 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index dd369b0..8fff15a 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -69,7 +69,6 @@ static struct cdevsw ata_cdevsw = { static void ata_shutdown(void *, int); static int ata_getparam(struct ata_device *, u_int8_t); static void ata_identify_devices(struct ata_channel *); -static void ata_fail_requests(struct ata_channel *ch,struct ata_device *device); static void ata_boot_attach(void); static void bswap(int8_t *, int); static void btrim(int8_t *, int); @@ -710,24 +709,6 @@ ata_identify_devices(struct ata_channel *ch) } } -static void -ata_fail_requests(struct ata_channel *ch, struct ata_device *device) -{ - struct ata_request *request; - - mtx_lock(&ch->queue_mtx); - while ((request = TAILQ_FIRST(&ch->ata_queue))) { - if (device == NULL || request->device == device) { - TAILQ_REMOVE(&ch->ata_queue, request, chain); - request->result = ENXIO; - mtx_unlock(&ch->queue_mtx); - ata_finish(request); - mtx_lock(&ch->queue_mtx); - } - } - mtx_unlock(&ch->queue_mtx); -} - static void ata_boot_attach(void) { diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index da86b4e..ad0203c 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -332,6 +332,7 @@ struct ata_channel { #define ATA_ATAPI_DMA_RO 0x08 #define ATA_48BIT_ACTIVE 0x10 #define ATA_IMMEDIATE_MODE 0x20 +#define ATA_HWGONE 0x40 struct ata_device device[2]; /* devices on this channel */ #define MASTER 0x00 @@ -396,6 +397,7 @@ int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t featur int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout); void ata_queue_request(struct ata_request *request); void ata_finish(struct ata_request *request); +void ata_fail_requests(struct ata_channel *ch, struct ata_device *device); char *ata_cmd2str(struct ata_request *request); /* ata-lowlevel.c: */ diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 9621a10..deac794 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -512,7 +512,7 @@ ata_cyrix_chipinit(device_t dev) if (ata_setup_interrupt(dev)) return ENXIO; - if (ctlr->r_io1) + if (ctlr->r_res1) ctlr->setmode = ata_cyrix_setmode; else ctlr->setmode = ata_generic_setmode; @@ -1145,14 +1145,14 @@ ata_promise_chipinit(device_t dev) switch (ctlr->chip->cfg1) { case PRNEW: /* setup clocks */ - ATA_OUTB(ctlr->r_io1, 0x11, ATA_INB(ctlr->r_io1, 0x11) | 0x0a); + ATA_OUTB(ctlr->r_res1, 0x11, ATA_INB(ctlr->r_res1, 0x11) | 0x0a); ctlr->dmainit = ata_promise_new_dmainit; /* FALLTHROUGH */ case PROLD: /* enable burst mode */ - ATA_OUTB(ctlr->r_io1, 0x1f, ATA_INB(ctlr->r_io1, 0x1f) | 0x01); + ATA_OUTB(ctlr->r_res1, 0x1f, ATA_INB(ctlr->r_res1, 0x1f) | 0x01); if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, ata_promise_old_intr, ctlr, &ctlr->handle))) { @@ -1170,21 +1170,23 @@ ata_promise_chipinit(device_t dev) break; case PRMIO: - rid = 0x1c; - if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, - 0, ~0, 1, RF_ACTIVE))) + ctlr->r_type2 = SYS_RES_MEMORY; + ctlr->r_rid2 = 0x1c; + if (!(ctlr->r_res2 = + bus_alloc_resource(dev, ctlr->r_type2, &ctlr->r_rid2, + 0, ~0, 1, RF_ACTIVE))) return ENXIO; ctlr->dmainit = ata_promise_mio_dmainit; ctlr->allocate = ata_promise_mio_allocate; if (ctlr->chip->cfg2 & PRDUAL) { - ctlr->channels = ((ATA_INL(ctlr->r_io2, 0x48) & 0x01) > 0) + - ((ATA_INL(ctlr->r_io2, 0x48) & 0x02) > 0) + 2; + ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x01) > 0) + + ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 2; } else if (ctlr->chip->cfg2 & PRSATA) { - ATA_OUTL(ctlr->r_io2, 0x06c, 0x00ff0033); - ctlr->channels = ((ATA_INL(ctlr->r_io2, 0x48) & 0x02) > 0) + 3; + ATA_OUTL(ctlr->r_res2, 0x06c, 0x00ff0033); + ctlr->channels = ((ATA_INL(ctlr->r_res2, 0x48) & 0x02) > 0) + 3; } else ctlr->channels = 4; @@ -1208,18 +1210,18 @@ ata_promise_mio_allocate(device_t dev, struct ata_channel *ch) int i; for (i = ATA_DATA; i <= ATA_STATUS; i++) { - ch->r_io[i].res = ctlr->r_io2; + ch->r_io[i].res = ctlr->r_res2; ch->r_io[i].offset = 0x200 + (i << 2) + (ch->unit << 7); } - ch->r_io[ATA_ALTSTAT].res = ctlr->r_io2; + ch->r_io[ATA_ALTSTAT].res = ctlr->r_res2; ch->r_io[ATA_ALTSTAT].offset = 0x238 + (ch->unit << 7); - ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMCMD_PORT].offset = 0x260 + (ch->unit << 7); - ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMDTP_PORT].offset = 0x244 + (ch->unit << 7); - ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2; + ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_res2; ch->r_io[ATA_BMDEVSPEC_0].offset = ((ch->unit + 1) << 2); - ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2; + ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; ATA_IDX_OUTL(ch, ATA_BMCMD_PORT, (ATA_IDX_INL(ch, ATA_BMCMD_PORT) & ~0x00003f9f) | @@ -1242,7 +1244,7 @@ ata_promise_old_intr(void *data) for (unit = 0; unit < 2; unit++) { if (!(ch = ctlr->interrupt[unit].argument)) continue; - if (ATA_INL(ctlr->r_io1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) { + if (ATA_INL(ctlr->r_res1, 0x1c) & (ch->unit ? 0x00004000 : 0x00000400)) { if (ch->dma && (ch->dma->flags & ATA_DMA_ACTIVE)) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; @@ -1292,7 +1294,7 @@ ata_promise_mio_intr(void *data) u_int32_t irq_vector; int unit; - irq_vector = ATA_INL(ctlr->r_io2, 0x0040); + irq_vector = ATA_INL(ctlr->r_res2, 0x0040); for (unit = 0; unit < ctlr->channels; unit++) { if (irq_vector & (1 << (unit + 1))) { if ((ch = ctlr->interrupt[unit].argument)) { @@ -1398,9 +1400,9 @@ ata_promise_new_dmastart(struct ata_channel *ch) device_get_softc(device_get_parent(ch->dev)); if (ch->flags & ATA_48BIT_ACTIVE) { - ATA_OUTB(ctlr->r_io1, 0x11, - ATA_INB(ctlr->r_io1, 0x11) | (ch->unit ? 0x08 : 0x02)); - ATA_OUTL(ctlr->r_io1, 0x20, + ATA_OUTB(ctlr->r_res1, 0x11, + ATA_INB(ctlr->r_res1, 0x11) | (ch->unit ? 0x08 : 0x02)); + ATA_OUTL(ctlr->r_res1, 0x20, ((ch->dma->flags & ATA_DMA_READ) ? 0x05000000 : 0x06000000) | (ch->dma->cur_iosize >> 1)); } @@ -1421,9 +1423,9 @@ ata_promise_new_dmastop(struct ata_channel *ch) int error; if (ch->flags & ATA_48BIT_ACTIVE) { - ATA_OUTB(ctlr->r_io1, 0x11, - ATA_INB(ctlr->r_io1, 0x11) & ~(ch->unit ? 0x08 : 0x02)); - ATA_OUTL(ctlr->r_io1, 0x20, 0); + ATA_OUTB(ctlr->r_res1, 0x11, + ATA_INB(ctlr->r_res1, 0x11) & ~(ch->unit ? 0x08 : 0x02)); + ATA_OUTL(ctlr->r_res1, 0x20, 0); } error = ATA_IDX_INB(ch, ATA_BMSTAT_PORT); ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, @@ -1630,9 +1632,11 @@ ata_sii_chipinit(device_t dev) return ENXIO; } - rid = 0x24; - if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, - 0, ~0, 1, RF_ACTIVE))) + ctlr->r_type2 = SYS_RES_MEMORY; + ctlr->r_rid2 = 0x24; + if (!(ctlr->r_res2 = + bus_alloc_resource(dev, ctlr->r_type2, &ctlr->r_rid2, + 0, ~0, 1, RF_ACTIVE))) return ENXIO; if (ctlr->chip->cfg2 & SIISETCLK) { @@ -1644,23 +1648,12 @@ ata_sii_chipinit(device_t dev) ctlr->chip->text); } - if (ctlr->chip->cfg2 & SII4CH) - ctlr->channels = 4; - /* enable interrupt as BIOS might not */ pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); - /* setup chipset defaults as BIOS might not */ -#if 0 - pci_write_config(dev, 0xa2, 0x328a, 2); - pci_write_config(dev, 0xa4, 0x328a328a, 4); - pci_write_config(dev, 0xa8, 0x22082208, 4); - pci_write_config(dev, 0xac, 0x40094009, 4); - pci_write_config(dev, 0xe2, 0x328a, 2); - pci_write_config(dev, 0xe4, 0x328a328a, 4); - pci_write_config(dev, 0xe8, 0x22082208, 4); - pci_write_config(dev, 0xec, 0x40094009, 4); -#endif + if (ctlr->chip->cfg2 & SII4CH) + ctlr->channels = 4; + ctlr->allocate = ata_sii_mio_allocate; if (ctlr->chip->max_dma >= ATA_SA150) ctlr->setmode = ata_sata_setmode; @@ -1697,22 +1690,22 @@ ata_sii_mio_allocate(device_t dev, struct ata_channel *ch) int i; for (i = ATA_DATA; i <= ATA_STATUS; i++) { - ch->r_io[i].res = ctlr->r_io2; + ch->r_io[i].res = ctlr->r_res2; ch->r_io[i].offset = 0x80 + i + (unit01 << 6) + (unit10 << 9); } - ch->r_io[ATA_ALTSTAT].res = ctlr->r_io2; + ch->r_io[ATA_ALTSTAT].res = ctlr->r_res2; ch->r_io[ATA_ALTSTAT].offset = 0x8a + (unit01 << 6) + (unit10 << 9); - ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (unit01 << 3) + (unit10 << 9); - ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 9); - ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_io2; + ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2; ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 9); - ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2; + ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_res2; ch->r_io[ATA_BMDEVSPEC_0].offset = 0xa1 + (unit01 << 6) + (unit10 << 9); - ch->r_io[ATA_BMDEVSPEC_1].res = ctlr->r_io2; + ch->r_io[ATA_BMDEVSPEC_1].res = ctlr->r_res2; ch->r_io[ATA_BMDEVSPEC_1].offset = 0x100 + (unit01 << 7) + (unit10 << 9); - ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2; + ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; if (ctlr->chip->max_dma >= ATA_SA150) { ch->flags |= ATA_NO_SLAVE; @@ -1723,7 +1716,6 @@ ata_sii_mio_allocate(device_t dev, struct ata_channel *ch) if (ctlr->chip->cfg2 & SIIBUG) ch->dma->boundary = 8 * 1024; - return 0; } diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index 1bbf5b2..8592e58 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -70,8 +70,8 @@ ata_generic_hw(struct ata_channel *ch) static int ata_transaction(struct ata_request *request) { - /* safety check, device might have been detached FIXME SOS */ - if (!request->device->param) { + /* safetybelt for HW that went away */ + if (!request->device->param || request->device->channel->flags&ATA_HWGONE) { request->result = ENXIO; return ATA_OP_FINISHED; } diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 81013ac..8fab433 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -154,21 +154,9 @@ static int ata_pci_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); - u_int8_t class, subclass; - u_int32_t type, cmd; + u_int32_t cmd; int unit; - /* set up vendor-specific stuff */ - type = pci_get_devid(dev); - class = pci_get_class(dev); - subclass = pci_get_subclass(dev); - cmd = pci_read_config(dev, PCIR_COMMAND, 2); - - if (!(cmd & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN))) { - device_printf(dev, "ATA channel disabled by BIOS\n"); - return 0; - } - /* do chipset specific setups only needed once */ if (ATA_MASTERDEV(dev) || pci_read_config(dev, 0x18, 4) & IOMASK) ctlr->channels = 2; @@ -178,18 +166,19 @@ ata_pci_attach(device_t dev) ctlr->dmainit = ata_pci_dmainit; ctlr->locking = ata_pci_locknoop; -#ifdef __sparc64__ + /* if needed try to enable busmastering */ + cmd = pci_read_config(dev, PCIR_COMMAND, 2); if (!(cmd & PCIM_CMD_BUSMASTEREN)) { pci_write_config(dev, PCIR_COMMAND, cmd | PCIM_CMD_BUSMASTEREN, 2); cmd = pci_read_config(dev, PCIR_COMMAND, 2); } -#endif - /* if busmastering configured get the I/O resource */ - if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { - int rid = ATA_BMADDR_RID; - ctlr->r_io1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, - 0, ~0, 1, RF_ACTIVE); + /* if busmastering mode "stuck" use it */ + if ((cmd & PCIM_CMD_BUSMASTEREN) == PCIM_CMD_BUSMASTEREN) { + ctlr->r_type1 = SYS_RES_IOPORT; + ctlr->r_rid1 = ATA_BMADDR_RID; + ctlr->r_res1 = bus_alloc_resource(dev, ctlr->r_type1, &ctlr->r_rid1, + 0, ~0, 1, RF_ACTIVE); } ctlr->chipinit(dev); @@ -199,9 +188,34 @@ ata_pci_attach(device_t dev) device_add_child(dev, "ata", ATA_MASTERDEV(dev) ? unit : devclass_find_free_unit(ata_devclass, 2)); - return bus_generic_attach(dev); -} + return bus_generic_attach(dev); } +static int +ata_pci_detach(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + struct ata_channel *ch; + int unit; + + /* mark HW as gone, we dont want to issue commands to HW no longer there */ + for (unit = 0; unit < ctlr->channels; unit++) { + if ((ch = ctlr->interrupt[unit].argument)) + ch->flags |= ATA_HWGONE; + } + + bus_generic_detach(dev); + + if (ctlr->r_irq) { + bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle); + bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ctlr->r_irq); + } + if (ctlr->r_res2) + bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); + if (ctlr->r_res1) + bus_release_resource(dev, ctlr->r_type1, ctlr->r_rid1, ctlr->r_res1); + + return 0; +} static int ata_pci_print_child(device_t dev, device_t child) @@ -420,9 +434,9 @@ ata_pci_allocate(device_t dev, struct ata_channel *ch) ch->r_io[ATA_ALTSTAT].offset = 0; ch->r_io[ATA_IDX_ADDR].res = io; - if (ctlr->r_io1) { + if (ctlr->r_res1) { for (i = ATA_BMCMD_PORT; i <= ATA_BMDTP_PORT; i++) { - ch->r_io[i].res = ctlr->r_io1; + ch->r_io[i].res = ctlr->r_res1; ch->r_io[i].offset = (i - ATA_BMCMD_PORT)+(ch->unit * ATA_BMIOSIZE); } @@ -481,6 +495,7 @@ static device_method_t ata_pci_methods[] = { /* device interface */ DEVMETHOD(device_probe, ata_pci_probe), DEVMETHOD(device_attach, ata_pci_attach), + DEVMETHOD(device_detach, ata_pci_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), @@ -514,6 +529,9 @@ ata_pcisub_probe(device_t dev) device_t *children; int count, error, i; + /* take care of green memory */ + bzero(ch, sizeof(struct ata_channel)); + /* find channel number on this controller */ device_get_children(device_get_parent(dev), &children, &count); for (i = 0; i < count; i++) { @@ -528,6 +546,8 @@ ata_pcisub_probe(device_t dev) ch->device[MASTER].setmode = ctlr->setmode; ch->device[SLAVE].setmode = ctlr->setmode; ch->locking = ctlr->locking; + if (ch->reset) + ch->reset(ch); return ata_probe(dev); } diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h index b39ac0c..5d4ec26 100644 --- a/sys/dev/ata/ata-pci.h +++ b/sys/dev/ata/ata-pci.h @@ -40,8 +40,12 @@ struct ata_chip_id { /* structure describing a PCI ATA controller */ struct ata_pci_controller { - struct resource *r_io1; - struct resource *r_io2; + int r_type1; + int r_rid1; + struct resource *r_res1; + int r_type2; + int r_rid2; + struct resource *r_res2; struct resource *r_irq; void *handle; struct ata_chip_id *chip; diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 667bd99..ef6d20f 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -459,6 +459,39 @@ ata_timeout(struct ata_request *request) return; } +void +ata_fail_requests(struct ata_channel *ch, struct ata_device *device) +{ + struct ata_request *request; + + /* fail all requests queued on this channel */ + mtx_lock(&ch->queue_mtx); + while ((request = TAILQ_FIRST(&ch->ata_queue))) { + if (!device || request->device == device) { + TAILQ_REMOVE(&ch->ata_queue, request, chain); + request->result = ENXIO; + if (request->callback) + (request->callback)(request); + else + sema_post(&request->done); + } + } + mtx_unlock(&ch->queue_mtx); + + /* if we have a request "in flight" fail it as well */ + if ((!device || request->device == device) && (request = ch->running)) { + untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); + ATA_UNLOCK_CH(request->device->channel); + request->device->channel->locking(request->device->channel, + ATA_LF_UNLOCK); + request->result = ENXIO; + if (request->callback) + (request->callback)(request); + else + sema_post(&request->done); + } +} + char * ata_cmd2str(struct ata_request *request) { |