forked from Minki/linux
ide: replace the global ide_lock spinlock by per-hwgroup spinlocks (v2)
Now that (almost) all host drivers have been fixed not to abuse ide_lock and core code usage of ide_lock has been sanitized we may safely replace ide_lock by per-hwgroup locks. This patch is partially based on earlier patch from Ravikiran G Thirumalai. While at it: - don't use deprecated HWIF() and HWGROUP() macros - update locking documentation in ide.h v2: Add missing spin_lock_init(&hwgroup->lock). (Noticed by Elias Oltmanns) Cc: Vaibhav V. Nivargi <vaibhav.nivargi@gmail.com> Cc: Alok N. Kataria <alokk@calsoftinc.com> Cc: Shai Fultheim <shai@scalex86.org> Signed-off-by: Ravikiran Thirumalai <kiran@scalex86.org> Cc: Elias Oltmanns <eo@nebensachen.de> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
parent
6ea52226ca
commit
2a2ca6a961
|
@ -907,7 +907,7 @@ repeat:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue a new request to a drive from hwgroup
|
* Issue a new request to a drive from hwgroup
|
||||||
* Caller must have already done spin_lock_irqsave(&ide_lock, ..);
|
* Caller must have already done spin_lock_irqsave(&hwgroup->lock, ..);
|
||||||
*
|
*
|
||||||
* A hwgroup is a serialized group of IDE interfaces. Usually there is
|
* A hwgroup is a serialized group of IDE interfaces. Usually there is
|
||||||
* exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
|
* exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
|
||||||
|
@ -919,7 +919,7 @@ repeat:
|
||||||
* possibly along with many other devices. This is especially common in
|
* possibly along with many other devices. This is especially common in
|
||||||
* PCI-based systems with off-board IDE controller cards.
|
* PCI-based systems with off-board IDE controller cards.
|
||||||
*
|
*
|
||||||
* The IDE driver uses the single global ide_lock spinlock to protect
|
* The IDE driver uses a per-hwgroup spinlock to protect
|
||||||
* access to the request queues, and to protect the hwgroup->busy flag.
|
* access to the request queues, and to protect the hwgroup->busy flag.
|
||||||
*
|
*
|
||||||
* The first thread into the driver for a particular hwgroup sets the
|
* The first thread into the driver for a particular hwgroup sets the
|
||||||
|
@ -935,7 +935,7 @@ repeat:
|
||||||
* will start the next request from the queue. If no more work remains,
|
* will start the next request from the queue. If no more work remains,
|
||||||
* the driver will clear the hwgroup->busy flag and exit.
|
* the driver will clear the hwgroup->busy flag and exit.
|
||||||
*
|
*
|
||||||
* The ide_lock (spinlock) is used to protect all access to the
|
* The per-hwgroup spinlock is used to protect all access to the
|
||||||
* hwgroup->busy flag, but is otherwise not needed for most processing in
|
* hwgroup->busy flag, but is otherwise not needed for most processing in
|
||||||
* the driver. This makes the driver much more friendlier to shared IRQs
|
* the driver. This makes the driver much more friendlier to shared IRQs
|
||||||
* than previous designs, while remaining 100% (?) SMP safe and capable.
|
* than previous designs, while remaining 100% (?) SMP safe and capable.
|
||||||
|
@ -948,7 +948,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
|
||||||
ide_startstop_t startstop;
|
ide_startstop_t startstop;
|
||||||
int loops = 0;
|
int loops = 0;
|
||||||
|
|
||||||
/* caller must own ide_lock */
|
/* caller must own hwgroup->lock */
|
||||||
BUG_ON(!irqs_disabled());
|
BUG_ON(!irqs_disabled());
|
||||||
|
|
||||||
while (!hwgroup->busy) {
|
while (!hwgroup->busy) {
|
||||||
|
@ -1070,11 +1070,11 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
|
||||||
*/
|
*/
|
||||||
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
||||||
disable_irq_nosync(hwif->irq);
|
disable_irq_nosync(hwif->irq);
|
||||||
spin_unlock(&ide_lock);
|
spin_unlock(&hwgroup->lock);
|
||||||
local_irq_enable_in_hardirq();
|
local_irq_enable_in_hardirq();
|
||||||
/* allow other IRQs while we start this request */
|
/* allow other IRQs while we start this request */
|
||||||
startstop = start_request(drive, rq);
|
startstop = start_request(drive, rq);
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
||||||
enable_irq(hwif->irq);
|
enable_irq(hwif->irq);
|
||||||
if (startstop == ide_stopped)
|
if (startstop == ide_stopped)
|
||||||
|
@ -1172,7 +1172,7 @@ void ide_timer_expiry (unsigned long data)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long wait = -1;
|
unsigned long wait = -1;
|
||||||
|
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
|
|
||||||
if (((handler = hwgroup->handler) == NULL) ||
|
if (((handler = hwgroup->handler) == NULL) ||
|
||||||
(hwgroup->req_gen != hwgroup->req_gen_timer)) {
|
(hwgroup->req_gen != hwgroup->req_gen_timer)) {
|
||||||
|
@ -1205,7 +1205,7 @@ void ide_timer_expiry (unsigned long data)
|
||||||
hwgroup->timer.expires = jiffies + wait;
|
hwgroup->timer.expires = jiffies + wait;
|
||||||
hwgroup->req_gen_timer = hwgroup->req_gen;
|
hwgroup->req_gen_timer = hwgroup->req_gen;
|
||||||
add_timer(&hwgroup->timer);
|
add_timer(&hwgroup->timer);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1215,7 +1215,7 @@ void ide_timer_expiry (unsigned long data)
|
||||||
* the handler() function, which means we need to
|
* the handler() function, which means we need to
|
||||||
* globally mask the specific IRQ:
|
* globally mask the specific IRQ:
|
||||||
*/
|
*/
|
||||||
spin_unlock(&ide_lock);
|
spin_unlock(&hwgroup->lock);
|
||||||
hwif = HWIF(drive);
|
hwif = HWIF(drive);
|
||||||
/* disable_irq_nosync ?? */
|
/* disable_irq_nosync ?? */
|
||||||
disable_irq(hwif->irq);
|
disable_irq(hwif->irq);
|
||||||
|
@ -1239,14 +1239,14 @@ void ide_timer_expiry (unsigned long data)
|
||||||
hwif->tp_ops->read_status(hwif));
|
hwif->tp_ops->read_status(hwif));
|
||||||
}
|
}
|
||||||
drive->service_time = jiffies - drive->service_start;
|
drive->service_time = jiffies - drive->service_start;
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
enable_irq(hwif->irq);
|
enable_irq(hwif->irq);
|
||||||
if (startstop == ide_stopped)
|
if (startstop == ide_stopped)
|
||||||
hwgroup->busy = 0;
|
hwgroup->busy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ide_do_request(hwgroup, IDE_NO_IRQ);
|
ide_do_request(hwgroup, IDE_NO_IRQ);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1339,14 +1339,13 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
|
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
|
||||||
ide_hwif_t *hwif;
|
ide_hwif_t *hwif = hwgroup->hwif;
|
||||||
ide_drive_t *drive;
|
ide_drive_t *drive;
|
||||||
ide_handler_t *handler;
|
ide_handler_t *handler;
|
||||||
ide_startstop_t startstop;
|
ide_startstop_t startstop;
|
||||||
irqreturn_t irq_ret = IRQ_NONE;
|
irqreturn_t irq_ret = IRQ_NONE;
|
||||||
|
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
hwif = hwgroup->hwif;
|
|
||||||
|
|
||||||
if (!ide_ack_intr(hwif))
|
if (!ide_ack_intr(hwif))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1416,7 +1415,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
||||||
hwgroup->handler = NULL;
|
hwgroup->handler = NULL;
|
||||||
hwgroup->req_gen++;
|
hwgroup->req_gen++;
|
||||||
del_timer(&hwgroup->timer);
|
del_timer(&hwgroup->timer);
|
||||||
spin_unlock(&ide_lock);
|
spin_unlock(&hwgroup->lock);
|
||||||
|
|
||||||
if (hwif->port_ops && hwif->port_ops->clear_irq)
|
if (hwif->port_ops && hwif->port_ops->clear_irq)
|
||||||
hwif->port_ops->clear_irq(drive);
|
hwif->port_ops->clear_irq(drive);
|
||||||
|
@ -1427,7 +1426,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
||||||
/* service this interrupt, may set handler for next interrupt */
|
/* service this interrupt, may set handler for next interrupt */
|
||||||
startstop = handler(drive);
|
startstop = handler(drive);
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
/*
|
/*
|
||||||
* Note that handler() may have set things up for another
|
* Note that handler() may have set things up for another
|
||||||
* interrupt to occur soon, but it cannot happen until
|
* interrupt to occur soon, but it cannot happen until
|
||||||
|
@ -1448,7 +1447,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
||||||
out_handled:
|
out_handled:
|
||||||
irq_ret = IRQ_HANDLED;
|
irq_ret = IRQ_HANDLED;
|
||||||
out:
|
out:
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
return irq_ret;
|
return irq_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -835,10 +835,12 @@ static void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
|
||||||
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
|
void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,
|
||||||
unsigned int timeout, ide_expiry_t *expiry)
|
unsigned int timeout, ide_expiry_t *expiry)
|
||||||
{
|
{
|
||||||
|
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
|
||||||
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
__ide_set_handler(drive, handler, timeout, expiry);
|
__ide_set_handler(drive, handler, timeout, expiry);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(ide_set_handler);
|
EXPORT_SYMBOL(ide_set_handler);
|
||||||
|
@ -860,10 +862,11 @@ EXPORT_SYMBOL(ide_set_handler);
|
||||||
void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
|
void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
|
||||||
unsigned timeout, ide_expiry_t *expiry)
|
unsigned timeout, ide_expiry_t *expiry)
|
||||||
{
|
{
|
||||||
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
|
ide_hwgroup_t *hwgroup = hwif->hwgroup;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
ide_hwif_t *hwif = HWIF(drive);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
__ide_set_handler(drive, handler, timeout, expiry);
|
__ide_set_handler(drive, handler, timeout, expiry);
|
||||||
hwif->tp_ops->exec_command(hwif, cmd);
|
hwif->tp_ops->exec_command(hwif, cmd);
|
||||||
/*
|
/*
|
||||||
|
@ -873,19 +876,20 @@ void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler,
|
||||||
* FIXME: we could skip this delay with care on non shared devices
|
* FIXME: we could skip this delay with care on non shared devices
|
||||||
*/
|
*/
|
||||||
ndelay(400);
|
ndelay(400);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ide_execute_command);
|
EXPORT_SYMBOL(ide_execute_command);
|
||||||
|
|
||||||
void ide_execute_pkt_cmd(ide_drive_t *drive)
|
void ide_execute_pkt_cmd(ide_drive_t *drive)
|
||||||
{
|
{
|
||||||
ide_hwif_t *hwif = drive->hwif;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
|
ide_hwgroup_t *hwgroup = hwif->hwgroup;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
|
hwif->tp_ops->exec_command(hwif, ATA_CMD_PACKET);
|
||||||
ndelay(400);
|
ndelay(400);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
|
EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
|
||||||
|
|
||||||
|
@ -1076,22 +1080,16 @@ static void pre_reset(ide_drive_t *drive)
|
||||||
*/
|
*/
|
||||||
static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
||||||
{
|
{
|
||||||
unsigned int unit;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
unsigned long flags, timeout;
|
ide_hwgroup_t *hwgroup = hwif->hwgroup;
|
||||||
ide_hwif_t *hwif;
|
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||||
ide_hwgroup_t *hwgroup;
|
const struct ide_tp_ops *tp_ops = hwif->tp_ops;
|
||||||
struct ide_io_ports *io_ports;
|
|
||||||
const struct ide_tp_ops *tp_ops;
|
|
||||||
const struct ide_port_ops *port_ops;
|
const struct ide_port_ops *port_ops;
|
||||||
|
unsigned long flags, timeout;
|
||||||
|
unsigned int unit;
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
hwif = HWIF(drive);
|
|
||||||
hwgroup = HWGROUP(drive);
|
|
||||||
|
|
||||||
io_ports = &hwif->io_ports;
|
|
||||||
|
|
||||||
tp_ops = hwif->tp_ops;
|
|
||||||
|
|
||||||
/* We must not reset with running handlers */
|
/* We must not reset with running handlers */
|
||||||
BUG_ON(hwgroup->handler != NULL);
|
BUG_ON(hwgroup->handler != NULL);
|
||||||
|
@ -1106,7 +1104,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
||||||
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
|
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
|
||||||
hwgroup->polling = 1;
|
hwgroup->polling = 1;
|
||||||
__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
|
__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
return ide_started;
|
return ide_started;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1129,9 +1127,9 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
||||||
if (time_before_eq(timeout, now))
|
if (time_before_eq(timeout, now))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
timeout = schedule_timeout_uninterruptible(timeout - now);
|
timeout = schedule_timeout_uninterruptible(timeout - now);
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
} while (timeout);
|
} while (timeout);
|
||||||
finish_wait(&ide_park_wq, &wait);
|
finish_wait(&ide_park_wq, &wait);
|
||||||
|
|
||||||
|
@ -1143,7 +1141,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
||||||
pre_reset(&hwif->drives[unit]);
|
pre_reset(&hwif->drives[unit]);
|
||||||
|
|
||||||
if (io_ports->ctl_addr == 0) {
|
if (io_ports->ctl_addr == 0) {
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
ide_complete_drive_reset(drive, -ENXIO);
|
ide_complete_drive_reset(drive, -ENXIO);
|
||||||
return ide_stopped;
|
return ide_stopped;
|
||||||
}
|
}
|
||||||
|
@ -1179,7 +1177,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
|
||||||
if (port_ops && port_ops->resetproc)
|
if (port_ops && port_ops->resetproc)
|
||||||
port_ops->resetproc(drive);
|
port_ops->resetproc(drive);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
return ide_started;
|
return ide_started;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,16 @@ DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
|
||||||
|
|
||||||
static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
|
static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
|
||||||
{
|
{
|
||||||
|
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
||||||
struct request_queue *q = drive->queue;
|
struct request_queue *q = drive->queue;
|
||||||
struct request *rq;
|
struct request *rq;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
timeout += jiffies;
|
timeout += jiffies;
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
if (drive->dev_flags & IDE_DFLAG_PARKED) {
|
if (drive->dev_flags & IDE_DFLAG_PARKED) {
|
||||||
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
int reset_timer = time_before(timeout, drive->sleep);
|
||||||
int reset_timer;
|
|
||||||
|
|
||||||
reset_timer = time_before(timeout, drive->sleep);
|
|
||||||
drive->sleep = timeout;
|
drive->sleep = timeout;
|
||||||
wake_up_all(&ide_park_wq);
|
wake_up_all(&ide_park_wq);
|
||||||
if (reset_timer && hwgroup->sleeping &&
|
if (reset_timer && hwgroup->sleeping &&
|
||||||
|
@ -26,10 +25,10 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
|
||||||
hwgroup->busy = 0;
|
hwgroup->busy = 0;
|
||||||
blk_start_queueing(q);
|
blk_start_queueing(q);
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
|
|
||||||
rq = blk_get_request(q, READ, __GFP_WAIT);
|
rq = blk_get_request(q, READ, __GFP_WAIT);
|
||||||
rq->cmd[0] = REQ_PARK_HEADS;
|
rq->cmd[0] = REQ_PARK_HEADS;
|
||||||
|
@ -62,20 +61,21 @@ ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
ide_drive_t *drive = to_ide_device(dev);
|
ide_drive_t *drive = to_ide_device(dev);
|
||||||
|
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
unsigned int msecs;
|
unsigned int msecs;
|
||||||
|
|
||||||
if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
|
if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
now = jiffies;
|
now = jiffies;
|
||||||
if (drive->dev_flags & IDE_DFLAG_PARKED &&
|
if (drive->dev_flags & IDE_DFLAG_PARKED &&
|
||||||
time_after(drive->sleep, now))
|
time_after(drive->sleep, now))
|
||||||
msecs = jiffies_to_msecs(drive->sleep - now);
|
msecs = jiffies_to_msecs(drive->sleep - now);
|
||||||
else
|
else
|
||||||
msecs = 0;
|
msecs = 0;
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
|
|
||||||
return snprintf(buf, 20, "%u\n", msecs);
|
return snprintf(buf, 20, "%u\n", msecs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -906,7 +906,8 @@ static int ide_init_queue(ide_drive_t *drive)
|
||||||
* do not.
|
* do not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
q = blk_init_queue_node(do_ide_request, &ide_lock, hwif_to_node(hwif));
|
q = blk_init_queue_node(do_ide_request, &hwif->hwgroup->lock,
|
||||||
|
hwif_to_node(hwif));
|
||||||
if (!q)
|
if (!q)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -947,7 +948,7 @@ static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
|
||||||
{
|
{
|
||||||
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
if (!hwgroup->drive) {
|
if (!hwgroup->drive) {
|
||||||
/* first drive for hwgroup. */
|
/* first drive for hwgroup. */
|
||||||
drive->next = drive;
|
drive->next = drive;
|
||||||
|
@ -957,7 +958,7 @@ static void ide_add_drive_to_hwgroup(ide_drive_t *drive)
|
||||||
drive->next = hwgroup->drive->next;
|
drive->next = hwgroup->drive->next;
|
||||||
hwgroup->drive->next = drive;
|
hwgroup->drive->next = drive;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1002,7 +1003,7 @@ void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
|
||||||
|
|
||||||
ide_ports[hwif->index] = NULL;
|
ide_ports[hwif->index] = NULL;
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
/*
|
/*
|
||||||
* Remove us from the hwgroup, and free
|
* Remove us from the hwgroup, and free
|
||||||
* the hwgroup if we were the only member
|
* the hwgroup if we were the only member
|
||||||
|
@ -1030,7 +1031,7 @@ void ide_remove_port_from_hwgroup(ide_hwif_t *hwif)
|
||||||
}
|
}
|
||||||
BUG_ON(hwgroup->hwif == hwif);
|
BUG_ON(hwgroup->hwif == hwif);
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1092,17 +1093,19 @@ static int init_irq (ide_hwif_t *hwif)
|
||||||
* linked list, the first entry is the hwif that owns
|
* linked list, the first entry is the hwif that owns
|
||||||
* hwgroup->handler - do not change that.
|
* hwgroup->handler - do not change that.
|
||||||
*/
|
*/
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
hwif->next = hwgroup->hwif->next;
|
hwif->next = hwgroup->hwif->next;
|
||||||
hwgroup->hwif->next = hwif;
|
hwgroup->hwif->next = hwif;
|
||||||
BUG_ON(hwif->next == hwif);
|
BUG_ON(hwif->next == hwif);
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
} else {
|
} else {
|
||||||
hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
|
hwgroup = kmalloc_node(sizeof(*hwgroup), GFP_KERNEL|__GFP_ZERO,
|
||||||
hwif_to_node(hwif));
|
hwif_to_node(hwif));
|
||||||
if (hwgroup == NULL)
|
if (hwgroup == NULL)
|
||||||
goto out_up;
|
goto out_up;
|
||||||
|
|
||||||
|
spin_lock_init(&hwgroup->lock);
|
||||||
|
|
||||||
hwif->hwgroup = hwgroup;
|
hwif->hwgroup = hwgroup;
|
||||||
hwgroup->hwif = hwif->next = hwif;
|
hwgroup->hwif = hwif->next = hwif;
|
||||||
|
|
||||||
|
@ -1263,20 +1266,21 @@ static void ide_remove_drive_from_hwgroup(ide_drive_t *drive)
|
||||||
static void drive_release_dev (struct device *dev)
|
static void drive_release_dev (struct device *dev)
|
||||||
{
|
{
|
||||||
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
|
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
|
||||||
|
ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
|
||||||
|
|
||||||
ide_proc_unregister_device(drive);
|
ide_proc_unregister_device(drive);
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
ide_remove_drive_from_hwgroup(drive);
|
ide_remove_drive_from_hwgroup(drive);
|
||||||
kfree(drive->id);
|
kfree(drive->id);
|
||||||
drive->id = NULL;
|
drive->id = NULL;
|
||||||
drive->dev_flags &= ~IDE_DFLAG_PRESENT;
|
drive->dev_flags &= ~IDE_DFLAG_PRESENT;
|
||||||
/* Messed up locking ... */
|
/* Messed up locking ... */
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
blk_cleanup_queue(drive->queue);
|
blk_cleanup_queue(drive->queue);
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
drive->queue = NULL;
|
drive->queue = NULL;
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
|
|
||||||
complete(&drive->gendev_rel_comp);
|
complete(&drive->gendev_rel_comp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,9 +74,6 @@ static const u8 ide_hwif_to_major[] = { IDE0_MAJOR, IDE1_MAJOR,
|
||||||
|
|
||||||
DEFINE_MUTEX(ide_cfg_mtx);
|
DEFINE_MUTEX(ide_cfg_mtx);
|
||||||
|
|
||||||
__cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock);
|
|
||||||
EXPORT_SYMBOL(ide_lock);
|
|
||||||
|
|
||||||
static void ide_port_init_devices_data(ide_hwif_t *);
|
static void ide_port_init_devices_data(ide_hwif_t *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -333,6 +330,7 @@ static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
|
||||||
static int set_pio_mode(ide_drive_t *drive, int arg)
|
static int set_pio_mode(ide_drive_t *drive, int arg)
|
||||||
{
|
{
|
||||||
ide_hwif_t *hwif = drive->hwif;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
|
ide_hwgroup_t *hwgroup = hwif->hwgroup;
|
||||||
const struct ide_port_ops *port_ops = hwif->port_ops;
|
const struct ide_port_ops *port_ops = hwif->port_ops;
|
||||||
|
|
||||||
if (arg < 0 || arg > 255)
|
if (arg < 0 || arg > 255)
|
||||||
|
@ -347,9 +345,9 @@ static int set_pio_mode(ide_drive_t *drive, int arg)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
|
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||||
port_ops->set_pio_mode(drive, arg);
|
port_ops->set_pio_mode(drive, arg);
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||||
} else
|
} else
|
||||||
port_ops->set_pio_mode(drive, arg);
|
port_ops->set_pio_mode(drive, arg);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -107,18 +107,21 @@ static void umc_set_speeds(u8 speeds[])
|
||||||
static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
|
static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
|
||||||
{
|
{
|
||||||
ide_hwif_t *hwif = drive->hwif;
|
ide_hwif_t *hwif = drive->hwif;
|
||||||
unsigned long flags;
|
ide_hwgroup_t *mate_hwgroup = hwif->mate ? hwif->mate->hwgroup : NULL;
|
||||||
|
unsigned long uninitialized_var(flags);
|
||||||
|
|
||||||
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
|
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
|
||||||
drive->name, pio, pio_to_umc[pio]);
|
drive->name, pio, pio_to_umc[pio]);
|
||||||
spin_lock_irqsave(&ide_lock, flags);
|
if (mate_hwgroup)
|
||||||
if (hwif->mate && hwif->mate->hwgroup->handler) {
|
spin_lock_irqsave(&mate_hwgroup->lock, flags);
|
||||||
|
if (mate_hwgroup && mate_hwgroup->handler) {
|
||||||
printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
|
printk(KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n");
|
||||||
} else {
|
} else {
|
||||||
current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
|
current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio];
|
||||||
umc_set_speeds(current_speeds);
|
umc_set_speeds(current_speeds);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ide_lock, flags);
|
if (mate_hwgroup)
|
||||||
|
spin_unlock_irqrestore(&mate_hwgroup->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ide_port_ops umc8672_port_ops = {
|
static const struct ide_port_ops umc8672_port_ops = {
|
||||||
|
|
|
@ -578,6 +578,8 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
|
||||||
{
|
{
|
||||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
||||||
ide_drive_t *drive = scsi->drive;
|
ide_drive_t *drive = scsi->drive;
|
||||||
|
ide_hwif_t *hwif;
|
||||||
|
ide_hwgroup_t *hwgroup;
|
||||||
int busy;
|
int busy;
|
||||||
int ret = FAILED;
|
int ret = FAILED;
|
||||||
|
|
||||||
|
@ -594,13 +596,16 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
|
||||||
goto no_drive;
|
goto no_drive;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First give it some more time, how much is "right" is hard to say :-( */
|
hwif = drive->hwif;
|
||||||
|
hwgroup = hwif->hwgroup;
|
||||||
|
|
||||||
busy = ide_wait_not_busy(HWIF(drive), 100); /* FIXME - uses mdelay which causes latency? */
|
/* First give it some more time, how much is "right" is hard to say :-(
|
||||||
|
FIXME - uses mdelay which causes latency? */
|
||||||
|
busy = ide_wait_not_busy(hwif, 100);
|
||||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||||
printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
|
printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
|
||||||
|
|
||||||
spin_lock_irq(&ide_lock);
|
spin_lock_irq(&hwgroup->lock);
|
||||||
|
|
||||||
/* If there is no pc running we're done (our interrupt took care of it) */
|
/* If there is no pc running we're done (our interrupt took care of it) */
|
||||||
pc = drive->pc;
|
pc = drive->pc;
|
||||||
|
@ -629,7 +634,7 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
ide_unlock:
|
ide_unlock:
|
||||||
spin_unlock_irq(&ide_lock);
|
spin_unlock_irq(&hwgroup->lock);
|
||||||
no_drive:
|
no_drive:
|
||||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||||
printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
|
printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
|
||||||
|
@ -642,6 +647,7 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
|
||||||
struct request *req;
|
struct request *req;
|
||||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
||||||
ide_drive_t *drive = scsi->drive;
|
ide_drive_t *drive = scsi->drive;
|
||||||
|
ide_hwgroup_t *hwgroup;
|
||||||
int ready = 0;
|
int ready = 0;
|
||||||
int ret = SUCCESS;
|
int ret = SUCCESS;
|
||||||
|
|
||||||
|
@ -658,14 +664,18 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hwgroup = drive->hwif->hwgroup;
|
||||||
|
|
||||||
spin_lock_irq(cmd->device->host->host_lock);
|
spin_lock_irq(cmd->device->host->host_lock);
|
||||||
spin_lock(&ide_lock);
|
spin_lock(&hwgroup->lock);
|
||||||
|
|
||||||
pc = drive->pc;
|
pc = drive->pc;
|
||||||
|
if (pc)
|
||||||
|
req = pc->rq;
|
||||||
|
|
||||||
if (pc == NULL || (req = pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
|
if (pc == NULL || req != hwgroup->rq || hwgroup->handler == NULL) {
|
||||||
printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
|
printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
|
||||||
spin_unlock(&ide_lock);
|
spin_unlock(&hwgroup->lock);
|
||||||
spin_unlock_irq(cmd->device->host->host_lock);
|
spin_unlock_irq(cmd->device->host->host_lock);
|
||||||
return FAILED;
|
return FAILED;
|
||||||
}
|
}
|
||||||
|
@ -685,10 +695,10 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
HWGROUP(drive)->rq = NULL;
|
hwgroup->rq = NULL;
|
||||||
HWGROUP(drive)->handler = NULL;
|
hwgroup->handler = NULL;
|
||||||
HWGROUP(drive)->busy = 1; /* will set this to zero when ide reset finished */
|
hwgroup->busy = 1; /* will set this to zero when ide reset finished */
|
||||||
spin_unlock(&ide_lock);
|
spin_unlock(&hwgroup->lock);
|
||||||
|
|
||||||
ide_do_reset(drive);
|
ide_do_reset(drive);
|
||||||
|
|
||||||
|
|
|
@ -909,6 +909,8 @@ typedef struct hwgroup_s {
|
||||||
|
|
||||||
int req_gen;
|
int req_gen;
|
||||||
int req_gen_timer;
|
int req_gen_timer;
|
||||||
|
|
||||||
|
spinlock_t lock;
|
||||||
} ide_hwgroup_t;
|
} ide_hwgroup_t;
|
||||||
|
|
||||||
typedef struct ide_driver_s ide_driver_t;
|
typedef struct ide_driver_s ide_driver_t;
|
||||||
|
@ -1610,13 +1612,13 @@ extern struct mutex ide_cfg_mtx;
|
||||||
/*
|
/*
|
||||||
* Structure locking:
|
* Structure locking:
|
||||||
*
|
*
|
||||||
* ide_cfg_mtx and ide_lock together protect changes to
|
* ide_cfg_mtx and hwgroup->lock together protect changes to
|
||||||
* ide_hwif_t->{next,hwgroup}
|
* ide_hwif_t->next
|
||||||
* ide_drive_t->next
|
* ide_drive_t->next
|
||||||
*
|
*
|
||||||
* ide_hwgroup_t->busy: ide_lock
|
* ide_hwgroup_t->busy: hwgroup->lock
|
||||||
* ide_hwgroup_t->hwif: ide_lock
|
* ide_hwgroup_t->hwif: hwgroup->lock
|
||||||
* ide_hwif_t->mate: constant, no locking
|
* ide_hwif_t->{hwgroup,mate}: constant, no locking
|
||||||
* ide_drive_t->hwif: constant, no locking
|
* ide_drive_t->hwif: constant, no locking
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user