summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2009-03-24 23:22:54 +0100
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2009-03-24 23:22:54 +0100
commit2f40c9b0b65b5635e2e13dfa068bd56fe7a8ff98 (patch)
treef2ac83e1b59fb7cefde88455882817a2af99dbe4
parentd45b70ab9bbf1a46ae52972d532f9e267b8d39d9 (diff)
downloadlwn-2f40c9b0b65b5635e2e13dfa068bd56fe7a8ff98.tar.gz
lwn-2f40c9b0b65b5635e2e13dfa068bd56fe7a8ff98.zip
ide: fix kmalloc() failure handling in ide_driveid_update()
* Doing kmalloc() in the middle of command execution is not only ugly but leaves drive waiting to send data on kmalloc() failure. Fix it. While at it: * Unify error code paths. * Fixup error message to be more useful and add missing KERN_ERR level. * Rename 'stat' variable to 's'. Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-rw-r--r--drivers/ide/ide-iops.c33
1 files changed, 20 insertions, 13 deletions
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index e0cfa2d2acc7..a955483d2404 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -293,7 +293,12 @@ int ide_driveid_update(ide_drive_t *drive)
const struct ide_tp_ops *tp_ops = hwif->tp_ops;
u16 *id;
unsigned long flags;
- u8 stat;
+ int rc;
+ u8 uninitialized_var(s);
+
+ id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
+ if (id == NULL)
+ return 0;
/*
* Re-read drive->id for possible DMA mode
@@ -306,25 +311,21 @@ int ide_driveid_update(ide_drive_t *drive)
tp_ops->exec_command(hwif, ATA_CMD_ID_ATA);
if (ide_busy_sleep(hwif, WAIT_WORSTCASE, 1)) {
- SELECT_MASK(drive, 0);
- return 0;
+ rc = 1;
+ goto out_err;
}
msleep(50); /* wait for IRQ and ATA_DRQ */
- stat = tp_ops->read_status(hwif);
- if (!OK_STAT(stat, ATA_DRQ, BAD_R_STAT)) {
- SELECT_MASK(drive, 0);
- printk("%s: CHECK for good STATUS\n", drive->name);
- return 0;
+ s = tp_ops->read_status(hwif);
+
+ if (!OK_STAT(s, ATA_DRQ, BAD_R_STAT)) {
+ rc = 2;
+ goto out_err;
}
+
local_irq_save(flags);
SELECT_MASK(drive, 0);
- id = kmalloc(SECTOR_SIZE, GFP_ATOMIC);
- if (!id) {
- local_irq_restore(flags);
- return 0;
- }
tp_ops->input_data(drive, NULL, id, SECTOR_SIZE);
(void)tp_ops->read_status(hwif); /* clear drive IRQ */
local_irq_enable();
@@ -342,6 +343,12 @@ int ide_driveid_update(ide_drive_t *drive)
ide_dma_off(drive);
return 1;
+out_err:
+ SELECT_MASK(drive, 0);
+ if (rc == 2)
+ printk(KERN_ERR "%s: %s: bad status\n", drive->name, __func__);
+ kfree(id);
+ return 0;
}
int ide_config_drive_speed(ide_drive_t *drive, u8 speed)