📄 nsp_cs.c
字号:
if (data->FifoCount == count) { //DEBUG(0, " not use bypass quirk\n"); return 0; } /* * XXX: NSP_QUIRK * data phase skip only occures in case of SCSI_LOW_READ */ SCpnt->SCp.phase = PH_DATA; nsp_pio_read(SCpnt, data); nsp_setup_fifo(data, FALSE); DEBUG(0, " use bypass quirk\n"); return 0;}/* * accept reselection */static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data){ unsigned int base = SCpnt->host->io_port; unsigned char reg; //DEBUG(0, __FUNCTION__ "()\n"); nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>"); nsp_nexus(SCpnt, data); reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); nsp_index_write(base, SCSIBUSCTRL, reg); nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB); return TRUE;}/* * count how many data transferd */static int nsp_fifo_count(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->host->io_port; unsigned int count; unsigned int l, m, h; nsp_index_write(base, POINTERCLR, POINTER_CLEAR); l = (unsigned int)nsp_read(base, DATAREG); m = (unsigned int)nsp_read(base, DATAREG); h = (unsigned int)nsp_read(base, DATAREG); count = (h << 16) | (m << 8) | (l << 0); //DEBUG(0, __FUNCTION__ "() =0x%x\n", count); return count;}/* fifo size */#define RFIFO_CRIT 64#define WFIFO_CRIT 64/* * read data in DATA IN phase */static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data){ unsigned int base = SCpnt->host->io_port; int time_out, i; int ocount, res; unsigned char stat, fifo_stat; ocount = data->FifoCount; DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); time_out = jiffies + 10 * HZ; while ((i = time_before(jiffies,time_out)) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; res = nsp_fifo_count(SCpnt) - ocount; //DEBUG(0, " ptr=0x%p this=0x%x ocount=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); if (res == 0) { /* if some data avilable ? */ if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ //DEBUG(0, " wait for data this=%d\n", SCpnt->SCp.this_residual); continue; } else { DEBUG(0, " phase changed stat=0x%x\n", stat); break; } } fifo_stat = nsp_read(base, FIFOSTATUS); if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && stat == BUSPHASE_DATA_IN) { continue; } res = MIN(res, SCpnt->SCp.this_residual); switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); break; case MODE_IO8: nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); break; default: DEBUG(0, "unknown read mode\n"); break; } RESID -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; //DEBUG(0, " ptr=0x%p this_residual=0x%x ocount=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); /* go to next scatter list if availavle */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { //DEBUG(0, " scatterlist next timeout=%d\n", time_out); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; } time_out = jiffies + 10 * HZ; } data->FifoCount = ocount; if (!i) { printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); } DEBUG(0, " read ocount=0x%x\n", ocount);}/* * write data in DATA OUT phase */static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data){ unsigned int base = SCpnt->host->io_port; int time_out, i; unsigned int ocount, res; unsigned char stat; ocount = data->FifoCount; DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID); time_out = jiffies + 10 * HZ; while ((i = time_before(jiffies, time_out)) && (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { stat = nsp_index_read(base, SCSIBUSMON); stat &= BUSMON_PHASE_MASK; if (stat != BUSPHASE_DATA_OUT) { DEBUG(0, " phase changed stat=0x%x\n", stat); break; } res = ocount - nsp_fifo_count(SCpnt); if (res > 0) { /* write all data? */ DEBUG(0, " wait for all data out. ocount=0x%x res=%d\n", ocount, res); continue; } res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); //DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); switch (data->TransferMode) { case MODE_IO32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); break; case MODE_IO8: nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); break; default: DEBUG(0, "unknown write mode\n"); break; } RESID -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; /* go to next scatter list if availavle */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { //DEBUG(0, " scatterlist next\n"); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; } time_out = jiffies + 10 * HZ; } data->FifoCount = ocount; if (!i) { printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID); } //DEBUG(0, " write ocount=%d\n", ocount);}#undef RFIFO_CRIT#undef WFIFO_CRIT/* * setup synchronous/asynchronous data transfer mode */static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data){ unsigned int base = SCpnt->host->io_port; unsigned char target = SCpnt->target; unsigned char lun = SCpnt->lun; sync_data *sync = &(data->Sync[target][lun]); //DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt); /* setup synch transfer registers */ nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); if (RESID % 4 != 0 || RESID <= 256 ) { data->TransferMode = MODE_IO8; } else { data->TransferMode = MODE_IO32; } /* setup pdma fifo */ nsp_setup_fifo(data, TRUE); /* clear ack counter */ data->FifoCount = 0; nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER_CLEAR | REQ_COUNTER_CLEAR | HOST_COUNTER_CLEAR); return 0;}#include "nsp_message.c"/* * interrupt handler */static void nspintr(int irq, void *dev_id, struct pt_regs *regs){ unsigned int base; unsigned char i_src, irq_phase, phase; Scsi_Cmnd *tmpSC; int len; unsigned char target, lun; unsigned int *sync_neg; int i, tmp; nsp_hw_data *data; //printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id); /* sanity check */ if (&nsp_data != dev_id) { DEBUG(0, " irq conflict? this can't happen\n"); return; } data = dev_id; if (irq != data->IrqNumber) { return; } base = data->BaseAddress; //DEBUG(0, " base=0x%x\n", base); /* * interrupt check */ nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); i_src = nsp_read(base, IRQSTATUS); if (i_src == 0xff || (i_src & IRQSTATUS_MASK) == 0) { nsp_write(base, IRQCONTROL, 0); //DEBUG(0, " no irq\n"); return; } //DEBUG(0, " i_src=0x%x\n", i_src); /* XXX: IMPORTANT * Do not read an irq_phase register if no scsi phase interrupt. * Unless, you should lose a scsi phase interrupt. */ phase = nsp_index_read(base, SCSIBUSMON); if((i_src & IRQSTATUS_SCSI) != 0) { irq_phase = nsp_index_read(base, IRQPHASESENCE); } else { irq_phase = 0; } //DEBUG(0, " irq_phase=0x%x\n", irq_phase); /* * timer interrupt handler (scsi vs timer interrupts) */ //DEBUG(0, " timercount=%d\n", data->TimerCount); if (data->TimerCount != 0) { //DEBUG(0, " stop timer\n"); nsp_index_write(base, TIMERCOUNT, 0); nsp_index_write(base, TIMERCOUNT, 0); data->TimerCount = 0; } if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER && data->SelectionTimeOut == 0) { //DEBUG(0, " timer start\n"); nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); return; } nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); if (data->CurrentSC == NULL) { printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase); return; } else { tmpSC = data->CurrentSC; target = tmpSC->target; lun = tmpSC->lun; sync_neg = &(data->Sync[target][lun].SyncNegotiation); } /* * parse hardware SCSI irq reasons register */ if ((i_src & IRQSTATUS_SCSI) != 0) { if ((irq_phase & SCSI_RESET_IRQ) != 0) { printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n"); *sync_neg = SYNC_NOT_YET; data->CurrentSC = NULL; tmpSC->result = DID_RESET << 16; tmpSC->scsi_done(tmpSC); return; } if ((irq_phase & RESELECT_IRQ) != 0) { DEBUG(0, " reselect\n"); nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); if (nsp_reselected(tmpSC, data) != FALSE) { return; } } if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { return; } } //show_phase(tmpSC); switch(tmpSC->SCp.phase) { case PH_SELSTART: *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_BSY) == 0) { //DEBUG(0, " selection count=%d\n", data->SelectionTimeOut); if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { DEBUG(0, " selection time out\n"); data->SelectionTimeOut = 0; nsp_index_write(base, SCSIBUSCTRL, 0); data->CurrentSC = NULL; tmpSC->result = DID_NO_CONNECT << 16; tmpSC->scsi_done(tmpSC); return; } data->SelectionTimeOut += 1; nsp_start_timer(tmpSC, data, 1000/51); return; } /* attention assert */ //DEBUG(0, " attention assert\n"); data->SelectionTimeOut = 0; tmpSC->SCp.phase = PH_SELECTED; nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); udelay(1); nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); return; break; case PH_RESELECT: //DEBUG(0, " phase reselect\n"); *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { data->CurrentSC = NULL; tmpSC->result = DID_ABORT << 16; tmpSC->scsi_done(tmpSC); return; } /* fall thru */ default: if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { return; } break; } /* * SCSI sequencer */ //DEBUG(0, " start scsi seq\n"); /* normal disconnect */ if ((irq_phase & LATCHED_BUS_FREE) != 0) { //DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ *sync_neg = SYNC_NOT_YET; data->CurrentSC = NULL; tmpSC->result = (DID_OK << 16) | (tmpSC->SCp.Message << 8) | (tmpSC->SCp.Status << 0); DEBUG(0, " command complete result=0x%x\n", tmpSC->result); tmpSC->scsi_done(tmpSC); return; } return; } /* check unexpected bus free state */ if (phase == 0) { printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase); *sync_neg = SYNC_NOT_YET; data->CurrentSC = NULL; tmpSC->result = DID_ERROR << 16; tmpSC->scsi_done(tmpSC); return; } switch (phase & BUSMON_PHASE_MASK) { case BUSPHASE_COMMAND: DEBUG(0, " BUSPHASE_COMMAND\n"); if ((phase & BUSMON_REQ) == 0) { DEBUG(0, " REQ == 0\n"); return; } tmpSC->SCp.phase = PH_COMMAND; nsp_nexus(tmpSC, data); /* write scsi command */ nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); for (len = 0; len < COMMAND_SIZE(tmpSC->cmnd[0]); len++) { nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[len]); } nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); break; case BUSPHASE_DATA_OUT: DEBUG(0, " BUSPHASE_DATA_OUT\n"); tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_OUT; nsp_pio_write(tmpSC, data); break; case BUSPHASE_DATA_IN: DEBUG(0, " BUSPHASE_DATA_IN\n"); tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_IN; nsp_pio_read(tmpSC, data); break; case BUSPHASE_STATUS: nsp_dataphase_bypass(tmpSC, data); DEBUG(0, " BUSPHASE_STATUS\n"); tmpSC->SCp.phase = PH_STATUS; tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); //DEBUG(0, " message=0x%x status=0x%x\n", tmpSC->SCp.Message, tmpSC->SCp.Status); break; case BUSPHASE_MESSAGE_OUT: DEBUG(0, " BUSPHASE_MESSAGE_OUT\n"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_OUT; data->MsgLen = len = 0; if (*sync_neg == SYNC_NOT_YET) { data->Sync[target][lun].SyncPeriod = 0; data->Sync[target][lun].SyncOffset = 0; nsp_msg(tmpSC, data); data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++; /* data->MsgBuffer[len] = MSG_EXTENDED; len++; data->MsgBuffer[len] = 3; len++; data->MsgBuffer[len] = MSG_EXT_SDTR; len++; data->MsgBuffer[len] = 0x0c; len++; data->MsgBuffer[len] = 15; len++; */ } if (len == 0) { data->MsgBuffer[len] = MSG_NO_OPERATION; len++; } data->MsgLen = len; show_message(data); nsp_message_out(tmpSC, data); break; case BUSPHASE_MESSAGE_IN: nsp_dataphase_bypass(tmpSC, data); DEBUG(0, " BUSPHASE_MESSAGE_IN\n"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_IN; nsp_message_in(tmpSC, data); /* if (data->MsgLen >= 5 && data->MsgBuffer[0] == MSG_EXTENDED && data->MsgBuffer[1] == 3 && data->MsgBuffer[2] == MSG_EXT_SDTR ) { data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3]; data->Sync[target][lun].SyncOffset = data->MsgBuffer[4]; nsp_msg(tmpSC, data); } */ /* search last messeage byte */ tmp = -1; for (i = 0; i < data->MsgLen; i++) { tmp = data->MsgBuffer[i]; if (data->MsgBuffer[i] == MSG_EXTENDED) { i += (1 + data->MsgBuffer[i+1]); } } tmpSC->SCp.Message = tmp; DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen); show_message(data); break; case BUSPHASE_SELECT: default: DEBUG(0, " BUSPHASE other\n"); break; } //DEBUG(0, __FUNCTION__ "() out\n"); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -