📄 imm.c
字号:
/* If not, drop back down to the scheduler and wait a timer tick */ if (!(r & 0x80)) return 0; } return 1; /* FINISH_RETURN */}/* deprecated synchronous interface */int imm_command(Scsi_Cmnd * cmd){ static int first_pass = 1; int host_no = cmd->host->unique_id; if (first_pass) { printk("imm: using non-queuing interface\n"); first_pass = 0; } if (imm_hosts[host_no].cur_cmd) { printk("IMM: bug in imm_command\n"); return 0; } imm_hosts[host_no].failed = 0; imm_hosts[host_no].jstart = jiffies; imm_hosts[host_no].cur_cmd = cmd; cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; imm_pb_claim(host_no); while (imm_engine(&imm_hosts[host_no], cmd)) schedule(); if (cmd->SCp.phase) /* Only disconnect if we have connected */ imm_disconnect(cmd->host->unique_id); imm_pb_release(host_no); imm_hosts[host_no].cur_cmd = 0; return cmd->result;}/* * Since the IMM itself doesn't generate interrupts, we use * the scheduler's task queue to generate a stream of call-backs and * complete the request when the drive is ready. */static void imm_interrupt(void *data){ imm_struct *tmp = (imm_struct *) data; Scsi_Cmnd *cmd = tmp->cur_cmd; unsigned long flags; if (!cmd) { printk("IMM: bug in imm_interrupt\n"); return; } if (imm_engine(tmp, cmd)) { tmp->imm_tq.data = (void *) tmp; tmp->imm_tq.sync = 0; queue_task(&tmp->imm_tq, &tq_timer); return; } /* Command must of completed hence it is safe to let go... */#if IMM_DEBUG > 0 switch ((cmd->result >> 16) & 0xff) { case DID_OK: break; case DID_NO_CONNECT: printk("imm: no device at SCSI ID %i\n", cmd->target); break; case DID_BUS_BUSY: printk("imm: BUS BUSY - EPP timeout detected\n"); break; case DID_TIME_OUT: printk("imm: unknown timeout\n"); break; case DID_ABORT: printk("imm: told to abort\n"); break; case DID_PARITY: printk("imm: parity error (???)\n"); break; case DID_ERROR: printk("imm: internal driver error\n"); break; case DID_RESET: printk("imm: told to reset device\n"); break; case DID_BAD_INTR: printk("imm: bad interrupt (???)\n"); break; default: printk("imm: bad return code (%02x)\n", (cmd->result >> 16) & 0xff); }#endif if (cmd->SCp.phase > 1) imm_disconnect(cmd->host->unique_id); if (cmd->SCp.phase > 0) imm_pb_release(cmd->host->unique_id); spin_lock_irqsave(&io_request_lock, flags); tmp->cur_cmd = 0; cmd->scsi_done(cmd); spin_unlock_irqrestore(&io_request_lock, flags); return;}static int imm_engine(imm_struct * tmp, Scsi_Cmnd * cmd){ int host_no = cmd->host->unique_id; unsigned short ppb = IMM_BASE(host_no); unsigned char l = 0, h = 0; int retv, x; /* First check for any errors that may of occurred * Here we check for internal errors */ if (tmp->failed) return 0; switch (cmd->SCp.phase) { case 0: /* Phase 0 - Waiting for parport */ if ((jiffies - tmp->jstart) > HZ) { /* * We waited more than a second * for parport to call us */ imm_fail(host_no, DID_BUS_BUSY); return 0; } return 1; /* wait until imm_wakeup claims parport */ /* Phase 1 - Connected */ case 1: imm_connect(host_no, CONNECT_EPP_MAYBE); cmd->SCp.phase++; /* Phase 2 - We are now talking to the scsi bus */ case 2: if (!imm_select(host_no, cmd->target)) { imm_fail(host_no, DID_NO_CONNECT); return 0; } cmd->SCp.phase++; /* Phase 3 - Ready to accept a command */ case 3: w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; if (!imm_send_command(cmd)) return 0; cmd->SCp.phase++; /* Phase 4 - Setup scatter/gather buffers */ case 4: if (cmd->use_sg) { /* if many buffers are available, start filling the first */ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = cmd->SCp.buffer->address; } else { /* else fill the only available buffer */ cmd->SCp.buffer = NULL; cmd->SCp.this_residual = cmd->request_bufflen; cmd->SCp.ptr = cmd->request_buffer; } cmd->SCp.buffers_residual = cmd->use_sg; cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; /* Phase 5 - Pre-Data transfer stage */ case 5: /* Spin lock for BUSY */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; /* Require negotiation for read requests */ x = (r_str(ppb) & 0xb8); tmp->rd = (x & 0x10) ? 1 : 0; tmp->dp = (x & 0x20) ? 0 : 1; if ((tmp->dp) && (tmp->rd)) if (imm_negotiate(tmp)) return 0; cmd->SCp.phase++; /* Phase 6 - Data transfer stage */ case 6: /* Spin lock for BUSY */ w_ctr(ppb, 0x0c); if (!(r_str(ppb) & 0x80)) return 1; if (tmp->dp) { retv = imm_completion(cmd); if (retv == -1) return 0; if (retv == 0) return 1; } cmd->SCp.phase++; /* Phase 7 - Post data transfer stage */ case 7: if ((tmp->dp) && (tmp->rd)) { if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) { w_ctr(ppb, 0x4); w_ctr(ppb, 0xc); w_ctr(ppb, 0xe); w_ctr(ppb, 0x4); } } cmd->SCp.phase++; /* Phase 8 - Read status/message */ case 8: /* Check for data overrun */ if (imm_wait(host_no) != (unsigned char) 0xb8) { imm_fail(host_no, DID_ERROR); return 0; } if (imm_negotiate(tmp)) return 0; if (imm_in(host_no, &l, 1)) { /* read status byte */ /* Check for optional message byte */ if (imm_wait(host_no) == (unsigned char) 0xb8) imm_in(host_no, &h, 1); cmd->result = (DID_OK << 16) + (l & STATUS_MASK); } if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) { w_ctr(ppb, 0x4); w_ctr(ppb, 0xc); w_ctr(ppb, 0xe); w_ctr(ppb, 0x4); } return 0; /* Finished */ break; default: printk("imm: Invalid scsi phase\n"); } return 0;}int imm_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){ int host_no = cmd->host->unique_id; if (imm_hosts[host_no].cur_cmd) { printk("IMM: bug in imm_queuecommand\n"); return 0; } imm_hosts[host_no].failed = 0; imm_hosts[host_no].jstart = jiffies; imm_hosts[host_no].cur_cmd = cmd; cmd->scsi_done = done; cmd->result = DID_ERROR << 16; /* default return code */ cmd->SCp.phase = 0; /* bus free */ imm_pb_claim(host_no); imm_hosts[host_no].imm_tq.data = imm_hosts + host_no; imm_hosts[host_no].imm_tq.sync = 0; queue_task(&imm_hosts[host_no].imm_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); return 0;}/* * Apparently the the disk->capacity attribute is off by 1 sector * for all disk drives. We add the one here, but it should really * be done in sd.c. Even if it gets fixed there, this will still * work. */int imm_biosparam(Disk * disk, kdev_t dev, int ip[]){ ip[0] = 0x40; ip[1] = 0x20; ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); if (ip[2] > 1024) { ip[0] = 0xff; ip[1] = 0x3f; ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]); } return 0;}int imm_abort(Scsi_Cmnd * cmd){ int host_no = cmd->host->unique_id; /* * There is no method for aborting commands since Iomega * have tied the SCSI_MESSAGE line high in the interface */ switch (cmd->SCp.phase) { case 0: /* Do not have access to parport */ case 1: /* Have not connected to interface */ imm_hosts[host_no].cur_cmd = NULL; /* Forget the problem */ return SUCCESS; break; default: /* SCSI command sent, can not abort */ return FAILED; break; }}void imm_reset_pulse(unsigned int base){ w_ctr(base, 0x04); w_dtr(base, 0x40); udelay(1); w_ctr(base, 0x0c); w_ctr(base, 0x0d); udelay(50); w_ctr(base, 0x0c); w_ctr(base, 0x04);}int imm_reset(Scsi_Cmnd * cmd){ int host_no = cmd->host->unique_id; if (cmd->SCp.phase) imm_disconnect(host_no); imm_hosts[host_no].cur_cmd = NULL; /* Forget the problem */ imm_connect(host_no, CONNECT_NORMAL); imm_reset_pulse(IMM_BASE(host_no)); udelay(1000); /* device settle delay */ imm_disconnect(host_no); udelay(1000); /* device settle delay */ return SUCCESS;}static int device_check(int host_no){ /* This routine looks for a device and then attempts to use EPP to send a command. If all goes as planned then EPP is available. */ static char cmd[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int loop, old_mode, status, k, ppb = IMM_BASE(host_no); unsigned char l; old_mode = imm_hosts[host_no].mode; for (loop = 0; loop < 8; loop++) { /* Attempt to use EPP for Test Unit Ready */ if ((ppb & 0x0007) == 0x0000) imm_hosts[host_no].mode = IMM_EPP_32; second_pass: imm_connect(host_no, CONNECT_EPP_MAYBE); /* Select SCSI device */ if (!imm_select(host_no, loop)) { imm_disconnect(host_no); continue; } printk("imm: Found device at ID %i, Attempting to use %s\n", loop, IMM_MODE_STRING[imm_hosts[host_no].mode]); /* Send SCSI command */ status = 1; w_ctr(ppb, 0x0c); for (l = 0; (l < 3) && (status); l++) status = imm_out(host_no, &cmd[l << 1], 2); if (!status) { imm_disconnect(host_no); imm_connect(host_no, CONNECT_EPP_MAYBE); imm_reset_pulse(IMM_BASE(host_no)); udelay(1000); imm_disconnect(host_no); udelay(1000); if (imm_hosts[host_no].mode == IMM_EPP_32) { imm_hosts[host_no].mode = old_mode; goto second_pass; } printk("imm: Unable to establish communication, aborting driver load.\n"); return 1; } w_ctr(ppb, 0x0c); k = 1000000; /* 1 Second */ do { l = r_str(ppb); k--; udelay(1); } while (!(l & 0x80) && (k)); l &= 0xb8; if (l != 0xb8) { imm_disconnect(host_no); imm_connect(host_no, CONNECT_EPP_MAYBE); imm_reset_pulse(IMM_BASE(host_no)); udelay(1000); imm_disconnect(host_no); udelay(1000); if (imm_hosts[host_no].mode == IMM_EPP_32) { imm_hosts[host_no].mode = old_mode; goto second_pass; } printk("imm: Unable to establish communication, aborting driver load.\n"); return 1; } imm_disconnect(host_no); printk("imm: Communication established at 0x%x with ID %i using %s\n", ppb, loop, IMM_MODE_STRING[imm_hosts[host_no].mode]); imm_connect(host_no, CONNECT_EPP_MAYBE); imm_reset_pulse(IMM_BASE(host_no)); udelay(1000); imm_disconnect(host_no); udelay(1000); return 0; } printk("imm: No devices found, aborting driver load.\n"); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -