?? ide-taskfile.c
字號:
rq->errors |= ERROR_RESET; } else { if (drive->media != ide_disk) goto media_out; if (stat & ERR_STAT) { /* err has different meaning on cdrom and tape */ if (err == ABRT_ERR) { if (drive->select.b.lba && (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)) /* some newer drives don't * support 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; } }media_out: if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE) task_try_to_flush_leftover_data(drive); } 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) { DRIVER(drive)->end_request(drive, 0); } else { 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;}EXPORT_SYMBOL(taskfile_error);/* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ide_startstop_t set_multmode_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 stat; if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { drive->mult_count = drive->mult_req; } else { drive->mult_req = drive->mult_count = 0; drive->special.b.recalibrate = 1; (void) ide_dump_status(drive, "set_multmode", stat); } return ide_stopped;}EXPORT_SYMBOL(set_multmode_intr);/* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ide_startstop_t set_geometry_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); int retries = 5; u8 stat; while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) udelay(10); if (OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_stopped; if (stat & (ERR_STAT|DRQ_STAT)) return DRIVER(drive)->error(drive, "set_geometry_intr", stat); if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL); return ide_started;}EXPORT_SYMBOL(set_geometry_intr);/* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ide_startstop_t recal_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) return DRIVER(drive)->error(drive, "recal_intr", stat); return ide_stopped;}EXPORT_SYMBOL(recal_intr);/* * Handler for commands without a data phase */ide_startstop_t task_no_data_intr (ide_drive_t *drive){ ide_task_t *args = HWGROUP(drive)->rq->special; ide_hwif_t *hwif = HWIF(drive); u8 stat; local_irq_enable(); if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { DTF("%s: command opcode 0x%02x\n", drive->name, args->tfRegister[IDE_COMMAND_OFFSET]); return DRIVER(drive)->error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ } if (args) ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); return ide_stopped;}EXPORT_SYMBOL(task_no_data_intr);/* * Handler for command with PIO data-in phase, READ *//* * FIXME before 2.4 enable ... * DATA integrity issue upon error. <andre@linux-ide.org> */ide_startstop_t task_in_intr (ide_drive_t *drive){ struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); char *pBuf = NULL; u8 stat; unsigned long flags; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) {#if 0 DTF("%s: attempting to recover last " \ "sector counter status=0x%02x\n", drive->name, stat); /* * Expect a BUG BOMB if we attempt to rewind the * offset in the BH aka PAGE in the current BLOCK * segment. This is different than the HOST segment. */#endif if (!rq->bh) rq->current_nr_sectors++; return DRIVER(drive)->error(drive, "task_in_intr", stat); } if (!(stat & BUSY_STAT)) { DTF("task_in_intr to Soon wait for next interrupt\n"); if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; } }#if 0 /* * Holding point for a brain dump of a thought :-/ */ if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { DTF("%s: READ attempting to recover last " \ "sector counter status=0x%02x\n", drive->name, stat); rq->current_nr_sectors++; return DRIVER(drive)->error(drive, "task_in_intr", stat); } if (!rq->current_nr_sectors) if (!DRIVER(drive)->end_request(drive, 1)) return ide_stopped; if (--rq->current_nr_sectors <= 0) if (!DRIVER(drive)->end_request(drive, 1)) return ide_stopped;#endif pBuf = task_map_rq(rq, &flags); DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n", pBuf, (int) rq->current_nr_sectors, stat); taskfile_input_data(drive, pBuf, SECTOR_WORDS); task_unmap_rq(rq, pBuf, &flags); /* * FIXME :: We really can not legally get a new page/bh * regardless, if this is the end of our segment. * BH walking or segment can only be updated after we have a good * hwif->INB(IDE_STATUS_REG); return. */ if (--rq->current_nr_sectors <= 0) if (!DRIVER(drive)->end_request(drive, 1)) return ide_stopped; /* * ERM, it is techincally legal to leave/exit here but it makes * a mess of the code ... */ if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started;}EXPORT_SYMBOL(task_in_intr);/* * Handler for command with Read Multiple */ide_startstop_t task_mulin_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; unsigned int msect = drive->mult_count; unsigned int nsect; unsigned long flags; u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { if (!rq->bh) { rq->current_nr_sectors += drive->mult_count; /* * NOTE: could rewind beyond beginning :-/ */ } else { printk("%s: MULTI-READ assume all data " \ "transfered is bad status=0x%02x\n", drive->name, stat); } return DRIVER(drive)->error(drive, "task_mulin_intr", stat); } /* no data yet, so wait for another interrupt */ if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); return ide_started; } do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; pBuf = task_map_rq(rq, &flags); DTF("Multiread: %p, nsect: %d, msect: %d, " \ " rq->current_nr_sectors: %d\n", pBuf, nsect, msect, rq->current_nr_sectors); taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors -= nsect; msect -= nsect; /* * FIXME :: We really can not legally get a new page/bh * regardless, if this is the end of our segment. * BH walking or segment can only be updated after we have a * good hwif->INB(IDE_STATUS_REG); return. */ if (!rq->current_nr_sectors) { if (!DRIVER(drive)->end_request(drive, 1)) return ide_stopped; } } while (msect); if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); return ide_started;}EXPORT_SYMBOL(task_mulin_intr);/* * VERIFY ME before 2.4 ... unexpected race is possible based on details * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. */ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq){ char *pBuf = NULL; unsigned long flags; ide_startstop_t startstop; if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", drive->name, drive->addressing ? "_EXT" : ""); return startstop; } /* For Write_sectors we need to stuff the first sector */ pBuf = task_map_rq(rq, &flags); taskfile_output_data(drive, pBuf, SECTOR_WORDS); rq->current_nr_sectors--; task_unmap_rq(rq, pBuf, &flags); return ide_started;}EXPORT_SYMBOL(pre_task_out_intr);/* * Handler for command with PIO data-out phase WRITE * * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org> */ide_startstop_t task_out_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; unsigned long flags; u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) { DTF("%s: WRITE attempting to recover last " \ "sector counter status=0x%02x\n", drive->name, stat); rq->current_nr_sectors++; return DRIVER(drive)->error(drive, "task_out_intr", stat); } /* * Safe to update request for partial completions. * We have a good STATUS CHECK!!! */ if (!rq->current_nr_sectors) if (!DRIVER(drive)->end_request(drive, 1)) return ide_stopped; if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { rq = HWGROUP(drive)->rq; pBuf = task_map_rq(rq, &flags); DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); taskfile_output_data(drive, pBuf, SECTOR_WORDS); task_unmap_rq(rq, pBuf, &flags); rq->errors = 0; rq->current_nr_sectors--; } if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); return ide_started;}EXPORT_SYMBOL(task_out_intr);#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUTide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq){#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT ide_hwif_t *hwif = HWIF(drive); char *pBuf = NULL; unsigned int nsect = 0, msect = drive->mult_count; u8 stat; unsigned long flags;#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ ide_task_t *args = rq->special; ide_startstop_t startstop;#if 0 /* * assign private copy for multi-write */ memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));#endif if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); return startstop; }#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; pBuf = task_map_rq(rq, &flags); DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \ "rq->current_nr_sectors: %ld\n", pBuf, nsect, msect, rq->current_nr_sectors); msect -= nsect; taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); task_unmap_rq(rq, pBuf, &flags); rq->current_nr_sectors -= nsect; if (!rq->current_nr_sectors) { if (!DRIVER(drive)->end_request(drive, 1)) if (!rq->bh) { stat = hwif->INB(IDE_STATUS_REG); return ide_stopped; } } } while (msect); rq->errors = 0; return ide_started;#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ if (!(drive_is_ready(drive))) { int i; for (i=0; i<100; i++) { if (drive_is_ready(drive)) break; } } /* * WARNING :: if the drive as not acked good status we may not * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org> */ return args->handler(drive);#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */}EXPORT_SYMBOL(pre_task_mulout_intr);/* * FIXME before enabling in 2.4 ... DATA integrity issue upon error. *//* * Handler for command write multiple * Called directly from execute_drive_cmd for the first bunch of sectors, * afterwards only by the ISR */ide_startstop_t task_mulout_intr (ide_drive_t *drive){ ide_hwif_t *hwif = HWIF(drive); u8 stat = hwif->INB(IDE_STATUS_REG); struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; ide_startstop_t startstop = ide_stopped; unsigned int msect = drive->mult_count; unsigned int nsect; unsigned long flags; /* * (ks/hs): Handle last IRQ on multi-sector transfer, * occurs after all data was sent in this chunk */ if (rq->current_nr_sectors == 0) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -