📄 ide-floppy.c
字号:
if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "ide-floppy: %s: I/O error\n", drive->name);#endif /* IDEFLOPPY_DEBUG_LOG */ rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk(KERN_ERR "ide-floppy: I/O error in " "request sense command\n"); return ide_do_reset(drive); } /* Retry operation */ idefloppy_retry_pc(drive); /* queued, but not started */ return ide_stopped; } pc->error = 0; if (floppy->failed_pc == pc) floppy->failed_pc = NULL; /* Command finished - Call the callback function */ pc->callback(drive); return ide_stopped; }#ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-floppy: The floppy wants to issue " "more interrupts in DMA mode\n"); (void) HWIF(drive)->ide_dma_off(drive); return ide_do_reset(drive); }#endif /* CONFIG_BLK_DEV_IDEDMA */ /* Get the number of bytes to transfer */ bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); /* on this interrupt */ ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); if (ireason.b.cod) { printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n"); return ide_do_reset(drive); } if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk(KERN_ERR "ide-floppy: We wanted to %s, ", ireason.b.io ? "Write":"Read"); printk(KERN_ERR "but the floppy wants us to %s !\n", ireason.b.io ? "Read":"Write"); return ide_do_reset(drive); } if (!test_bit(PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ temp = pc->actually_transferred + bcount.all; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); idefloppy_discard_data(drive,bcount.all); if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); return ide_started; }#if IDEFLOPPY_DEBUG_LOG printk(KERN_NOTICE "ide-floppy: The floppy wants to " "send us more data than expected - " "allowing transfer\n");#endif /* IDEFLOPPY_DEBUG_LOG */ } } if (test_bit(PC_WRITING, &pc->flags)) { if (pc->buffer != NULL) /* Write the current buffer */ HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); else idefloppy_output_buffers(drive, pc, bcount.all); } else { if (pc->buffer != NULL) /* Read the current buffer */ HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); else idefloppy_input_buffers(drive, pc, bcount.all); } /* Update the current position */ pc->actually_transferred += bcount.all; pc->current_position += bcount.all; if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started;}/* * This is the original routine that did the packet transfer. * It fails at high speeds on the Iomega ZIP drive, so there's a slower version * for that drive below. The algorithm is chosen based on drive type */static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive){ ide_startstop_t startstop; idefloppy_floppy_t *floppy = drive->driver_data; atapi_ireason_t ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset(drive); } if (HWGROUP(drive)->handler != NULL) BUG(); /* Set the interrupt routine */ ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Send the actual packet */ HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); return ide_started;}/* * What we have here is a classic case of a top half / bottom half * interrupt service routine. In interrupt mode, the device sends * an interrupt to signal it's ready to receive a packet. However, * we need to delay about 2-3 ticks before issuing the packet or we * gets in trouble. * * So, follow carefully. transfer_pc1 is called as an interrupt (or * directly). In either case, when the device says it's ready for a * packet, we schedule the packet transfer to occur about 2-3 ticks * later in transfer_pc2. */static int idefloppy_transfer_pc2 (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; /* Send the actual packet */ HWIF(drive)->atapi_output_bytes(drive, floppy->pc->c, 12); /* Timeout for the packet command */ return IDEFLOPPY_WAIT_CMD;}static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; ide_startstop_t startstop; atapi_ireason_t ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); if (!ireason.b.cod || ireason.b.io) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) " "while issuing a packet command\n"); return ide_do_reset(drive); } /* * The following delay solves a problem with ATAPI Zip 100 drives * where the Busy flag was apparently being deasserted before the * unit was ready to receive data. This was happening on a * 1200 MHz Athlon system. 10/26/01 25msec is too short, * 40 and 50msec work well. idefloppy_pc_intr will not be actually * used until after the packet is moved in about 50 msec. */ if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &idefloppy_pc_intr, /* service routine for packet command */ floppy->ticks, /* wait this long before "failing" */ &idefloppy_transfer_pc2); /* fail == transfer_pc2 */ return ide_started;}/* * Issue a packet command */static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *pc){ idefloppy_floppy_t *floppy = drive->driver_data; atapi_feature_t feature; atapi_bcount_t bcount; ide_handler_t *pkt_xfer_routine;#if IDEFLOPPY_DEBUG_BUGS if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - " "Two request sense in serial were issued\n"); }#endif /* IDEFLOPPY_DEBUG_BUGS */ if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD) floppy->failed_pc = pc; /* Set the current packet command */ floppy->pc = pc; if (pc->retries > IDEFLOPPY_MAX_PC_RETRIES || test_bit(PC_ABORT, &pc->flags)) { /* * We will "abort" retrying a packet command in case * a legitimate error code was received. */ if (!test_bit(PC_ABORT, &pc->flags)) { if (!test_bit(PC_SUPPRESS_ERROR, &pc->flags)) { printk(KERN_ERR "ide-floppy: %s: I/O error, " "pc = %2x, key = %2x, " "asc = %2x, ascq = %2x\n", drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq); } /* Giving up */ pc->error = IDEFLOPPY_ERROR_GENERAL; } floppy->failed_pc = NULL; pc->callback(drive); return ide_stopped; }#if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "Retry number - %d\n", pc->retries);#endif /* IDEFLOPPY_DEBUG_LOG */ pc->retries++; /* We haven't transferred any data yet */ pc->actually_transferred = 0; pc->current_position = pc->buffer; bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);#ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { (void) HWIF(drive)->ide_dma_off(drive); }#endif /* CONFIG_BLK_DEV_IDEDMA */ feature.all = 0;#ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) { if (test_bit(PC_WRITING, &pc->flags)) { feature.b.dma = !HWIF(drive)->ide_dma_write(drive); } else { feature.b.dma = !HWIF(drive)->ide_dma_read(drive); } }#endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); /* Use PIO/DMA */ HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);#ifdef CONFIG_BLK_DEV_IDEDMA if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->ide_dma_begin(drive)); }#endif /* CONFIG_BLK_DEV_IDEDMA */ /* Can we transfer the packet when we get the interrupt or wait? */ if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) { /* wait */ pkt_xfer_routine = &idefloppy_transfer_pc1; } else { /* immediate */ pkt_xfer_routine = &idefloppy_transfer_pc; } if (test_bit(IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { /* Issue the packet command */ ide_execute_command(drive, WIN_PACKETCMD, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL); return ide_started; } else { /* Issue the packet command */ HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG); return (*pkt_xfer_routine) (drive); }}static void idefloppy_rw_callback (ide_drive_t *drive){#if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_do_end_request(drive, 1); return;}static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent){#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "ide-floppy: creating prevent removal command, " "prevent = %d\n", prevent);#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD; pc->c[4] = prevent;}static void idefloppy_create_read_capacity_cmd (idefloppy_pc_t *pc){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD; pc->c[7] = 255; pc->c[8] = 255; pc->request_transfer = 255;}static void idefloppy_create_format_unit_cmd (idefloppy_pc_t *pc, int b, int l, int flags){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_FORMAT_UNIT_CMD; pc->c[1] = 0x17; memset(pc->buffer, 0, 12); pc->buffer[1] = 0xA2; /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ if (flags & 1) /* Verify bit on... */ pc->buffer[1] ^= 0x20; /* ... turn off DCRT bit */ pc->buffer[3] = 8; put_unaligned(htonl(b), (unsigned int *)(&pc->buffer[4])); put_unaligned(htonl(l), (unsigned int *)(&pc->buffer[8])); pc->buffer_size=12; set_bit(PC_WRITING, &pc->flags);}/* * A mode sense command is used to "sense" floppy parameters. */static void idefloppy_create_mode_sense_cmd (idefloppy_pc_t *pc, u8 page_code, u8 type){ u16 length = sizeof(idefloppy_mode_parameter_header_t); idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_MODE_SENSE_CMD; pc->c[1] = 0; pc->c[2] = page_code + (type << 6); switch (page_code) { case IDEFLOPPY_CAPABILITIES_PAGE: length += 12; break; case IDEFLOPPY_FLEXIBLE_DISK_PAGE: length += 32; break; default: printk(KERN_ERR "ide-floppy: unsupported page code " "in create_mode_sense_cmd\n"); } put_unaligned(htons(length), (u16 *) &pc->c[7]); pc->request_transfer = length;}static void idefloppy_create_start_stop_cmd (idefloppy_pc_t *pc, int start){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_START_STOP_CMD; pc->c[4] = start;}static void idefloppy_create_test_unit_ready_cmd(idefloppy_pc_t *pc){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_TEST_UNIT_READY_CMD;}static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq, unsigned long sector){ int block = sector / floppy->bs_factor; int blocks = rq->nr_sectors / floppy->bs_factor; #if IDEFLOPPY_DEBUG_LOG printk("create_rw1%d_cmd: block == %d, blocks == %d\n", 2 * test_bit(IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks);#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_init_pc(pc); if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) { pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ12_CMD : IDEFLOPPY_WRITE12_CMD; put_unaligned(htonl(blocks), (unsigned int *) &pc->c[6]); } else { pc->c[0] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD; put_unaligned(htons(blocks), (u16 *) &pc->c[7]); } put_unaligned(htonl(block), (unsigned int *) &pc->c[2]); pc->callback = &idefloppy_rw_callback; pc->rq = rq; pc->b_data = rq->buffer; pc->b_count = rq->cmd == READ ? 0 : rq->bh->b_size; if (rq->cmd == WRITE) set_bit(PC_WRITING, &pc->flags); pc->buffer = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -