diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c index 88bfc566bf13..05f40c297d0c 100644 --- a/sys/dev/ata/ata-all.c +++ b/sys/dev/ata/ata-all.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include @@ -60,13 +60,13 @@ static d_ioctl_t ata_ioctl; static struct cdevsw ata_cdevsw = { .d_ioctl = ata_ioctl, .d_name = "ata", - .d_maj = 159, }; /* prototypes */ 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); @@ -175,7 +175,6 @@ int ata_detach(device_t dev) { struct ata_channel *ch; - struct ata_request *request; if (!dev || !(ch = device_get_softc(dev)) || !ch->r_irq) return ENXIO; @@ -190,16 +189,9 @@ ata_detach(device_t dev) #endif /* fail outstanding requests on this channel */ - mtx_lock(&ch->queue_mtx); - while ((request = TAILQ_FIRST(&ch->ata_queue))) { - TAILQ_REMOVE(&ch->ata_queue, request, chain); - request->status = ATA_S_ERROR; - mtx_unlock(&ch->queue_mtx); - ata_finish(request); - mtx_lock(&ch->queue_mtx); - } - mtx_unlock(&ch->queue_mtx); + ata_fail_requests(ch, NULL); + /* flush cache and powerdown device */ if (ch->device[MASTER].param) { if (ch->device[MASTER].param->support.command2 & ATA_SUPPORT_FLUSHCACHE) ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0); @@ -237,42 +229,51 @@ ata_reinit(struct ata_channel *ch) return ENXIO; /* reset the HW */ - ata_printf(ch, -1, "resetting devices ..\n"); + if (bootverbose) + ata_printf(ch, -1, "reiniting channel ..\n"); ATA_FORCELOCK_CH(ch, ATA_CONTROL); + ch->flags |= ATA_IMMEDIATE_MODE; ch->running = NULL; devices = ch->devices; ch->hw.reset(ch); ATA_UNLOCK_CH(ch); + if (bootverbose) + ata_printf(ch, -1, "resetting done ..\n"); + /* detach what left the channel during reset */ if ((misdev = devices & ~ch->devices)) { if ((misdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) && ch->device[MASTER].detach) { if (request && (request->device == &ch->device[MASTER])) { request->result = ENXIO; - request->flags |= ATA_R_DONE; if (request->callback) (request->callback)(request); else - wakeup(request); + sema_post(&request->done); } ch->device[MASTER].detach(&ch->device[MASTER]); + ata_fail_requests(ch, &ch->device[MASTER]); + free(ch->device[MASTER].param, M_ATA); + ch->device[MASTER].param = NULL; } if ((misdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) && ch->device[SLAVE].detach) { if (request && (request->device == &ch->device[SLAVE])) { request->result = ENXIO; - request->flags |= ATA_R_DONE; if (request->callback) (request->callback)(request); else - wakeup(request); + sema_post(&request->done); } ch->device[SLAVE].detach(&ch->device[SLAVE]); + ata_fail_requests(ch, &ch->device[SLAVE]); + free(ch->device[SLAVE].param, M_ATA); + ch->device[SLAVE].param = NULL; } } - - /* identify whats present on this channel now */ + + /* identify what is present on the channel now */ ata_identify_devices(ch); /* attach new devices that appeared during reset */ @@ -285,17 +286,26 @@ ata_reinit(struct ata_channel *ch) ch->device[SLAVE].attach(&ch->device[SLAVE]); } - /* restore transfermode on devices */ - if (ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) + /* restore device config and transfermode on devices */ + if (ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) { + if (ch->device[MASTER].config) + ch->device[MASTER].config(&ch->device[MASTER]); ch->device[MASTER].setmode(&ch->device[MASTER],ch->device[MASTER].mode); - if (ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) + } + if (ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) { + if (ch->device[SLAVE].config) + ch->device[SLAVE].config(&ch->device[SLAVE]); ch->device[SLAVE].setmode(&ch->device[SLAVE], ch->device[SLAVE].mode); + } #ifdef DEV_ATAPICAM atapi_cam_reinit_bus(ch); #endif - printf("done\n"); + if (bootverbose) + ata_printf(ch, -1, "device config done ..\n"); + ch->flags &= ~ATA_IMMEDIATE_MODE; + ata_start(ch); return 0; } @@ -543,21 +553,18 @@ ata_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td) static int ata_getparam(struct ata_device *atadev, u_int8_t command) { - struct ata_params *atacap; struct ata_request *request; int error = ENOMEM; - if (atadev->param) - atacap = atadev->param; - else - atacap = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT); - if (atacap) { + if (!atadev->param) + atadev->param = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT); + if (atadev->param) { request = ata_alloc_request(); if (request) { request->device = atadev; request->u.ata.command = command; - request->flags = (ATA_R_READ | ATA_R_QUIET); - request->data = (caddr_t)atacap; + request->flags = (ATA_R_READ | ATA_R_AT_HEAD); + request->data = (caddr_t)atadev->param; request->timeout = 2; request->retries = 3; request->bytecount = sizeof(struct ata_params); @@ -566,18 +573,19 @@ ata_getparam(struct ata_device *atadev, u_int8_t command) ata_queue_request(request); if (!(error = request->result)) break; - request->flags &= ~ATA_R_QUIET; request->retries--; } ata_free_request(request); } - if (!isprint(atacap->model[0]) || !isprint(atacap->model[1])) + if (!isprint(atadev->param->model[0]) || + !isprint(atadev->param->model[1])) error = ENXIO; if (error) { + free(atadev->param, M_ATA); atadev->param = NULL; - free(atacap, M_ATA); } else { + struct ata_params *atacap = atadev->param; #if BYTE_ORDER == BIG_ENDIAN int16_t *ptr; @@ -598,7 +606,6 @@ ata_getparam(struct ata_device *atadev, u_int8_t command) bswap(atacap->serial, sizeof(atacap->serial)); btrim(atacap->serial, sizeof(atacap->serial)); bpack(atacap->serial, atacap->serial, sizeof(atacap->serial)); - atadev->param = atacap; if (bootverbose) ata_prtdev(atadev, "pio=0x%02x wdma=0x%02x udma=0x%02x cable=%spin\n", @@ -694,6 +701,24 @@ 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) { @@ -964,12 +989,12 @@ ata_init(void) printf("ata: malloc of delayed attach hook failed\n"); return; } - ata_delayed_attach->ich_func = (void*)ata_boot_attach; if (config_intrhook_establish(ata_delayed_attach) != 0) { printf("ata: config_intrhook_establish failed\n"); free(ata_delayed_attach, M_TEMP); } + /* Register a handler to flush write caches on shutdown */ if ((EVENTHANDLER_REGISTER(shutdown_post_sync, ata_shutdown, NULL, SHUTDOWN_PRI_DEFAULT)) == NULL) diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h index 18cf77817108..821d17cd0a40 100644 --- a/sys/dev/ata/ata-all.h +++ b/sys/dev/ata/ata-all.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -182,21 +182,25 @@ struct ata_request { u_int32_t donecount; /* bytes transferred */ caddr_t data; /* pointer to data buf */ int flags; -#define ATA_R_DONE 0x0001 -#define ATA_R_CONTROL 0x0002 -#define ATA_R_READ 0x0004 -#define ATA_R_WRITE 0x0008 +#define ATA_R_CONTROL 0x0001 +#define ATA_R_READ 0x0002 +#define ATA_R_WRITE 0x0004 +#define ATA_R_DMA 0x0008 #define ATA_R_ATAPI 0x0010 #define ATA_R_QUIET 0x0020 -#define ATA_R_DMA 0x0040 +#define ATA_R_INTR_SEEN 0x0040 +#define ATA_R_TIMEOUT 0x0080 #define ATA_R_ORDERED 0x0100 #define ATA_R_AT_HEAD 0x0200 #define ATA_R_REQUEUE 0x0400 #define ATA_R_SKIPSTART 0x0800 +#define ATA_R_DEBUG 0x1000 + void (*callback)(struct ata_request *request); + struct sema done; /* request done sema */ int retries; /* retry count */ int timeout; /* timeout for this cmd */ struct callout_handle timeout_handle; /* handle for untimeout */ @@ -206,6 +210,19 @@ struct ata_request { TAILQ_ENTRY(ata_request) chain; /* list management */ }; +/* define this for debugging request processing */ +#if 0 +#define ATA_DEBUG_RQ(request, string) \ + { \ + if (request->flags & ATA_R_DEBUG) \ + ata_prtdev(request->device, "req=%08x %s " string "\n", \ + (u_int)request, ata_cmd2str(request)); \ + } +#else +#define ATA_DEBUG_RQ(request, string) +#endif + + /* structure describing an ATA/ATAPI device */ struct ata_device { struct ata_channel *channel; @@ -218,6 +235,7 @@ struct ata_device { void *softc; /* ptr to softc for device */ void (*attach)(struct ata_device *atadev); void (*detach)(struct ata_device *atadev); + void (*config)(struct ata_device *atadev); void (*start)(struct ata_device *atadev); int flags; #define ATA_D_USE_CHS 0x0001 @@ -289,6 +307,7 @@ struct ata_channel { #define ATA_USE_PC98GEOM 0x04 #define ATA_ATAPI_DMA_RO 0x08 #define ATA_48BIT_ACTIVE 0x10 +#define ATA_IMMEDIATE_MODE 0x20 struct ata_device device[2]; /* devices on this channel */ #define MASTER 0x00 @@ -305,11 +324,12 @@ struct ata_channel { #define ATA_ACTIVE 0x0001 #define ATA_CONTROL 0x0002 + void (*reset)(struct ata_channel *); void (*locking)(struct ata_channel *, int); #define ATA_LF_LOCK 0x0001 #define ATA_LF_UNLOCK 0x0002 - struct mtx queue_mtx; + struct mtx queue_mtx; /* queue lock */ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */ void *running; /* currently running request */ }; diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c index 220c5d059a37..08b172b2ad48 100644 --- a/sys/dev/ata/ata-card.c +++ b/sys/dev/ata/ata-card.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c index 3fa82b2b56be..8f065c144682 100644 --- a/sys/dev/ata/ata-cbus.c +++ b/sys/dev/ata/ata-cbus.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002, 2003 Søren Schmidt + * Copyright (c) 2002 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -144,7 +145,7 @@ ata_cbus_attach(device_t dev) return ENXIO; } - if ((bus_setup_intr(dev, ctlr->irq, INTR_TYPE_BIO | INTR_ENTROPY, + if ((bus_setup_intr(dev, ctlr->irq, ATA_INTR_FLAGS, ata_cbus_intr, ctlr, &ctlr->ih))) { device_printf(dev, "unable to setup interrupt\n"); bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ctlr->io); diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c index 8f07c40be2f4..2aae069d6116 100644 --- a/sys/dev/ata/ata-chipset.c +++ b/sys/dev/ata/ata-chipset.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -99,6 +100,7 @@ static int ata_serverworks_chipinit(device_t); static void ata_serverworks_setmode(struct ata_device *, int); static int ata_sii_chipinit(device_t); static int ata_sii_mio_allocate(device_t, struct ata_channel *); +static void ata_sii_reset(struct ata_channel *); static void ata_sii_intr(void *); static void ata_cmd_intr(void *); static void ata_cmd_old_intr(void *); @@ -1622,6 +1624,7 @@ ata_sii_chipinit(device_t dev) device_printf(dev, "unable to setup interrupt\n"); return ENXIO; } + rid = 0x24; if (!(ctlr->r_io2 = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE))) @@ -1650,10 +1653,8 @@ ata_sii_chipinit(device_t dev) pci_write_config(dev, 0xec, 0x40094009, 4); ctlr->allocate = ata_sii_mio_allocate; - if (ctlr->chip->max_dma >= ATA_SA150) { + if (ctlr->chip->max_dma >= ATA_SA150) ctlr->setmode = ata_sata_setmode; - ctlr->locking = ata_serialize; - } else ctlr->setmode = ata_sii_setmode; } @@ -1699,16 +1700,30 @@ ata_sii_mio_allocate(device_t dev, struct ata_channel *ch) ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (ch->unit << 3); ch->r_io[ATA_BMDEVSPEC_0].res = ctlr->r_io2; ch->r_io[ATA_BMDEVSPEC_0].offset = 0xa1 + (ch->unit << 6); + ch->r_io[ATA_BMDEVSPEC_1].res = ctlr->r_io2; + ch->r_io[ATA_BMDEVSPEC_1].offset = 0x100 + (ch->unit << 7); ch->r_io[ATA_IDX_ADDR].res = ctlr->r_io2; if (ctlr->chip->max_dma >= ATA_SA150) ch->flags |= ATA_NO_SLAVE; + ctlr->dmainit(ch); if (ctlr->chip->cfg2 & SIIBUG) ch->dma->boundary = 8 * 1024; + + ch->reset = ata_sii_reset; + return 0; } +static void +ata_sii_reset(struct ata_channel *ch) +{ + ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_1, 0x00000001); + DELAY(25000); + ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_1, 0x00000000); +} + static void ata_sii_intr(void *data) { @@ -1724,8 +1739,7 @@ ata_sii_intr(void *data) if (ch->dma) { int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; - if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) != - ATA_BMSTAT_INTERRUPT) + if (!(bmstat & ATA_BMSTAT_INTERRUPT)) continue; ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR); DELAY(1); diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index 5c056ff7cb44..99532681c8c4 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ __FBSDID("$FreeBSD$"); /* prototypes */ static void ad_detach(struct ata_device *); +static void ad_config(struct ata_device *); static void ad_start(struct ata_device *); static void ad_done(struct ata_request *); static disk_open_t adopen; @@ -79,7 +81,9 @@ ad_attach(struct ata_device *atadev) atadev->attach = NULL; return; } + atadev->softc = adp; adp->device = atadev; + #ifdef ATA_STATIC_ID adp->lun = (device_get_unit(atadev->channel->dev)<<1)+ATA_DEV(atadev->unit); #else @@ -119,30 +123,16 @@ ad_attach(struct ata_device *atadev) lbasize48 > 268435455) adp->total_secs = lbasize48; - /* enable read caching */ - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); - - /* enable write caching if enabled */ - if (ata_wc) - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); - else - ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); - - /* use multiple sectors/interrupt if device supports it */ - adp->max_iosize = DEV_BSIZE; - if (ad_version(atadev->param->version_major)) { - int secsperint = max(1, min(atadev->param->sectors_intr, 16)); - - if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint)) - adp->max_iosize = secsperint * DEV_BSIZE; - } - /* setup the function ptrs */ atadev->detach = ad_detach; + atadev->config = ad_config; atadev->start = ad_start; - atadev->softc = adp; + + /* config device features */ + ad_config(atadev); /* lets create the disk device */ + adp->max_iosize = DEV_BSIZE; adp->disk.d_open = adopen; adp->disk.d_strategy = adstrategy; adp->disk.d_dump = addump; @@ -191,6 +181,30 @@ ad_detach(struct ata_device *atadev) free(adp, M_AD); } +static void +ad_config(struct ata_device *atadev) +{ + struct ad_softc *adp = atadev->softc; + + /* enable read caching */ + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0); + + /* enable write caching if enabled */ + if (ata_wc) + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0); + else + ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0); + + /* use multiple sectors/interrupt if device supports it */ + adp->max_iosize = DEV_BSIZE; + if (ad_version(atadev->param->version_major)) { + int secsperint = max(1, min(atadev->param->sectors_intr, 16)); + + if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint)) + adp->max_iosize = secsperint * DEV_BSIZE; + } +} + static int adopen(struct disk *dp) { @@ -243,7 +257,7 @@ ad_start(struct ata_device *atadev) request->device = atadev; request->driver = bp; request->callback = ad_done; - request->timeout = 10; + request->timeout = 5; request->retries = 2; request->data = bp->bio_data; request->bytecount = bp->bio_bcount; diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 1637f20714c5..f22cb8a2593b 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c index f4e9ec88213f..dcbd8f1bcf9e 100644 --- a/sys/dev/ata/ata-isa.c +++ b/sys/dev/ata/ata-isa.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c index c3837f80f44b..39eeb9aea0fc 100644 --- a/sys/dev/ata/ata-lowlevel.c +++ b/sys/dev/ata/ata-lowlevel.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include @@ -69,9 +69,17 @@ 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) { + request->result = ENXIO; + return ATA_OP_FINISHED; + } + /* record the request as running */ request->device->channel->running = request; + ATA_DEBUG_RQ(request, "transaction"); + /* disable ATAPI DMA writes if HW doesn't support it */ if ((request->device->channel->flags & ATA_ATAPI_DMA_RO) && ((request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE)) == @@ -83,7 +91,7 @@ ata_transaction(struct ata_request *request) /* ATA PIO data transfer and control commands */ default: { - /* record command direction here as our request might be done later */ + /* record command direction here as our request might be gone later */ int write = (request->flags & ATA_R_WRITE); /* issue command */ @@ -106,6 +114,7 @@ ata_transaction(struct ata_request *request) ata_pio_write(request, request->transfersize); } } + /* return and wait for interrupt */ return ATA_OP_CONTINUES; @@ -136,6 +145,7 @@ ata_transaction(struct ata_request *request) request->result = EIO; break; } + /* return and wait for interrupt */ return ATA_OP_CONTINUES; @@ -294,16 +304,23 @@ ata_interrupt(void *data) return; } + ATA_DEBUG_RQ(request, "interrupt"); + /* ignore interrupt if device is busy */ - if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { + if (!(request->flags & ATA_R_TIMEOUT) && + ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) { DELAY(100); if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ)) return; } + ATA_DEBUG_RQ(request, "interrupt accepted"); + /* clear interrupt and get status */ request->status = ATA_IDX_INB(ch, ATA_STATUS); + request->flags |= ATA_R_INTR_SEEN; + switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_CONTROL)) { /* ATA PIO data transfer and control commands */ @@ -492,6 +509,13 @@ ata_interrupt(void *data) break; } + /* if we timed out, we hold on to the channel, ata_reinit() will unlock */ + if (request->flags & ATA_R_TIMEOUT) { + ata_finish(request); + return; + } + + /* schedule completition for this request */ ata_finish(request); /* unlock the ATA channel for new work */ @@ -529,7 +553,7 @@ ata_reset(struct ata_channel *ch) } } - /* if nothing showed up no need to get any further */ + /* if nothing showed up there is no need to get any further */ /* SOS is that too strong?, we just might loose devices here XXX */ ch->devices = 0; if (!mask) @@ -539,7 +563,11 @@ ata_reset(struct ata_channel *ch) ata_printf(ch, -1, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n", mask, ostat0, ostat1); - /* reset channel */ + /* reset host end of channel (if supported) */ + if (ch->reset) + ch->reset(ch); + + /* reset (both) devices on this channel */ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); DELAY(10); ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET); @@ -617,6 +645,10 @@ ata_reset(struct ata_channel *ch) DELAY(100000); } + /* enable interrupt */ + DELAY(10); + ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT); + if (stat0 & ATA_S_BUSY) mask &= ~0x01; if (stat1 & ATA_S_BUSY) @@ -627,41 +659,6 @@ ata_reset(struct ata_channel *ch) "reset tp2 mask=%02x stat0=%02x stat1=%02x devices=0x%b\n", mask, stat0, stat1, ch->devices, "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); -#if 0 - if (!mask) - return; - - if (mask & 0x01 && ostat0 != 0x00 && - !(ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_MASTER, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); - if (err != 0x58 && lsb == 0xa5) - ch->devices |= ATA_ATA_MASTER; - } - if (mask & 0x02 && ostat1 != 0x00 && - !(ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))) { - ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE); - DELAY(10); - ATA_IDX_OUTB(ch, ATA_ERROR, 0x58); - ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5); - err = ATA_IDX_INB(ch, ATA_ERROR); - lsb = ATA_IDX_INB(ch, ATA_CYL_LSB); - if (bootverbose) - ata_printf(ch, ATA_SLAVE, "ATA err=0x%02x lsb=0x%02x\n", err, lsb); - if (err != 0x58 && lsb == 0xa5) - ch->devices |= ATA_ATA_SLAVE; - } - - if (bootverbose) - ata_printf(ch, -1, "reset tp3 devices=0x%b\n", ch->devices, - "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER"); -#endif } static int @@ -736,9 +733,6 @@ ata_command(struct ata_device *atadev, u_int8_t command, return -1; } - /* enable interrupt */ - ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT); - /* only use 48bit addressing if needed (avoid bugs and overhead) */ if ((lba > 268435455 || count > 256) && atadev->param && atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) { diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c index 027556de2bfb..79a8eda494d6 100644 --- a/sys/dev/ata/ata-pci.c +++ b/sys/dev/ata/ata-pci.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c index 6fd30fcdd587..415d398567a5 100644 --- a/sys/dev/ata/ata-queue.c +++ b/sys/dev/ata/ata-queue.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,8 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include +#include #include #include #include @@ -51,7 +50,6 @@ static char *ata_skey2str(u_int8_t); /* local vars */ static MALLOC_DEFINE(M_ATA_REQ, "ATA request", "ATA request"); -static int atadebug = 0; /* * ATA request related functions @@ -64,42 +62,65 @@ ata_alloc_request(void) request = malloc(sizeof(struct ata_request), M_ATA_REQ, M_NOWAIT | M_ZERO); if (!request) printf("FAILURE - malloc ATA request failed\n"); + sema_init(&request->done, 0, "ATA request done"); return request; } void ata_free_request(struct ata_request *request) { + sema_destroy(&request->done); free(request, M_ATA_REQ); } void ata_queue_request(struct ata_request *request) { - /* mark request as virgin (it might be a reused one) */ + /* mark request as virgin (it might be a retry) */ request->result = request->status = request->error = 0; - request->flags &= ~ATA_R_DONE; - /* put request on the locked queue at the specified location */ - mtx_lock(&request->device->channel->queue_mtx); - if (request->flags & ATA_R_AT_HEAD) - TAILQ_INSERT_HEAD(&request->device->channel->ata_queue, request, chain); - else - TAILQ_INSERT_TAIL(&request->device->channel->ata_queue, request, chain); - mtx_unlock(&request->device->channel->queue_mtx); + if (request->device->channel->flags & ATA_IMMEDIATE_MODE) { - /* should we skip start ? */ - if (!(request->flags & ATA_R_SKIPSTART)) - ata_start(request->device->channel); + // request->flags |= ATA_R_DEBUG; - /* if this was a requeue op callback/sleep already setup */ - if (request->flags & ATA_R_REQUEUE) - return; + /* arm timeout */ + if (!request->timeout_handle.callout && !dumping) { + request->timeout_handle = + timeout((timeout_t*)ata_timeout, request, request->timeout*hz); + } - /* if this is not a callback and we havn't seen DONE yet -> sleep */ - if (!request->callback) { - while (!(request->flags & ATA_R_DONE)) - tsleep(request, PRIBIO, "atareq", hz/10); + /* kick HW into action */ + if (request->device->channel->hw.transaction(request) == + ATA_OP_CONTINUES) { + ATA_DEBUG_RQ(request, "wait for completition"); + sema_wait(&request->done); + } + } + else { + /* put request on the locked queue at the specified location */ + mtx_lock(&request->device->channel->queue_mtx); + if (request->flags & ATA_R_AT_HEAD) + TAILQ_INSERT_HEAD(&request->device->channel->ata_queue, + request, chain); + else + TAILQ_INSERT_TAIL(&request->device->channel->ata_queue, + request, chain); + mtx_unlock(&request->device->channel->queue_mtx); + + ATA_DEBUG_RQ(request, "queued"); + + /* should we skip start ? */ + if (!(request->flags & ATA_R_SKIPSTART)) + ata_start(request->device->channel); + + /* if this is a requeued request callback/sleep is already setup */ + if (request->flags & ATA_R_REQUEUE) + return; + /* if this is not a callback wait until request is completed */ + if (!request->callback) { + ATA_DEBUG_RQ(request, "wait for completition"); + sema_wait(&request->done); + } } } @@ -156,14 +177,16 @@ ata_start(struct ata_channel *ch) { struct ata_request *request; + /* if in immediate mode, just skip start requests (stall queue) */ + if (ch->flags & ATA_IMMEDIATE_MODE) + return; + /* lock the ATA HW for this request */ ch->locking(ch, ATA_LF_LOCK); if (!ATA_LOCK_CH(ch, ATA_ACTIVE)) { return; } -if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n"); - /* if we dont have any work, ask the subdriver(s) */ mtx_lock(&ch->queue_mtx); if (TAILQ_EMPTY(&ch->ata_queue)) { @@ -178,6 +201,8 @@ if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n"); TAILQ_REMOVE(&ch->ata_queue, request, chain); mtx_unlock(&ch->queue_mtx); + ATA_DEBUG_RQ(request, "starting"); + /* arm timeout */ if (!request->timeout_handle.callout && !dumping) { request->timeout_handle = @@ -188,8 +213,6 @@ if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n"); if (ch->hw.transaction(request) == ATA_OP_CONTINUES) return; - /* untimeout request */ - untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); ata_finish(request); } else @@ -202,9 +225,16 @@ if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n"); void ata_finish(struct ata_request *request) { + ATA_DEBUG_RQ(request, "taskqueue completition"); + /* request is done schedule it for completition */ - TASK_INIT(&request->task, 0, ata_completed, request); - taskqueue_enqueue(taskqueue_swi, &request->task); + if (request->device->channel->flags & ATA_IMMEDIATE_MODE) { + ata_completed(request, 0); + } + else { + TASK_INIT(&request->task, 0, ata_completed, request); + taskqueue_enqueue(taskqueue_swi, &request->task); + } } /* current command finished, clean up and return result */ @@ -214,27 +244,60 @@ ata_completed(void *context, int pending) struct ata_request *request = (struct ata_request *)context; struct ata_channel *channel = request->device->channel; - /* untimeout request now we have control back */ - untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); + ATA_DEBUG_RQ(request, "completed called"); - /* do the all the magic for completition evt retry etc etc */ - if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) - ata_prtdev(request->device, "WARNING - %s soft error (ECC corrected)\n", - ata_cmd2str(request)); + if (request->flags & ATA_R_TIMEOUT) { + ata_reinit(channel); - /* if this is a UDMA CRC error, retry request */ - if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) { - if (request->retries--) { - ata_prtdev(request->device, - "WARNING - %s UDMA ICRC error (retrying request)\n", - ata_cmd2str(request)); - request->flags &= ~ATA_R_SKIPSTART; + /* if retries still permit, reinject this request */ + if (request->retries-- > 0) { + request->flags &= ~(ATA_R_TIMEOUT | ATA_R_SKIPSTART); + request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); ata_queue_request(request); return; } + + /* otherwise just finish with error */ + else { + if (!(request->flags & ATA_R_QUIET)) + ata_prtdev(request->device, + "FAILURE - %s timed out\n", + ata_cmd2str(request)); + request->result = EIO; + } + } + else { + /* untimeout request now we have control back */ + untimeout((timeout_t *)ata_timeout, request, request->timeout_handle); + + /* do the all the magic for completition evt retry etc etc */ + if ((request->status & (ATA_S_CORR | ATA_S_ERROR)) == ATA_S_CORR) { + ata_prtdev(request->device, + "WARNING - %s soft error (ECC corrected)", + ata_cmd2str(request)); + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); + } + + /* if this is a UDMA CRC error, retry request */ + if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) { + if (request->retries-- > 0) { + ata_prtdev(request->device, + "WARNING - %s UDMA ICRC error (retrying request)", + ata_cmd2str(request)); + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); + request->flags &= ~ATA_R_SKIPSTART; + ata_queue_request(request); + return; + } + } } switch (request->flags & ATA_R_ATAPI) { + /* ATA errors */ default: if (request->status & ATA_S_ERROR) { @@ -250,8 +313,7 @@ ata_completed(void *context, int pending) if ((request->flags & ATA_R_DMA) && (request->dmastat & ATA_BMSTAT_ERROR)) printf(" dma=0x%02x", request->dmastat); - if (!(request->flags & ATA_R_ATAPI) && - !(request->flags & ATA_R_CONTROL)) + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); printf("\n"); } @@ -306,74 +368,67 @@ ata_completed(void *context, int pending) break; } - request->flags |= ATA_R_DONE; + ATA_DEBUG_RQ(request, "completed callback/wakeup"); + if (request->callback) (request->callback)(request); else - wakeup(request); + sema_post(&request->done); + ata_start(channel); } static void ata_timeout(struct ata_request *request) { - struct ata_channel *ch = request->device->channel; - int quiet = request->flags & ATA_R_QUIET; + ATA_DEBUG_RQ(request, "timeout"); /* clear timeout etc */ request->timeout_handle.callout = NULL; - /* call hw.interrupt to try finish up the command */ - ch->hw.interrupt(request->device->channel); - if (ch->running != request) { - if (!quiet) - ata_prtdev(request->device, - "WARNING - %s recovered from missing interrupt\n", + if (request->flags & ATA_R_INTR_SEEN) { + if (request->retries-- > 0) { + ata_prtdev(request->device, + "WARNING - %s interrupt was seen but timeout fired", ata_cmd2str(request)); - return; - } + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); - /* if this was a DMA request stop the engine to be on the safe side */ - if (request->flags & ATA_R_DMA) { - request->dmastat = - request->device->channel->dma->stop(request->device->channel); + /* re-arm timeout */ + if (!request->timeout_handle.callout && !dumping) { + request->timeout_handle = + timeout((timeout_t*)ata_timeout, request, + request->timeout * hz); + } + } + else { + ata_prtdev(request->device, + "WARNING - %s interrupt was seen but taskqueue stalled", + ata_cmd2str(request)); + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); + ata_completed(request, 0); + } + return; } /* report that we timed out */ - if (request->retries > 0 && !(request->flags & ATA_R_QUIET)) + if (!(request->flags & ATA_R_QUIET)) { ata_prtdev(request->device, - "TIMEOUT - %s retrying (%d retr%s left)\n", + "TIMEOUT - %s retrying (%d retr%s left)", ata_cmd2str(request), request->retries, request->retries == 1 ? "y" : "ies"); - - /* try to adjust HW's attitude towards work */ - ata_reinit(request->device->channel); - - /* if device disappeared nothing more to do here */ - if (!request->device->softc) { - if (!(request->flags & ATA_R_QUIET)) - ata_prtdev(request->device, - "FAILURE - %s device lockup/removed\n", - ata_cmd2str(request)); - return; + if (!(request->flags & (ATA_R_ATAPI | ATA_R_CONTROL))) + printf(" LBA=%llu", (unsigned long long)request->u.ata.lba); + printf("\n"); } - /* if retries still permit, reinject this request */ - if (request->retries-- > 0) { - request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE); - request->flags &= ~ATA_R_SKIPSTART; - ata_queue_request(request); - } - /* otherwise just schedule finish with error */ - else { - if (!(request->flags & ATA_R_QUIET)) - ata_prtdev(request->device, - "FAILURE - %s timed out\n", - ata_cmd2str(request)); - request->status = ATA_S_ERROR; - TASK_INIT(&request->task, 0, ata_completed, request); - taskqueue_enqueue(taskqueue_swi, &request->task); - } + /* now simulate the missing interrupt */ + request->flags |= ATA_R_TIMEOUT; + request->device->channel->hw.interrupt(request->device->channel); + return; } char * @@ -464,7 +519,16 @@ ata_cmd2str(struct ata_request *request) case 0xe7: return ("FLUSHCACHE"); case 0xea: return ("FLUSHCACHE48"); case 0xec: return ("ATA_IDENTIFY"); - case 0xef: return ("SETFEATURES"); + case 0xef: + switch (request->u.ata.feature) { + case 0x03: return ("SETFEATURES SET TRANSFER MODE"); + case 0x02: return ("SETFEATURES ENABLE WCACHE"); + case 0x82: return ("SETFEATURES DISABLE WCACHE"); + case 0xaa: return ("SETFEATURES ENABLE RCACHE"); + case 0x55: return ("SETFEATURES DISABLE RCACHE"); + } + sprintf(buffer, "SETFEATURES 0x%02x", request->u.ata.feature); + return buffer; } } sprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command); diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c index 95df9f609498..323c0caecbe3 100644 --- a/sys/dev/ata/ata-raid.c +++ b/sys/dev/ata/ata-raid.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 - 2003 Søren Schmidt + * Copyright (c) 2000 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -711,7 +712,7 @@ arstrategy(struct bio *bp) return; } - buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO); + buf1 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT | M_ZERO); /* XXX */ buf1->bp.bio_pblkno = lba; if ((buf1->drive = drv) > 0) buf1->bp.bio_pblkno += rdp->offset; @@ -819,7 +820,7 @@ arstrategy(struct bio *bp) ((rdp->flags & AR_F_REBUILDING) && (rdp->disks[buf1->drive].flags & AR_DF_SPARE) && buf1->bp.bio_pblkno < rdp->lock_start)) { - buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); + buf2 = malloc(sizeof(struct ar_buf), M_AR, M_NOWAIT); /* XXX */ bcopy(buf1, buf2, sizeof(struct ar_buf)); buf1->mirror = buf2; buf2->mirror = buf1; @@ -1020,7 +1021,7 @@ ar_rebuild(void *arg) rdp->lock_end = rdp->lock_start + AR_REBUILD_SIZE; rdp->flags |= AR_F_REBUILDING; splx(s); - buffer = malloc(AR_REBUILD_SIZE * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO); + buffer = malloc(AR_REBUILD_SIZE * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO); /* XXX */ /* now go copy entire disk(s) */ while (rdp->lock_end < (rdp->total_sectors / rdp->width)) { diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index ec35c4e64fd8..6cdbaea8d8e6 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include #include #include diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 91f2110bd250..0c0f4ac6ee41 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index f442258e4c18..1a5d6cacae2b 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 - 2003 Søren Schmidt + * Copyright (c) 1998 - 2004 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include