ps2esdi.c
来自「linux 内核源代码」· C语言 代码 · 共 1,080 行 · 第 1/2 页
C
1,080 行
outb_p(CTRL_SOFT_RESET, ESDI_ATTN); } /* soft reset */ else { /*BA */ printk("%s: hard reset...\n", DEVICE_NAME); outb_p(CTRL_HARD_RESET, ESDI_CONTROL); expire = jiffies + 2*HZ; while (time_before(jiffies, expire)); outb_p(1, ESDI_CONTROL); } /* hard reset */} /* reset the controller *//* called by the strategy routine to handle read and write requests */static void ps2esdi_readwrite(int cmd, struct request *req){ struct ps2esdi_i_struct *p = req->rq_disk->private_data; unsigned block = req->sector; unsigned count = req->current_nr_sectors; int drive = p - ps2esdi_info; u_short track, head, cylinder, sector; u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH]; /* do some relevant arithmatic */ track = block / p->sect; head = track % p->head; cylinder = track / p->head; sector = block % p->sect;#if 0 printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);#endif /* call the routine that actually fills out a command block */ ps2esdi_fill_cmd_block (cmd_blk, (cmd == READ) ? CMD_READ : CMD_WRITE, cylinder, head, sector, count, drive); /* send the command block to the controller */ current_req = req; spin_unlock_irq(&ps2esdi_lock); if (ps2esdi_out_cmd_blk(cmd_blk)) { spin_lock_irq(&ps2esdi_lock); printk("%s: Controller failed\n", DEVICE_NAME); if ((++req->errors) >= MAX_RETRIES) end_request(req, FAIL); } /* check for failure to put out the command block */ else { spin_lock_irq(&ps2esdi_lock);#if 0 printk("%s: waiting for xfer\n", DEVICE_NAME);#endif /* turn disk lights on */ LITE_ON; }} /* ps2esdi_readwrite *//* fill out the command block */static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, u_short cyl, u_short head, u_short sector, u_short length, u_char drive){ cmd_blk[0] = (drive << 5) | cmd; cmd_blk[1] = length; cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector; cmd_blk[3] = (cyl & 0x3E0) >> 5;} /* fill out the command block *//* write a command block to the controller */static int ps2esdi_out_cmd_blk(u_short * cmd_blk){ int i; unsigned long jif; u_char status; /* enable interrupts */ outb(CTRL_ENABLE_INTR, ESDI_CONTROL); /* do not write to the controller, if it is busy */ for (jif = jiffies + ESDI_STAT_TIMEOUT; time_after(jif, jiffies) && (inb(ESDI_STATUS) & STATUS_BUSY); ) ;#if 0 printk("%s: i(1)=%ld\n", DEVICE_NAME, jif);#endif /* if device is still busy - then just time out */ if (inb(ESDI_STATUS) & STATUS_BUSY) { printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME); return ERROR; } /* timeout ??? */ /* Set up the attention register in the controller */ outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);#if 0 printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);#endif /* one by one send each word out */ for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) { status = inb(ESDI_STATUS); for (jif = jiffies + ESDI_STAT_TIMEOUT; time_after(jif, jiffies) && (status & STATUS_BUSY) && (status & STATUS_CMD_INF); status = inb(ESDI_STATUS)); if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {#if 0 printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);#endif outw(*cmd_blk++, ESDI_CMD_INT); } else { printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n", DEVICE_NAME, status); return ERROR; } } /* send all words out */ return OK;} /* send out the commands *//* prepare for dma - do all the necessary setup */static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode){ unsigned long flags = claim_dma_lock(); mca_disable_dma(dma_arb_level); mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer)); mca_set_dma_count(dma_arb_level, length * 512 / 2); mca_set_dma_mode(dma_arb_level, dma_xmode); mca_enable_dma(dma_arb_level); release_dma_lock(flags);} /* prepare for dma */static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id){ u_int int_ret_code; if (inb(ESDI_STATUS) & STATUS_INTR) { int_ret_code = inb(ESDI_INTRPT); if (current_int_handler) { /* Disable adapter interrupts till processing is finished */ outb(CTRL_DISABLE_INTR, ESDI_CONTROL); current_int_handler(int_ret_code); } else printk("%s: help ! No interrupt handler.\n", DEVICE_NAME); } else { return IRQ_NONE; } return IRQ_HANDLED;}static void ps2esdi_initial_reset_int_handler(u_int int_ret_code){ switch (int_ret_code & 0xf) { case INT_RESET: /*BA */ printk("%s: initial reset completed.\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); wake_up(&ps2esdi_int); break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS)); break; default: printk("%s: initial reset handler received interrupt: %02X\n", DEVICE_NAME, int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); break; } outb(CTRL_ENABLE_INTR, ESDI_CONTROL);}static void ps2esdi_geometry_int_handler(u_int int_ret_code){ u_int status, drive_num; unsigned long rba; int i; drive_num = int_ret_code >> 5; switch (int_ret_code & 0xf) { case INT_CMD_COMPLETE: for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); break; } status = inw(ESDI_STT_INT); if ((status & 0x1F) == CMD_GET_DEV_CONFIG) {#define REPLY_WORDS 5 /* we already read word 0 */ u_short reply[REPLY_WORDS]; if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) { /*BA */ printk("%s: Device Configuration Status for drive %u\n", DEVICE_NAME, drive_num); printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8); printk ("Config bits: %s%s%s%s%s\n", (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "", ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS)) ? "Zero Defect, " : "Defects Present, ", (reply[0] & CONFIG_SF) ? "Skewed Format, " : "", (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ", (reply[0] & CONFIG_RT) ? "No Retries" : "Retries"); rba = reply[1] | ((unsigned long) reply[2] << 16); printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba); printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n", DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff); if (!ps2esdi_info[drive_num].head) { ps2esdi_info[drive_num].head = 64; ps2esdi_info[drive_num].sect = 32; ps2esdi_info[drive_num].cyl = rba / (64 * 32); ps2esdi_info[drive_num].wpcom = 0; ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl; ps2esdi_info[drive_num].ctl = 8; if (tp720esdi) { /* store the retrieved parameters */ ps2esdi_info[0].head = reply[4] & 0Xff; ps2esdi_info[0].sect = reply[4] >> 8; ps2esdi_info[0].cyl = reply[3]; ps2esdi_info[0].wpcom = 0; ps2esdi_info[0].lzone = reply[3]; } else { if (!intg_esdi) ps2esdi_drives++; } }#ifdef OBSOLETE if (!ps2esdi_info[drive_num].head) { ps2esdi_info[drive_num].head = reply[4] & 0Xff; ps2esdi_info[drive_num].sect = reply[4] >> 8; ps2esdi_info[drive_num].cyl = reply[3]; ps2esdi_info[drive_num].wpcom = 0; ps2esdi_info[drive_num].lzone = reply[3]; if (tp720esdi) { /* store the retrieved parameters */ ps2esdi_info[0].head = reply[4] & 0Xff; ps2esdi_info[0].sect = reply[4] >> 8; ps2esdi_info[0].cyl = reply[3]; ps2esdi_info[0].wpcom = 0; ps2esdi_info[0].lzone = reply[3]; } else { ps2esdi_drives++; } }#endif } else printk("%s: failed while getting device config\n", DEVICE_NAME);#undef REPLY_WORDS } else printk("%s: command %02X unknown by geometry handler\n", DEVICE_NAME, status & 0x1f); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); printk("%s: Device not available\n", DEVICE_NAME); break; case INT_CMD_ECC: case INT_CMD_RETRY: case INT_CMD_ECC_RETRY: case INT_CMD_WARNING: case INT_CMD_ABORT: case INT_CMD_FAILED: case INT_DMA_ERR: case INT_CMD_BLK_ERR: /*BA */ printk("%s: Whaa. Error occurred...\n", DEVICE_NAME); dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); break; default: printk("%s: Unknown interrupt reason: %02X\n", DEVICE_NAME, int_ret_code & 0xf); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); break; } wake_up(&ps2esdi_int); no_int_yet = FALSE; outb(CTRL_ENABLE_INTR, ESDI_CONTROL);}static void ps2esdi_normal_interrupt_handler(u_int int_ret_code){ unsigned long flags; u_int status; u_int ending; int i; switch (int_ret_code & 0x0f) { case INT_TRANSFER_REQ: ps2esdi_prep_dma(current_req->buffer, current_req->current_nr_sectors, (rq_data_dir(current_req) == READ) ? MCA_DMA_MODE_16 | MCA_DMA_MODE_WRITE | MCA_DMA_MODE_XFER : MCA_DMA_MODE_16 | MCA_DMA_MODE_READ); outb(CTRL_ENABLE_DMA | CTRL_ENABLE_INTR, ESDI_CONTROL); ending = -1; break; case INT_ATTN_ERROR: printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME, int_ret_code); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = FAIL; break; case INT_CMD_COMPLETE: for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { printk("%s: timeout reading status word\n", DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++current_req->errors) >= MAX_RETRIES) ending = FAIL; else ending = -1; break; } status = inw(ESDI_STT_INT); switch (status & 0x1F) { case (CMD_READ & 0xff): case (CMD_WRITE & 0xff): LITE_OFF; outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = SUCCES; break; default: printk("%s: interrupt for unknown command %02X\n", DEVICE_NAME, status & 0x1f); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = -1; break; } break; case INT_CMD_ECC: case INT_CMD_RETRY: case INT_CMD_ECC_RETRY: LITE_OFF; dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = SUCCES; break; case INT_CMD_WARNING: case INT_CMD_ABORT: case INT_CMD_FAILED: case INT_DMA_ERR: LITE_OFF; dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); if ((++current_req->errors) >= MAX_RETRIES) ending = FAIL; else ending = -1; break; case INT_CMD_BLK_ERR: dump_cmd_complete_status(int_ret_code); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = FAIL; break; case INT_CMD_FORMAT: printk("%s: huh ? Who issued this format command ?\n" ,DEVICE_NAME); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = -1; break; case INT_RESET: /* BA printk("%s: reset completed.\n", DEVICE_NAME) */ ; outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = -1; break; default: printk("%s: Unknown interrupt reason: %02X\n", DEVICE_NAME, int_ret_code & 0xf); outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); ending = -1; break; } if(ending != -1) { spin_lock_irqsave(&ps2esdi_lock, flags); end_request(current_req, ending); current_req = NULL; do_ps2esdi_request(ps2esdi_queue); spin_unlock_irqrestore(&ps2esdi_lock, flags); }} /* handle interrupts */static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer){ int i; for (; max_words && num_words; max_words--, num_words--, buffer++) { for (i = ESDI_TIMEOUT; i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--); if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { printk("%s: timeout reading status word\n", DEVICE_NAME); return FAIL; } *buffer = inw(ESDI_STT_INT); } return SUCCES;}static void dump_cmd_complete_status(u_int int_ret_code){#define WAIT_FOR_STATUS \ for(i=ESDI_TIMEOUT;i && !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL);i--); \ if(!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) { \ printk("%s: timeout reading status word\n",DEVICE_NAME); \ return; \ } int i, word_count; u_short stat_word; u_long rba; printk("%s: Device: %u, interrupt ID: %02X\n", DEVICE_NAME, int_ret_code >> 5, int_ret_code & 0xf); WAIT_FOR_STATUS; stat_word = inw(ESDI_STT_INT); word_count = (stat_word >> 8) - 1; printk("%s: %u status words, command: %02X\n", DEVICE_NAME, word_count, stat_word & 0xff); if (word_count--) { WAIT_FOR_STATUS; stat_word = inw(ESDI_STT_INT); printk("%s: command status code: %02X, command error code: %02X\n", DEVICE_NAME, stat_word >> 8, stat_word & 0xff); } if (word_count--) { WAIT_FOR_STATUS; stat_word = inw(ESDI_STT_INT); printk("%s: device error code: %s%s%s%s%s,%02X\n", DEVICE_NAME, (stat_word & 0x1000) ? "Ready, " : "Not Ready, ", (stat_word & 0x0800) ? "Selected, " : "Not Selected, ", (stat_word & 0x0400) ? "Write Fault, " : "", (stat_word & 0x0200) ? "Track 0, " : "", (stat_word & 0x0100) ? "Seek or command complete, " : "", stat_word >> 8); } if (word_count--) { WAIT_FOR_STATUS; stat_word = inw(ESDI_STT_INT); printk("%s: Blocks to do: %u", DEVICE_NAME, stat_word); } if (word_count -= 2) { WAIT_FOR_STATUS; rba = inw(ESDI_STT_INT); WAIT_FOR_STATUS; rba |= inw(ESDI_STT_INT) << 16; printk(", Last Cyl: %u Head: %u Sector: %u\n", (u_short) ((rba & 0x1ff80000) >> 11), (u_short) ((rba & 0x7E0) >> 5), (u_short) (rba & 0x1f)); } else printk("\n"); if (word_count--) { WAIT_FOR_STATUS; stat_word = inw(ESDI_STT_INT); printk("%s: Blocks required ECC: %u", DEVICE_NAME, stat_word); } printk("\n");#undef WAIT_FOR_STATUS}static int ps2esdi_getgeo(struct block_device *bdev, struct hd_geometry *geo){ struct ps2esdi_i_struct *p = bdev->bd_disk->private_data; geo->heads = p->head; geo->sectors = p->sect; geo->cylinders = p->cyl; return 0;}static void ps2esdi_reset_timer(unsigned long unused){ int status; status = inb(ESDI_INTRPT); if ((status & 0xf) == INT_RESET) { outb((status & 0xe0) | ATT_EOI, ESDI_ATTN); outb(CTRL_ENABLE_INTR, ESDI_CONTROL); reset_status = 1; } wake_up(&ps2esdi_int);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?