📄 ide-floppy.c
字号:
unsigned ansi_version :3; /* ANSI Version */ unsigned ecma_version :3; /* ECMA Version */ unsigned iso_version :2; /* ISO Version */ unsigned response_format :4; /* Response Data Format */ unsigned reserved3_45 :2; /* Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_7 :1; /* AENC - Reserved */#elif defined(__BIG_ENDIAN_BITFIELD) unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ unsigned device_type :5; /* Peripheral Device Type */ unsigned rmb :1; /* Removable Medium Bit */ unsigned reserved1_6t0 :7; /* Reserved */ unsigned iso_version :2; /* ISO Version */ unsigned ecma_version :3; /* ECMA Version */ unsigned ansi_version :3; /* ANSI Version */ unsigned reserved3_7 :1; /* AENC - Reserved */ unsigned reserved3_6 :1; /* TrmIOP - Reserved */ unsigned reserved3_45 :2; /* Reserved */ unsigned response_format :4; /* Response Data Format */#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u8 additional_length; /* Additional Length (total_length-4) */ u8 rsv5, rsv6, rsv7; /* Reserved */ u8 vendor_id[8]; /* Vendor Identification */ u8 product_id[16]; /* Product Identification */ u8 revision_level[4]; /* Revision Level */ u8 vendor_specific[20]; /* Vendor Specific - Optional */ u8 reserved56t95[40]; /* Reserved - Optional */ /* Additional information may be returned */} idefloppy_inquiry_result_t;/* * REQUEST SENSE packet command result - Data Format. */typedef struct {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned error_code :7; /* Current error (0x70) */ unsigned valid :1; /* The information field conforms to SFF-8070i */ u8 reserved1 :8; /* Reserved */ unsigned sense_key :4; /* Sense Key */ unsigned reserved2_4 :1; /* Reserved */ unsigned ili :1; /* Incorrect Length Indicator */ unsigned reserved2_67 :2;#elif defined(__BIG_ENDIAN_BITFIELD) unsigned valid :1; /* The information field conforms to SFF-8070i */ unsigned error_code :7; /* Current error (0x70) */ u8 reserved1 :8; /* Reserved */ unsigned reserved2_67 :2; unsigned ili :1; /* Incorrect Length Indicator */ unsigned reserved2_4 :1; /* Reserved */ unsigned sense_key :4; /* Sense Key */#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u32 information __attribute__ ((packed)); u8 asl; /* Additional sense length (n-7) */ u32 command_specific; /* Additional command specific information */ u8 asc; /* Additional Sense Code */ u8 ascq; /* Additional Sense Code Qualifier */ u8 replaceable_unit_code; /* Field Replaceable Unit Code */ u8 sksv[3]; u8 pad[2]; /* Padding to 20 bytes */} idefloppy_request_sense_result_t;/* * Pages of the SELECT SENSE / MODE SENSE packet commands. */#define IDEFLOPPY_CAPABILITIES_PAGE 0x1b#define IDEFLOPPY_FLEXIBLE_DISK_PAGE 0x05/* * Mode Parameter Header for the MODE SENSE packet command */typedef struct { u16 mode_data_length; /* Length of the following data transfer */ u8 medium_type; /* Medium Type */#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned reserved3 :7; unsigned wp :1; /* Write protect */#elif defined(__BIG_ENDIAN_BITFIELD) unsigned wp :1; /* Write protect */ unsigned reserved3 :7;#else#error "Bitfield endianness not defined! Check your byteorder.h"#endif u8 reserved[4];} idefloppy_mode_parameter_header_t;#define IDEFLOPPY_MIN(a,b) ((a)<(b) ? (a):(b))#define IDEFLOPPY_MAX(a,b) ((a)>(b) ? (a):(b))/* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. */static void idefloppy_discard_data (ide_drive_t *drive, unsigned int bcount){ while (bcount--) (void) HWIF(drive)->INB(IDE_DATA_REG);}#if IDEFLOPPY_DEBUG_BUGSstatic void idefloppy_write_zeros (ide_drive_t *drive, unsigned int bcount){ while (bcount--) HWIF(drive)->OUTB(0, IDE_DATA_REG);}#endif /* IDEFLOPPY_DEBUG_BUGS */static int idefloppy_end_request (ide_drive_t *drive, int uptodate){ struct request *rq; unsigned long flags; int ret = 1; spin_lock_irqsave(&io_request_lock, flags); rq = HWGROUP(drive)->rq; /* * decide whether to reenable DMA -- 3 is a random magic for now, * if we DMA timeout more than 3 times, just stay in PIO */ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { drive->state = 0; HWGROUP(drive)->hwif->ide_dma_on(drive); } if (!end_that_request_first(rq, uptodate, drive->name)) { add_blkdev_randomness(MAJOR(rq->rq_dev)); blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; end_that_request_last(rq); ret = 0; } spin_unlock_irqrestore(&io_request_lock, flags); return ret;}/* * idefloppy_do_end_request is used to finish servicing a request. * * For read/write requests, we will call ide_end_request to pass to the * next buffer. */static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate){ idefloppy_floppy_t *floppy = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; int error;#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "Reached idefloppy_end_request\n");#endif /* IDEFLOPPY_DEBUG_LOG */ switch (uptodate) { case 0: error = IDEFLOPPY_ERROR_GENERAL; break; case 1: error = 0; break; default: error = uptodate; } if (error) floppy->failed_pc = NULL; /* Why does this happen? */ if (!rq) return 0; if (!IDEFLOPPY_RQ_CMD(rq->cmd)) { /* our real local end request function */ idefloppy_end_request(drive, uptodate); return 0; } rq->errors = error; /* fixme: need to move this local also */ ide_end_drive_cmd(drive, 0, 0); return 0;}static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount){ struct request *rq = pc->rq; struct buffer_head *bh = rq->bh; int count; while (bcount) { if (pc->b_count == bh->b_size) { rq->sector += rq->current_nr_sectors; rq->nr_sectors -= rq->current_nr_sectors; idefloppy_do_end_request(drive, 1); if ((bh = rq->bh) != NULL) pc->b_count = 0; } if (bh == NULL) { printk(KERN_ERR "%s: bh == NULL in " "idefloppy_input_buffers, bcount == %d\n", drive->name, bcount); idefloppy_discard_data(drive, bcount); return; } count = IDEFLOPPY_MIN(bh->b_size - pc->b_count, bcount); HWIF(drive)->atapi_input_bytes(drive, bh->b_data + pc->b_count, count); bcount -= count; pc->b_count += count; }}static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount){ struct request *rq = pc->rq; struct buffer_head *bh = rq->bh; int count; while (bcount) { if (!pc->b_count) { rq->sector += rq->current_nr_sectors; rq->nr_sectors -= rq->current_nr_sectors; idefloppy_do_end_request(drive, 1); if ((bh = rq->bh) != NULL) { pc->b_data = bh->b_data; pc->b_count = bh->b_size; } } if (bh == NULL) { printk(KERN_ERR "%s: bh == NULL in " "idefloppy_output_buffers, bcount == %d\n", drive->name, bcount); idefloppy_write_zeros (drive, bcount); return; } count = IDEFLOPPY_MIN(pc->b_count, bcount); HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count); bcount -= count; pc->b_data += count; pc->b_count -= count; }}#ifdef CONFIG_BLK_DEV_IDEDMAstatic void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc){ struct request *rq = pc->rq; struct buffer_head *bh = rq->bh; while ((bh = rq->bh) != NULL) idefloppy_do_end_request(drive, 1);}#endif /* CONFIG_BLK_DEV_IDEDMA *//* * idefloppy_queue_pc_head generates a new packet command request in front * of the request queue, before the current request, so that it will be * processed immediately, on the next pass through the driver. */static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq){ ide_init_drive_cmd(rq); rq->buffer = (char *)pc; rq->cmd = IDEFLOPPY_PC_RQ; (void) ide_do_drive_cmd(drive, rq, ide_preempt);}static idefloppy_pc_t *idefloppy_next_pc_storage (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; if (floppy->pc_stack_index == IDEFLOPPY_PC_STACK) floppy->pc_stack_index=0; return (&floppy->pc_stack[floppy->pc_stack_index++]);}static struct request *idefloppy_next_rq_storage (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; if (floppy->rq_stack_index == IDEFLOPPY_PC_STACK) floppy->rq_stack_index = 0; return (&floppy->rq_stack[floppy->rq_stack_index++]);}/* * idefloppy_analyze_error is called on each failed packet command retry * to analyze the request sense. */static void idefloppy_analyze_error (ide_drive_t *drive,idefloppy_request_sense_result_t *result){ idefloppy_floppy_t *floppy = drive->driver_data; floppy->sense_key = result->sense_key; floppy->asc = result->asc; floppy->ascq = result->ascq; floppy->progress_indication = result->sksv[0] & 0x80 ? (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000;#if IDEFLOPPY_DEBUG_LOG if (floppy->failed_pc) printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, " "asc = %x, ascq = %x\n", floppy->failed_pc->c[0], result->sense_key, result->asc, result->ascq); else printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, " "ascq = %x\n", result->sense_key, result->asc, result->ascq);#endif /* IDEFLOPPY_DEBUG_LOG */}static void idefloppy_request_sense_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data;#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);#endif /* IDEFLOPPY_DEBUG_LOG */ if (!floppy->pc->error) { idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); idefloppy_do_end_request(drive, 1); } else { printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); idefloppy_do_end_request(drive, 0); }}/* * General packet command callback function. */static void idefloppy_pc_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; #if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__);#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);}/* * idefloppy_init_pc initializes a packet command. */static void idefloppy_init_pc (idefloppy_pc_t *pc){ memset(pc->c, 0, 12); pc->retries = 0; pc->flags = 0; pc->request_transfer = 0; pc->buffer = pc->pc_buffer; pc->buffer_size = IDEFLOPPY_PC_BUFFER_SIZE; pc->b_data = NULL; pc->callback = &idefloppy_pc_callback;}static void idefloppy_create_request_sense_cmd (idefloppy_pc_t *pc){ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_REQUEST_SENSE_CMD; pc->c[4] = 255; pc->request_transfer = 18; pc->callback = &idefloppy_request_sense_callback;}/* * idefloppy_retry_pc is called when an error was detected during the * last packet command. We queue a request sense packet command in * the head of the request list. */static void idefloppy_retry_pc (ide_drive_t *drive){ idefloppy_pc_t *pc; struct request *rq; atapi_error_t error; error.all = HWIF(drive)->INB(IDE_ERROR_REG); pc = idefloppy_next_pc_storage(drive); rq = idefloppy_next_rq_storage(drive); idefloppy_create_request_sense_cmd(pc); idefloppy_queue_pc_head(drive, pc, rq);}/* * idefloppy_pc_intr is the usual interrupt handler which will be called * during a packet command. */static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; atapi_status_t status; atapi_bcount_t bcount; atapi_ireason_t ireason; idefloppy_pc_t *pc = floppy->pc; struct request *rq = pc->rq; unsigned int temp;#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__);#endif /* IDEFLOPPY_DEBUG_LOG */ #ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (HWIF(drive)->ide_dma_end(drive)) { set_bit(PC_DMA_ERROR, &pc->flags); } else { pc->actually_transferred = pc->request_transfer; idefloppy_update_buffers(drive, pc); }#if IDEFLOPPY_DEBUG_LOG printk (KERN_INFO "ide-floppy: DMA finished\n");#endif /* IDEFLOPPY_DEBUG_LOG */ }#endif /* CONFIG_BLK_DEV_IDEDMA */ /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!status.b.drq) { /* No more interrupts */#if IDEFLOPPY_DEBUG_LOG printk(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred);#endif /* IDEFLOPPY_DEBUG_LOG */ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -