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: default avatarRavikiran Thirumalai <kiran@scalex86.org>
Cc: Elias Oltmanns <eo@nebensachen.de>
Signed-off-by: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 6ea52226
...@@ -907,7 +907,7 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) ...@@ -907,7 +907,7 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
/* /*
* 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 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) ...@@ -919,7 +919,7 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
* 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 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) ...@@ -935,7 +935,7 @@ static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
* 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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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); ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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[]) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 { ...@@ -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; ...@@ -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
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment