📄 ide-io.c
字号:
if (err == ABRT_ERR) { if (drive->select.b.lba && /* some newer drives don't support WIN_SPECIFY */ hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY) return ide_stopped; } else if ((err & BAD_CRC) == BAD_CRC) { /* UDMA crc error, just retry the operation */ drive->crc_count++; } else if (err & (BBD_ERR | ECC_ERR)) { /* retries won't help these */ rq->errors = ERROR_MAX; } else if (err & TRK0_ERR) { /* help it find track zero */ rq->errors |= ERROR_RECAL; } } if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && (hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) try_to_flush_leftover_data(drive); if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) { ide_kill_rq(drive, rq); return ide_stopped; } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) 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.b.recalibrate = 1; ++rq->errors; return ide_stopped;}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 & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; } else { /* add decoding error stuff */ } if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); 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;}ide_startstop_t__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err){ if (drive->media == ide_disk) return ide_ata_error(drive, rq, stat, err); return ide_atapi_error(drive, rq, stat, err);}EXPORT_SYMBOL_GPL(__ide_error);/** * ide_error - handle an error on the IDE * @drive: drive the error occurred on * @msg: message to report * @stat: status bits * * ide_error() takes action based on the error returned by the drive. * For normal I/O that may well include retries. We deal with * both new-style (taskfile) and old style command handling here. * In the case of taskfile command handling there is work left to * do */ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat){ struct request *rq; u8 err; err = ide_dump_status(drive, msg, stat); if ((rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, stat, err); return ide_stopped; } if (rq->rq_disk) { ide_driver_t *drv; drv = *(ide_driver_t **)rq->rq_disk->private_data; return drv->error(drive, rq, stat, err); } else return __ide_error(drive, rq, stat, err);}EXPORT_SYMBOL_GPL(ide_error);ide_startstop_t __ide_abort(ide_drive_t *drive, struct request *rq){ if (drive->media != ide_disk) rq->errors |= ERROR_RESET; ide_kill_rq(drive, rq); return ide_stopped;}EXPORT_SYMBOL_GPL(__ide_abort);/** * ide_abort - abort pending IDE operations * @drive: drive the error occurred on * @msg: message to report * * ide_abort kills and cleans up when we are about to do a * host initiated reset on active commands. Longer term we * want handlers to have sensible abort handling themselves * * This differs fundamentally from ide_error because in * this case the command is doing just fine when we * blow it away. */ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg){ struct request *rq; if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) return ide_stopped; /* retry only "normal" I/O: */ if (!blk_fs_request(rq)) { rq->errors = 1; ide_end_drive_cmd(drive, BUSY_STAT, 0); return ide_stopped; } if (rq->rq_disk) { ide_driver_t *drv; drv = *(ide_driver_t **)rq->rq_disk->private_data; return drv->abort(drive, rq); } else return __ide_abort(drive, rq);}/** * ide_cmd - issue a simple drive command * @drive: drive the command is for * @cmd: command byte * @nsect: sector byte * @handler: handler for the command completion * * Issue a simple drive command with interrupts. * The drive must be selected beforehand. */static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler){ ide_hwif_t *hwif = HWIF(drive); if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(drive,0); hwif->OUTB(nsect,IDE_NSECTOR_REG); ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL);}/** * drive_cmd_intr - drive command completion interrupt * @drive: drive the completion interrupt occurred on * * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. * We do any necessary data reading and then wait for the drive to * go non busy. At that point we may read the error data and complete * the request */ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); u8 *args = (u8 *) rq->buffer; u8 stat = hwif->INB(IDE_STATUS_REG); int retries = 10; local_irq_enable_in_hardirq(); if (rq->cmd_type == REQ_TYPE_ATA_CMD && (stat & DRQ_STAT) && args && args[3]) { u8 io_32bit = drive->io_32bit; drive->io_32bit = 0; hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) udelay(100); } if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); return ide_stopped;}static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task){ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; task->tfRegister[IDE_SECTOR_OFFSET] = drive->sect; task->tfRegister[IDE_LCYL_OFFSET] = drive->cyl; task->tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; task->tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; task->handler = &set_geometry_intr;}static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task){ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; task->handler = &recal_intr;}static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task){ task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; task->handler = &set_multmode_intr;}static ide_startstop_t ide_disk_special(ide_drive_t *drive){ special_t *s = &drive->special; ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); args.command_type = IDE_DRIVE_TASK_NO_DATA; if (s->b.set_geometry) { s->b.set_geometry = 0; ide_init_specify_cmd(drive, &args); } else if (s->b.recalibrate) { s->b.recalibrate = 0; ide_init_restore_cmd(drive, &args); } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; ide_init_setmult_cmd(drive, &args); } else if (s->all) { int special = s->all; s->all = 0; printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, special); return ide_stopped; } do_rw_taskfile(drive, &args); return ide_started;}/* * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away */static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio){ switch (req_pio) { case 202: case 201: case 200: case 102: case 101: case 100: return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; case 9: case 8: return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; case 7: case 6: return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; default: return 0; }}/** * do_special - issue some special commands * @drive: drive the command is for * * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * commands to a drive. It used to do much more, but has been scaled * back. */static ide_startstop_t do_special (ide_drive_t *drive){ special_t *s = &drive->special;#ifdef DEBUG printk("%s: do_special: 0x%02x\n", drive->name, s->all);#endif if (s->b.set_tune) { ide_hwif_t *hwif = drive->hwif; u8 req_pio = drive->tune_req; s->b.set_tune = 0; if (set_pio_mode_abuse(drive->hwif, req_pio)) { if (hwif->set_pio_mode == NULL) return ide_stopped; /* * take ide_lock for drive->[no_]unmask/[no_]io_32bit */ if (req_pio == 8 || req_pio == 9) { unsigned long flags; spin_lock_irqsave(&ide_lock, flags); hwif->set_pio_mode(drive, req_pio); spin_unlock_irqrestore(&ide_lock, flags); } else hwif->set_pio_mode(drive, req_pio); } else { int keep_dma = drive->using_dma; ide_set_pio(drive, req_pio); if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { if (keep_dma) hwif->ide_dma_on(drive); } } return ide_stopped; } else { if (drive->media == ide_disk) return ide_disk_special(drive); s->all = 0; drive->mult_req = 0; return ide_stopped; }}void ide_map_sg(ide_drive_t *drive, struct request *rq){ ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; if (hwif->sg_mapped) /* needed by ide-scsi */ return; if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) { hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg); } else { sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE); hwif->sg_nents = 1; }}EXPORT_SYMBOL_GPL(ide_map_sg);void ide_init_sg_cmd(ide_drive_t *drive, struct request *rq){ ide_hwif_t *hwif = drive->hwif; hwif->nsect = hwif->nleft = rq->nr_sectors; hwif->cursg_ofs = 0; hwif->cursg = NULL;}EXPORT_SYMBOL_GPL(ide_init_sg_cmd);/** * execute_drive_command - issue special drive command * @drive: the drive to issue the command on * @rq: the request structure holding the command * * execute_drive_cmd() issues a special drive command, usually * initiated by ioctl() from the external hdparm program. The * command can be a drive command, drive task or taskfile * operation. Weirdly you can call it with NULL to wait for * all commands to finish. Don't do this as that is due to change */static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq){ ide_hwif_t *hwif = HWIF(drive); if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = rq->special; if (!args) goto done; hwif->data_phase = args->data_phase; switch (hwif->data_phase) { case TASKFILE_MULTI_OUT: case TASKFILE_OUT: case TASKFILE_MULTI_IN: case TASKFILE_IN: ide_init_sg_cmd(drive, rq); ide_map_sg(drive, rq); default: break; } if (args->tf_out_flags.all != 0) return flagged_taskfile(drive, args); return do_rw_taskfile(drive, args); } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { u8 *args = rq->buffer; if (!args) goto done;#ifdef DEBUG printk("%s: DRIVE_TASK_CMD ", drive->name); printk("cmd=0x%02x ", args[0]); printk("fr=0x%02x ", args[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -