Skip to content

Commit

Permalink
IDE: Report errors during drive reset back to user space
Browse files Browse the repository at this point in the history
Make sure that each error condition during the execution of an
HDIO_DRIVE_RESET ioctl is actually reported to the calling process.
Also, unify the exit path of reset_pollfunc() when returning ide_stopped
since the need of ->port_ops->reset_poll() to be treated specially has
vanished (way back, it seems).

Signed-off-by: Elias Oltmanns <eo@nebensachen.de>
Cc: "Alan Cox" <alan@lxorguk.ukuu.org.uk>
Cc: "Randy Dunlap" <randy.dunlap@oracle.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
  • Loading branch information
Elias Oltmanns authored and Bartlomiej Zolnierkiewicz committed Jul 16, 2008
1 parent bb7ee9b commit 64a8f00
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 13 deletions.
2 changes: 2 additions & 0 deletions Documentation/ioctl/hdio.txt
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ HDIO_DRIVE_RESET execute a device reset

error returns:
EACCES Access denied: requires CAP_SYS_ADMIN
ENXIO No such device: phy dead or ctl_addr == 0
EIO I/O error: reset timed out or hardware error

notes:

Expand Down
18 changes: 11 additions & 7 deletions drivers/ide/ide-iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,12 +905,12 @@ void ide_execute_pkt_cmd(ide_drive_t *drive)
}
EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);

static inline void ide_complete_drive_reset(ide_drive_t *drive)
static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
{
struct request *rq = drive->hwif->hwgroup->rq;

if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
ide_end_request(drive, 1, 0);
ide_end_request(drive, err ? err : 1, 0);
}

/* needed below */
Expand Down Expand Up @@ -948,7 +948,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
}
/* done polling */
hwgroup->polling = 0;
ide_complete_drive_reset(drive);
ide_complete_drive_reset(drive, 0);
return ide_stopped;
}

Expand All @@ -964,9 +964,11 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
ide_hwif_t *hwif = HWIF(drive);
const struct ide_port_ops *port_ops = hwif->port_ops;
u8 tmp;
int err = 0;

if (port_ops && port_ops->reset_poll) {
if (port_ops->reset_poll(drive)) {
err = port_ops->reset_poll(drive);
if (err) {
printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
hwif->name, drive->name);
goto out;
Expand All @@ -983,6 +985,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
}
printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);
drive->failures++;
err = -EIO;
} else {
printk("%s: reset: ", hwif->name);
tmp = ide_read_error(drive);
Expand All @@ -1009,11 +1012,12 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
if (tmp & 0x80)
printk("; slave: failed");
printk("\n");
err = -EIO;
}
}
hwgroup->polling = 0; /* done polling */
out:
ide_complete_drive_reset(drive);
hwgroup->polling = 0; /* done polling */
ide_complete_drive_reset(drive, err);
return ide_stopped;
}

Expand Down Expand Up @@ -1120,7 +1124,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)

if (io_ports->ctl_addr == 0) {
spin_unlock_irqrestore(&ide_lock, flags);
ide_complete_drive_reset(drive);
ide_complete_drive_reset(drive, -ENXIO);
return ide_stopped;
}

Expand Down
10 changes: 6 additions & 4 deletions drivers/ide/ide.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,17 +529,20 @@ static int generic_ide_resume(struct device *dev)
return err;
}

static void generic_drive_reset(ide_drive_t *drive)
static int generic_drive_reset(ide_drive_t *drive)
{
struct request *rq;
int ret = 0;

rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd_len = 1;
rq->cmd[0] = REQ_DRIVE_RESET;
rq->cmd_flags |= REQ_SOFTBARRIER;
blk_execute_rq(drive->queue, NULL, rq, 1);
if (blk_execute_rq(drive->queue, NULL, rq, 1))
ret = rq->errors;
blk_put_request(rq);
return ret;
}

int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
Expand Down Expand Up @@ -616,8 +619,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
if (!capable(CAP_SYS_ADMIN))
return -EACCES;

generic_drive_reset(drive);
return 0;
return generic_drive_reset(drive);

case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
Expand Down
3 changes: 1 addition & 2 deletions drivers/ide/pci/siimage.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,7 @@ static int sil_sata_reset_poll(ide_drive_t *drive)
if ((sata_stat & 0x03) != 0x03) {
printk(KERN_WARNING "%s: reset phy dead, status=0x%08x\n",
hwif->name, sata_stat);
HWGROUP(drive)->polling = 0;
return ide_started;
return -ENXIO;
}
}

Expand Down

0 comments on commit 64a8f00

Please sign in to comment.