📄 ide-floppy.c
字号:
};/* * INQUIRY packet command - Data Format */typedef struct {#if defined(__LITTLE_ENDIAN_BITFIELD) unsigned device_type :5; /* Peripheral Device Type */ unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ unsigned reserved1_6t0 :7; /* Reserved */ unsigned rmb :1; /* Removable Medium Bit */ 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;static DEFINE_MUTEX(idefloppy_ref_mutex);#define to_ide_floppy(obj) container_of(obj, struct ide_floppy_obj, kref)#define ide_floppy_g(disk) \ container_of((disk)->private_data, struct ide_floppy_obj, driver)static struct ide_floppy_obj *ide_floppy_get(struct gendisk *disk){ struct ide_floppy_obj *floppy = NULL; mutex_lock(&idefloppy_ref_mutex); floppy = ide_floppy_g(disk); if (floppy) kref_get(&floppy->kref); mutex_unlock(&idefloppy_ref_mutex); return floppy;}static void ide_floppy_release(struct kref *);static void ide_floppy_put(struct ide_floppy_obj *floppy){ mutex_lock(&idefloppy_ref_mutex); kref_put(&floppy->kref, ide_floppy_release); mutex_unlock(&idefloppy_ref_mutex);}/* * 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 *//* * 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, int nsecs){ idefloppy_floppy_t *floppy = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; int error; debug_log(KERN_INFO "Reached idefloppy_end_request\n"); 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 (!blk_special_request(rq)) { /* our real local end request function */ ide_end_request(drive, uptodate, nsecs); 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 bio_vec *bvec; struct req_iterator iter; unsigned long flags; char *data; int count, done = 0; rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); drive->hwif->atapi_input_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; pc->b_count += count; done += count; } idefloppy_do_end_request(drive, 1, done >> 9); if (bcount) { printk(KERN_ERR "%s: leftover data in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount); idefloppy_discard_data(drive, bcount); }}static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount){ struct request *rq = pc->rq; struct req_iterator iter; struct bio_vec *bvec; unsigned long flags; int count, done = 0; char *data; rq_for_each_segment(bvec, rq, iter) { if (!bcount) break; count = min(bvec->bv_len, bcount); data = bvec_kmap_irq(bvec, &flags); drive->hwif->atapi_output_bytes(drive, data, count); bvec_kunmap_irq(data, &flags); bcount -= count; pc->b_count += count; done += count; } idefloppy_do_end_request(drive, 1, done >> 9);#if IDEFLOPPY_DEBUG_BUGS if (bcount) { printk(KERN_ERR "%s: leftover data in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount); idefloppy_write_zeros(drive, bcount); }#endif}static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc){ struct request *rq = pc->rq; struct bio *bio = rq->bio; while ((bio = rq->bio) != NULL) idefloppy_do_end_request(drive, 1, 0);}/* * 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){ struct ide_floppy_obj *floppy = drive->driver_data; ide_init_drive_cmd(rq); rq->buffer = (char *) pc; rq->cmd_type = REQ_TYPE_SPECIAL; rq->rq_disk = floppy->disk; (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 (floppy->failed_pc) debug_log(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 debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, " "ascq = %x\n", result->sense_key, result->asc, result->ascq);}static void idefloppy_request_sense_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); if (!floppy->pc->error) { idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); idefloppy_do_end_request(drive, 1, 0); } else { printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n"); idefloppy_do_end_request(drive, 0, 0); }}/* * General packet command callback function. */static void idefloppy_pc_callback (ide_drive_t *drive){ idefloppy_floppy_t *floppy = drive->driver_data; debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0);}/* * 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->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; debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__); 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); } debug_log(KERN_INFO "ide-floppy: DMA finished\n"); } /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!status.b.drq) { /* No more interrupts */ debug_log(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred); clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable_in_hardirq(); if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ debug_log(KERN_INFO "ide-floppy: %s: I/O error\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -