Add new support for locking an ATA channel and use that throughout

the ATA/ATAPI driver. This solves the concurrency problem with
the new GEOM code, and also cuts a good deal of the patch size
in the upcoming MFC.
This commit is contained in:
Søren Schmidt 2002-03-11 21:04:32 +00:00
parent bb7d54e8c7
commit fe86c44885
8 changed files with 70 additions and 49 deletions

View File

@ -218,11 +218,9 @@ ata_detach(device_t dev)
return ENXIO;
/* make sure channel is not busy */
s = splbio();
while (!atomic_cmpset_int(&ch->active, ATA_IDLE, ATA_CONTROL))
tsleep((caddr_t)&s, PRIBIO, "atarel", hz/4);
splx(s);
ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
s = splbio();
#ifdef DEV_ATADISK
if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver)
ad_detach(&ch->device[MASTER], 1);
@ -235,6 +233,7 @@ ata_detach(device_t dev)
if (ch->devices & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver)
atapi_detach(&ch->device[SLAVE]);
#endif
splx(s);
if (ch->device[MASTER].param) {
free(ch->device[MASTER].param, M_ATA);
@ -260,7 +259,7 @@ ata_detach(device_t dev)
ch->r_altio = NULL;
ch->r_bmio = NULL;
ch->r_irq = NULL;
ch->active = ATA_IDLE;
ATA_UNLOCK_CH(ch);
return 0;
}
@ -276,7 +275,7 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
struct ata_cmd *iocmd = (struct ata_cmd *)addr;
struct ata_channel *ch;
device_t device = devclass_get_device(ata_devclass, iocmd->channel);
int error, s;
int error;
if (cmd != IOCATA)
return ENOTTY;
@ -300,12 +299,8 @@ ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
case ATAREINIT:
if (!device || !(ch = device_get_softc(device)))
return ENXIO;
s = splbio();
while (!atomic_cmpset_int(&ch->active, ATA_IDLE, ATA_ACTIVE))
tsleep((caddr_t)&s, PRIBIO, "atarin", hz/4);
ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE);
error = ata_reinit(ch);
splx(s);
return error;
#ifdef DEV_ATADISK
@ -607,10 +602,12 @@ ata_start(struct ata_channel *ch)
#if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST)
struct atapi_request *atapi_request;
#endif
int s;
if (!atomic_cmpset_int(&ch->active, ATA_IDLE, ATA_ACTIVE))
if (!ATA_LOCK_CH(ch, ATA_ACTIVE))
return;
s = splbio();
#ifdef DEV_ATADISK
/* find & call the responsible driver if anything on the ATA queue */
if (TAILQ_EMPTY(&ch->ata_queue)) {
@ -623,8 +620,10 @@ ata_start(struct ata_channel *ch)
TAILQ_REMOVE(&ch->ata_queue, ad_request, chain);
ch->active = ATA_ACTIVE_ATA;
ch->running = ad_request;
if (ad_transfer(ad_request) == ATA_OP_CONTINUES)
if (ad_transfer(ad_request) == ATA_OP_CONTINUES) {
splx(s);
return;
}
}
#endif
@ -640,10 +639,13 @@ ata_start(struct ata_channel *ch)
TAILQ_REMOVE(&ch->atapi_queue, atapi_request, chain);
ch->active = ATA_ACTIVE_ATAPI;
ch->running = atapi_request;
if (atapi_transfer(atapi_request) == ATA_OP_CONTINUES)
if (atapi_transfer(atapi_request) == ATA_OP_CONTINUES) {
splx(s);
return;
}
}
#endif
splx(s);
ch->active = ATA_IDLE;
}
@ -782,7 +784,7 @@ ata_reinit(struct ata_channel *ch)
if (!ch->r_io || !ch->r_altio || !ch->r_irq)
return ENXIO;
ch->active = ATA_CONTROL;
ATA_FORCELOCK_CH(ch, ATA_CONTROL);
ch->running = NULL;
devices = ch->devices;
ata_printf(ch, -1, "resetting devices .. ");
@ -859,7 +861,7 @@ ata_reinit(struct ata_channel *ch)
}
#endif
printf("done\n");
ch->active = ATA_IDLE;
ATA_UNLOCK_CH(ch);
ata_start(ch);
return 0;
}
@ -1037,7 +1039,7 @@ ata_command(struct ata_device *atadev, u_int8_t command,
if (atadev->channel->flags & ATA_QUEUED)
ATA_OUTB(atadev->channel->r_altio, ATA_ALTSTAT, ATA_A_4BIT);
if (tsleep((caddr_t)atadev->channel, PRIBIO, "atacmd", 10 * hz) != 0) {
if (tsleep((caddr_t)atadev->channel, PRIBIO, "atacmd", 10 * hz)) {
ata_prtdev(atadev, "timeout waiting for interrupt\n");
atadev->channel->active &= ~ATA_WAIT_INTR;
error = -1;
@ -1086,10 +1088,6 @@ static void
ata_change_mode(struct ata_device *atadev, int mode)
{
int umode, wmode, pmode;
int s = splbio();
while (!atomic_cmpset_int(&atadev->channel->active, ATA_IDLE, ATA_ACTIVE))
tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4);
umode = ata_umode(atadev->param);
wmode = ata_wmode(atadev->param);
@ -1111,11 +1109,11 @@ ata_change_mode(struct ata_device *atadev, int mode)
umode = -1;
wmode = -1;
}
ata_dmainit(atadev->channel, atadev->unit, pmode, wmode, umode);
atadev->channel->active = ATA_IDLE;
ATA_SLEEPLOCK_CH(atadev->channel, ATA_ACTIVE);
ata_dmainit(atadev->channel, atadev->unit, pmode, wmode, umode);
ATA_UNLOCK_CH(atadev->channel);
ata_start(atadev->channel);
splx(s);
}
int

View File

@ -266,6 +266,20 @@ void ata_dmastart(struct ata_channel *, int, struct ata_dmaentry *, int);
int ata_dmastatus(struct ata_channel *);
int ata_dmadone(struct ata_channel *);
/* macros for locking a channel */
#define ATA_LOCK_CH(ch, value)\
atomic_cmpset_int(&(ch)->active, ATA_IDLE, (value))
#define ATA_SLEEPLOCK_CH(ch, value)\
while (!atomic_cmpset_int(&(ch)->active, ATA_IDLE, (value)))\
tsleep((caddr_t)&(ch), PRIBIO, "atalck", 1);
#define ATA_FORCELOCK_CH(ch, value)\
(ch)->active = value;
#define ATA_UNLOCK_CH(ch)\
(ch)->active = ATA_IDLE
/* macros to hide busspace uglyness */
#define ATA_INB(res, offset) \
bus_space_read_1(rman_get_bustag((res)), \

View File

@ -121,6 +121,7 @@ ad_attach(struct ata_device *atadev)
adp->heads = atadev->param->heads;
adp->sectors = atadev->param->sectors;
adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors;
bioq_init(&adp->queue);
/* does this device need oldstyle CHS addressing */
if (!ad_version(atadev->param->version_major) ||
@ -137,6 +138,7 @@ ad_attach(struct ata_device *atadev)
atadev->param->lba_size48 > 268435455)
adp->total_secs = atadev->param->lba_size48;
ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
/* use multiple sectors/interrupt if device supports it */
adp->transfersize = DEV_BSIZE;
if (ad_version(atadev->param->version_major)) {
@ -185,6 +187,8 @@ ad_attach(struct ata_device *atadev)
ata_prtdev(atadev, "disabling service interrupt failed\n");
}
ATA_UNLOCK_CH(atadev->channel);
devstat_add_entry(&adp->stats, "ad", adp->lun, DEV_BSIZE,
DEVSTAT_NO_ORDERED_TAGS,
DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_IDE,
@ -194,7 +198,6 @@ ad_attach(struct ata_device *atadev)
dev->si_drv1 = adp;
dev->si_iosize_max = 256 * DEV_BSIZE;
adp->dev = dev;
bioq_init(&adp->queue);
/* construct the disklabel */
bzero(&adp->disk.d_label, sizeof(struct disklabel));
@ -267,8 +270,10 @@ adclose(dev_t dev, int flags, int fmt, struct thread *td)
{
struct ad_softc *adp = dev->si_drv1;
ATA_SLEEPLOCK_CH(adp->device->channel, ATA_CONTROL);
if (ata_command(adp->device, ATA_C_FLUSHCACHE, 0, 0, 0, ATA_WAIT_READY))
ata_prtdev(adp->device, "flushing cache on close failed\n");
ATA_UNLOCK_CH(adp->device->channel);
return 0;
}
@ -284,8 +289,8 @@ adstrategy(struct bio *bp)
}
s = splbio();
bioqdisksort(&adp->queue, bp);
ata_start(adp->device->channel);
splx(s);
ata_start(adp->device->channel);
}
int
@ -776,14 +781,10 @@ ad_service(struct ad_softc *adp, int change)
static void
ad_free(struct ad_request *request)
{
int s = splbio();
if (request->dmatab)
free(request->dmatab, M_DEVBUF);
request->softc->tags[request->tag] = NULL;
free(request, M_AD);
splx(s);
}
static void
@ -849,7 +850,6 @@ static void
ad_timeout(struct ad_request *request)
{
struct ad_softc *adp = request->softc;
int s = splbio();
adp->device->channel->running = NULL;
ata_prtdev(adp->device, "%s command timeout tag=%d serv=%d - resetting\n",
@ -869,7 +869,10 @@ ad_timeout(struct ad_request *request)
/* if retries still permit, reinject this request */
if (request->retries++ < AD_MAX_RETRIES) {
int s = splbio();
TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
splx(s);
}
else {
/* retries all used up, return error */
@ -879,7 +882,6 @@ ad_timeout(struct ad_request *request)
ad_free(request);
}
ata_reinit(adp->device->channel);
splx(s);
}
void

View File

@ -179,7 +179,7 @@ ata_raid_attach()
continue;
ar_config_changed(rdp, 0);
dev = disk_create(rdp->lun, &rdp->disk, 0, &ar_cdevsw,&ardisk_cdevsw);
dev = disk_create(rdp->lun, &rdp->disk, 0, &ar_cdevsw, &ardisk_cdevsw);
dev->si_drv1 = rdp;
dev->si_iosize_max = 256 * DEV_BSIZE;
rdp->dev = dev;
@ -553,9 +553,8 @@ ar_config_changed(struct ar_softc *rdp, int writeback)
static int
ar_rebuild(struct ar_softc *rdp)
{
int disk, s, count = 0, error = 0;
caddr_t buffer;
int count = 0, error = 0;
int disk;
if ((rdp->flags & (AR_F_READY|AR_F_DEGRADED)) != (AR_F_READY|AR_F_DEGRADED))
return EEXIST;
@ -578,9 +577,11 @@ ar_rebuild(struct ar_softc *rdp)
return ENODEV;
/* setup start conditions */
s = splbio();
rdp->lock_start = 0;
rdp->lock_end = rdp->lock_start + 256;
rdp->flags |= AR_F_REBUILDING;
splx(s);
buffer = malloc(256 * DEV_BSIZE, M_AR, M_NOWAIT | M_ZERO);
/* now go copy entire disk(s) */
@ -619,11 +620,12 @@ ar_rebuild(struct ar_softc *rdp)
free(buffer, M_AR);
return error;
}
s = splbio();
rdp->lock_start = rdp->lock_end;
rdp->lock_end = rdp->lock_start + size;
splx(s);
wakeup(rdp);
}
rdp->lock_start = 0xffffffff;
free(buffer, M_AR);
for (disk = 0; disk < rdp->total_disks; disk++) {
if ((rdp->disks[disk].flags&(AR_DF_PRESENT|AR_DF_ONLINE|AR_DF_SPARE))==
@ -632,7 +634,11 @@ ar_rebuild(struct ar_softc *rdp)
rdp->disks[disk].flags |= (AR_DF_ASSIGNED | AR_DF_ONLINE);
}
}
s = splbio();
rdp->lock_start = 0xffffffff;
rdp->lock_end = 0xffffffff;
rdp->flags &= ~AR_F_REBUILDING;
splx(s);
ar_config_changed(rdp, 1);
return 0;
}

View File

@ -72,6 +72,7 @@ atapi_attach(struct ata_device *atadev)
ata_pmode(atadev->param), ata_wmode(atadev->param),
ata_umode(atadev->param), atadev->param->support_dma);
ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
if (atapi_dma && !(atadev->param->drq_type == ATAPI_DRQT_INTR)) {
ata_dmainit(atadev->channel, atadev->unit,
(ata_pmode(atadev->param) < 0) ?
@ -84,6 +85,7 @@ atapi_attach(struct ata_device *atadev)
ata_dmainit(atadev->channel, atadev->unit,
ata_pmode(atadev->param) < 0 ? 0 : ata_pmode(atadev->param),
-1, -1);
ATA_UNLOCK_CH(atadev->channel);
if (!(atadev->result = malloc(sizeof(struct atapi_reqsense), M_ATAPI,
M_NOWAIT | M_ZERO)))
@ -190,28 +192,25 @@ atapi_queue_cmd(struct ata_device *atadev, int8_t *ccb, caddr_t data,
atadev->mode = ATA_PIO;
}
s = splbio();
/* append onto controller queue and try to start controller */
#ifdef ATAPI_DEBUG
ata_prtdev(atadev, "queueing %s ", atapi_cmd2str(request->ccb[0]));
atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb));
#endif
/* append onto controller queue and try to start controller */
s = splbio();
if (flags & ATPR_F_AT_HEAD)
TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain);
else
TAILQ_INSERT_TAIL(&atadev->channel->atapi_queue, request, chain);
splx(s);
ata_start(atadev->channel);
/* if callback used, then just return, gets called from interrupt context */
if (callback) {
splx(s);
if (callback)
return 0;
}
/* wait for request to complete */
tsleep((caddr_t)request, PRIBIO, "atprq", 0);
splx(s);
error = request->error;
if (error)
bcopy(&request->sense, atadev->result, sizeof(struct atapi_reqsense));
@ -605,7 +604,6 @@ static void
atapi_timeout(struct atapi_request *request)
{
struct ata_device *atadev = request->device;
int s = splbio();
atadev->channel->running = NULL;
ata_prtdev(atadev, "%s command timeout - resetting\n",
@ -623,15 +621,18 @@ atapi_timeout(struct atapi_request *request)
}
/* if retries still permit, reinject this request */
if (request->retries++ < ATAPI_MAX_RETRIES)
if (request->retries++ < ATAPI_MAX_RETRIES) {
int s = splbio();
TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain);
splx(s);
}
else {
/* retries all used up, return error */
request->error = EIO;
wakeup((caddr_t)request);
}
ata_reinit(atadev->channel);
splx(s);
}
static char *

View File

@ -1071,8 +1071,8 @@ acdstrategy(struct bio *bp)
s = splbio();
bioqdisksort(&cdp->queue, bp);
ata_start(cdp->device->channel);
splx(s);
ata_start(cdp->device->channel);
}
void

View File

@ -295,8 +295,8 @@ afdstrategy(struct bio *bp)
s = splbio();
bioqdisksort(&fdp->queue, bp);
ata_start(fdp->device->channel);
splx(s);
ata_start(fdp->device->channel);
}
void

View File

@ -448,8 +448,8 @@ aststrategy(struct bio *bp)
s = splbio();
bioq_insert_tail(&stp->queue, bp);
ata_start(stp->device->channel);
splx(s);
ata_start(stp->device->channel);
}
void