static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) { ide_hwif_t *hwif = drive->hwif; if ((stat & ATA_BUSY) || ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { /* add decoding error stuff */ } if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) /* force an abort */ hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE); if (rq->errors >= ERROR_MAX) { ide_kill_rq(drive, rq); } else { if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; return ide_do_reset(drive); } ++rq->errors; } return ide_stopped; }
static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) { ide_hwif_t *hwif = drive->hwif; if ((stat & ATA_BUSY) || ((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else if (stat & ATA_ERR) { /* err has different meaning on cdrom and tape */ if (err == ATA_ABORTED) { if ((drive->dev_flags & IDE_DFLAG_LBA) && /* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */ hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS) return ide_stopped; } else if ((err & BAD_CRC) == BAD_CRC) { /* UDMA crc error, just retry the operation */ drive->crc_count++; } else if (err & (ATA_BBK | ATA_UNC)) { /* retries won't help these */ rq->errors = ERROR_MAX; } else if (err & ATA_TRK0NF) { /* help it find track zero */ rq->errors |= ERROR_RECAL; } } if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ && (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) { int nsect = drive->mult_count ? drive->mult_count : 1; ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE); } if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) { ide_kill_rq(drive, rq); return ide_stopped; } if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ)) rq->errors |= ERROR_RESET; if ((rq->errors & ERROR_RESET) == ERROR_RESET) { ++rq->errors; return ide_do_reset(drive); } if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) drive->special_flags |= IDE_SFLAG_RECALIBRATE; ++rq->errors; return ide_stopped; }
static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) { u8 cmd = rq->cmd[0]; if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) { ide_task_t task; struct ide_taskfile *tf = &task.tf; memset(&task, 0, sizeof(task)); if (cmd == REQ_PARK_HEADS) { drive->sleep = *(unsigned long *)rq->special; drive->dev_flags |= IDE_DFLAG_SLEEPING; tf->command = ATA_CMD_IDLEIMMEDIATE; tf->feature = 0x44; tf->lbal = 0x4c; tf->lbam = 0x4e; tf->lbah = 0x55; task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER; } else /* cmd == REQ_UNPARK_HEADS */ tf->command = ATA_CMD_CHK_POWER; task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE; task.rq = rq; drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA; return do_rw_taskfile(drive, &task); } switch (cmd) { case REQ_DEVSET_EXEC: { int err, (*setfunc)(ide_drive_t *, int) = rq->special; err = setfunc(drive, *(int *)&rq->cmd[1]); if (err) rq->errors = err; else err = 1; ide_end_request(drive, err, 0); return ide_stopped; } case REQ_DRIVE_RESET: return ide_do_reset(drive); default: blk_dump_rq_flags(rq, "ide_special_rq - bad request"); ide_end_request(drive, 0, 0); return ide_stopped; } }
static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) { u8 cmd = rq->cmd[0]; switch (cmd) { case REQ_PARK_HEADS: case REQ_UNPARK_HEADS: return ide_do_park_unpark(drive, rq); case REQ_DEVSET_EXEC: return ide_do_devset(drive, rq); case REQ_DRIVE_RESET: return ide_do_reset(drive); default: BUG(); } }
static int scc_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); void __iomem *dma_base = (void __iomem *)hwif->dma_base; unsigned long intsts_port = hwif->dma_base + 0x014; u32 reg; int dma_stat, data_loss = 0; static int retry = 0; /* errata A308 workaround: Step5 (check data loss) */ /* We don't check non ide_disk because it is limited to UDMA4 */ if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr) & ERR_STAT) && drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) { reg = in_be32((void __iomem *)intsts_port); if (!(reg & INTSTS_ACTEINT)) { printk(KERN_WARNING "%s: operation failed (transfer data loss)\n", drive->name); data_loss = 1; if (retry++) { struct request *rq = HWGROUP(drive)->rq; int unit; /* ERROR_RESET and drive->crc_count are needed * to reduce DMA transfer mode in retry process. */ if (rq) rq->errors |= ERROR_RESET; for (unit = 0; unit < MAX_DRIVES; unit++) { ide_drive_t *drive = &hwif->drives[unit]; drive->crc_count++; } } } } while (1) { reg = in_be32((void __iomem *)intsts_port); if (reg & INTSTS_SERROR) { printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME); out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT); out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); continue; } if (reg & INTSTS_PRERR) { u32 maea0, maec0; unsigned long ctl_base = hwif->config_data; maea0 = in_be32((void __iomem *)(ctl_base + 0xF50)); maec0 = in_be32((void __iomem *)(ctl_base + 0xF54)); printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0); out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT); out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); continue; } if (reg & INTSTS_RERR) { printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME); out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT); out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); continue; } if (reg & INTSTS_ICERR) { out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS); printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME); out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT); continue; } if (reg & INTSTS_BMSINT) { printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME); out_be32((void __iomem *)intsts_port, INTSTS_BMSINT); ide_do_reset(drive); continue; } if (reg & INTSTS_BMHE) { out_be32((void __iomem *)intsts_port, INTSTS_BMHE); continue; } if (reg & INTSTS_ACTEINT) { out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT); continue; } if (reg & INTSTS_IOIRQS) { out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS); continue; } break; } dma_stat = __scc_dma_end(drive); if (data_loss) dma_stat |= 2; /* emulate DMA error (to retry command) */ return dma_stat; }
int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, unsigned int cmd, unsigned long arg) { unsigned long flags; ide_driver_t *drv; void __user *p = (void __user *)arg; int err = 0, (*setfunc)(ide_drive_t *, int); u8 *val; switch (cmd) { case HDIO_GET_32BIT: val = &drive->io_32bit; goto read_val; case HDIO_GET_KEEPSETTINGS: val = &drive->keep_settings; goto read_val; case HDIO_GET_UNMASKINTR: val = &drive->unmask; goto read_val; case HDIO_GET_DMA: val = &drive->using_dma; goto read_val; case HDIO_SET_32BIT: setfunc = set_io_32bit; goto set_val; case HDIO_SET_KEEPSETTINGS: setfunc = set_ksettings; goto set_val; case HDIO_SET_PIO_MODE: setfunc = set_pio_mode; goto set_val; case HDIO_SET_UNMASKINTR: setfunc = set_unmaskirq; goto set_val; case HDIO_SET_DMA: setfunc = set_using_dma; goto set_val; } switch (cmd) { case HDIO_OBSOLETE_IDENTITY: case HDIO_GET_IDENTITY: if (bdev != bdev->bd_contains) return -EINVAL; if (drive->id_read == 0) return -ENOMSG; if (copy_to_user(p, drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142)) return -EFAULT; return 0; case HDIO_GET_NICE: return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | drive->nice0 << IDE_NICE_0 | drive->nice1 << IDE_NICE_1 | drive->nice2 << IDE_NICE_2, (long __user *) arg); #ifdef CONFIG_IDE_TASK_IOCTL case HDIO_DRIVE_TASKFILE: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; switch(drive->media) { case ide_disk: return ide_taskfile_ioctl(drive, cmd, arg); default: return -ENOMSG; } #endif /* CONFIG_IDE_TASK_IOCTL */ case HDIO_DRIVE_CMD: if (!capable(CAP_SYS_RAWIO)) return -EACCES; return ide_cmd_ioctl(drive, cmd, arg); case HDIO_DRIVE_TASK: if (!capable(CAP_SYS_RAWIO)) return -EACCES; return ide_task_ioctl(drive, cmd, arg); case HDIO_SCAN_HWIF: { hw_regs_t hw; int args[3]; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (copy_from_user(args, p, 3 * sizeof(int))) return -EFAULT; memset(&hw, 0, sizeof(hw)); ide_init_hwif_ports(&hw, (unsigned long) args[0], (unsigned long) args[1], NULL); hw.irq = args[2]; if (ide_register_hw(&hw, 0, NULL) == -1) return -EIO; return 0; } case HDIO_UNREGISTER_HWIF: if (!capable(CAP_SYS_RAWIO)) return -EACCES; /* (arg > MAX_HWIFS) checked in function */ ide_unregister(arg); return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1)))) return -EPERM; drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1; drv = *(ide_driver_t **)bdev->bd_disk->private_data; if (drive->dsc_overlap && !drv->supports_dsc_overlap) { drive->dsc_overlap = 0; return -EPERM; } drive->nice1 = (arg >> IDE_NICE_1) & 1; return 0; case HDIO_DRIVE_RESET: { unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * Abort the current command on the * group if there is one, taking * care not to allow anything else * to be queued and to die on the * spot if we miss one somehow */ spin_lock_irqsave(&ide_lock, flags); if (HWGROUP(drive)->resetting) { spin_unlock_irqrestore(&ide_lock, flags); return -EBUSY; } ide_abort(drive, "drive reset"); BUG_ON(HWGROUP(drive)->handler); /* Ensure nothing gets queued after we drop the lock. Reset will clear the busy */ HWGROUP(drive)->busy = 1; spin_unlock_irqrestore(&ide_lock, flags); (void) ide_do_reset(drive); return 0; } case CDROMEJECT: case CDROMCLOSETRAY: return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p); case HDIO_GET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (put_user(HWIF(drive)->bus_state, (long __user *)arg)) return -EFAULT; return 0; case HDIO_SET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (HWIF(drive)->busproc) return HWIF(drive)->busproc(drive, (int)arg); return -EOPNOTSUPP; default: return -EINVAL; } read_val: down(&ide_setting_sem); spin_lock_irqsave(&ide_lock, flags); err = *val; spin_unlock_irqrestore(&ide_lock, flags); up(&ide_setting_sem); return err >= 0 ? put_user(err, (long __user *)arg) : err; set_val: if (bdev != bdev->bd_contains) err = -EINVAL; else { if (!capable(CAP_SYS_ADMIN)) err = -EACCES; else { down(&ide_setting_sem); err = setfunc(drive, arg); up(&ide_setting_sem); } } return err; }
static int idescsi_eh_reset (struct scsi_cmnd *cmd) { struct request *req; idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host); ide_drive_t *drive = scsi->drive; int ready = 0; int ret = SUCCESS; /* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number); if (!drive) { printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n"); WARN_ON(1); return FAILED; } spin_lock_irq(cmd->device->host->host_lock); spin_lock(&ide_lock); if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) { printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n"); spin_unlock(&ide_lock); spin_unlock_irq(cmd->device->host->host_lock); return FAILED; } /* kill current request */ if (__blk_end_request(req, -EIO, 0)) BUG(); if (blk_sense_request(req)) kfree(scsi->pc->buf); kfree(scsi->pc); scsi->pc = NULL; blk_put_request(req); /* now nuke the drive queue */ while ((req = elv_next_request(drive->queue))) { if (__blk_end_request(req, -EIO, 0)) BUG(); } HWGROUP(drive)->rq = NULL; HWGROUP(drive)->handler = NULL; HWGROUP(drive)->busy = 1; /* will set this to zero when ide reset finished */ spin_unlock(&ide_lock); ide_do_reset(drive); /* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */ do { spin_unlock_irq(cmd->device->host->host_lock); msleep(50); spin_lock_irq(cmd->device->host->host_lock); } while ( HWGROUP(drive)->handler ); ready = drive_is_ready(drive); HWGROUP(drive)->busy--; if (!ready) { printk (KERN_ERR "ide-scsi: reset failed!\n"); ret = FAILED; } spin_unlock_irq(cmd->device->host->host_lock); return ret; }