📄 nsp_cs.c
字号:
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; case MODE_MEM32: res &= ~(BIT(1)|BIT(0)); /* align 4 */ nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); break; default: nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode"); break; } SCpnt->resid -= res; SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; /* go to next scatter list if available */ if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); SCpnt->SCp.buffers_residual--; SCpnt->SCp.buffer++; SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; } } data->FifoCount = ocount; if (time_out == 0) { nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid); } nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);}#undef RFIFO_CRIT#undef WFIFO_CRIT/* * setup synchronous/asynchronous data transfer mode */static int nsp_nexus(Scsi_Cmnd *SCpnt){ unsigned int base = SCpnt->device->host->io_port; unsigned char target = SCpnt->device->id;// unsigned char lun = SCpnt->device->lun; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; sync_data *sync = &(data->Sync[target]); //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt); /* setup synch transfer registers */ nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); if (SCpnt->use_sg == 0 || SCpnt->resid % 4 != 0 || SCpnt->resid <= PAGE_SIZE ) { data->TransferMode = MODE_IO8; } else if (nsp_burst_mode == BURST_MEM32) { data->TransferMode = MODE_MEM32; } else if (nsp_burst_mode == BURST_IO32) { data->TransferMode = MODE_IO32; } else { data->TransferMode = MODE_IO8; } /* 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 irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs){ unsigned int base; unsigned char irq_status, irq_phase, phase; Scsi_Cmnd *tmpSC; unsigned char target, lun; unsigned int *sync_neg; int i, tmp; unsigned long flags; nsp_hw_data *data; int handled = 0; //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id); //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host); if ( dev_id != NULL && ((scsi_info_t *)dev_id)->host != NULL ) { scsi_info_t *info = (scsi_info_t *)dev_id; data = (nsp_hw_data *)(info->host->hostdata); } else { nsp_dbg(NSP_DEBUG_INTR, "host data wrong"); return IRQ_NONE; } spin_lock_irqsave(HOST_LOCK, flags); //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id); base = data->BaseAddress; //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base); /* * interrupt check */ nsp_write(base, IRQCONTROL, IRQCONTROL_ALL_MASK); irq_status = nsp_read(base, IRQSTATUS); //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status); if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) { //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq"); goto out; } handled = 1; /* 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((irq_status & IRQSTATUS_SCSI) != 0) { irq_phase = nsp_index_read(base, IRQPHASESENCE); } else { irq_phase = 0; } //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase); /* * timer interrupt handler (scsi vs timer interrupts) */ //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount); if (data->TimerCount != 0) { //nsp_dbg(NSP_DEBUG_INTR, "stop timer"); nsp_index_write(base, TIMERCOUNT, 0); nsp_index_write(base, TIMERCOUNT, 0); data->TimerCount = 0; } if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER && data->SelectionTimeOut == 0) { //nsp_dbg(NSP_DEBUG_INTR, "timer start"); nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); goto out; } nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); if ((irq_status & IRQSTATUS_SCSI) && (irq_phase & SCSI_RESET_IRQ)) { nsp_msg(KERN_ERR, "bus reset (power off?)"); nsphw_init(data); nsp_bus_reset(data); if(data->CurrentSC != NULL) { tmpSC = data->CurrentSC; tmpSC->result = (DID_RESET << 16) | ((tmpSC->SCp.Message & 0xff) << 8) | ((tmpSC->SCp.Status & 0xff) << 0); nsp_scsi_done(tmpSC); } goto out; } if (data->CurrentSC == NULL) { nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase); nsphw_init(data); nsp_bus_reset(data); goto out; } tmpSC = data->CurrentSC; target = tmpSC->device->id; lun = tmpSC->device->lun; sync_neg = &(data->Sync[target].SyncNegotiation); /* * parse hardware SCSI irq reasons register */ if (irq_status & IRQSTATUS_SCSI) { if (irq_phase & RESELECT_IRQ) { nsp_dbg(NSP_DEBUG_INTR, "reselect"); nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); if (nsp_reselected(tmpSC) != FALSE) { goto out; } } if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { goto out; } } //show_phase(tmpSC); switch(tmpSC->SCp.phase) { case PH_SELSTART: // *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_BSY) == 0) { //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut); if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { nsp_dbg(NSP_DEBUG_INTR, "selection time out"); data->SelectionTimeOut = 0; nsp_index_write(base, SCSIBUSCTRL, 0); tmpSC->result = DID_TIME_OUT << 16; nsp_scsi_done(tmpSC); goto out; } data->SelectionTimeOut += 1; nsp_start_timer(tmpSC, 1000/51); goto out; } /* attention assert */ //nsp_dbg(NSP_DEBUG_INTR, "attention assert"); 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); goto out; break; case PH_RESELECT: //nsp_dbg(NSP_DEBUG_INTR, "phase reselect"); // *sync_neg = SYNC_NOT_YET; if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { tmpSC->result = DID_ABORT << 16; nsp_scsi_done(tmpSC); goto out; } /* fall thru */ default: if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { goto out; } break; } /* * SCSI sequencer */ //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq"); /* normal disconnect */ if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && (irq_phase & LATCHED_BUS_FREE) != 0 ) { nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); // *sync_neg = SYNC_NOT_YET; if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ tmpSC->result = (DID_OK << 16) | ((tmpSC->SCp.Message & 0xff) << 8) | ((tmpSC->SCp.Status & 0xff) << 0); nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result); nsp_scsi_done(tmpSC); goto out; } goto out; } /* check unexpected bus free state */ if (phase == 0) { nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); *sync_neg = SYNC_NG; tmpSC->result = DID_ERROR << 16; nsp_scsi_done(tmpSC); goto out; } switch (phase & BUSMON_PHASE_MASK) { case BUSPHASE_COMMAND: nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND"); if ((phase & BUSMON_REQ) == 0) { nsp_dbg(NSP_DEBUG_INTR, "REQ == 0"); goto out; } tmpSC->SCp.phase = PH_COMMAND; nsp_nexus(tmpSC); /* write scsi command */ nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len); nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); for (i = 0; i < tmpSC->cmd_len; i++) { nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); } nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); break; case BUSPHASE_DATA_OUT: nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT"); tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_OUT; nsp_pio_write(tmpSC); break; case BUSPHASE_DATA_IN: nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN"); tmpSC->SCp.phase = PH_DATA; tmpSC->SCp.have_data_in = IO_IN; nsp_pio_read(tmpSC); break; case BUSPHASE_STATUS: nsp_dataphase_bypass(tmpSC); nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS"); tmpSC->SCp.phase = PH_STATUS; tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status); break; case BUSPHASE_MESSAGE_OUT: nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_OUT; // *sync_neg = SYNC_NOT_YET; data->MsgLen = i = 0; data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; if (*sync_neg == SYNC_NOT_YET) { data->Sync[target].SyncPeriod = 0; data->Sync[target].SyncOffset = 0; /**/ data->MsgBuffer[i] = MSG_EXTENDED; i++; data->MsgBuffer[i] = 3; i++; data->MsgBuffer[i] = MSG_EXT_SDTR; i++; data->MsgBuffer[i] = 0x0c; i++; data->MsgBuffer[i] = 15; i++; /**/ } data->MsgLen = i; nsp_analyze_sdtr(tmpSC); show_message(data); nsp_message_out(tmpSC); break; case BUSPHASE_MESSAGE_IN: nsp_dataphase_bypass(tmpSC); nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN"); if ((phase & BUSMON_REQ) == 0) { goto timer_out; } tmpSC->SCp.phase = PH_MSG_IN; nsp_message_in(tmpSC); /**/ if (*sync_neg == SYNC_NOT_YET) { //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun); if (data->MsgLen >= 5 && data->MsgBuffer[0] == MSG_EXTENDED && data->MsgBuffer[1] == 3 && data->MsgBuffer[2] == MSG_EXT_SDTR ) { data->Sync[target].SyncPeriod = data->MsgBuffer[3]; data->Sync[target].SyncOffset = data->MsgBuffer[4]; //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]); *sync_neg = SYNC_OK; } else { data->Sync[target].SyncPeriod = 0; data->Sync[target].SyncOffset = 0; *sync_neg = SYNC_NG; } nsp_analyze_sdtr(tmpSC); } /**/ /* 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; nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen); show_message(data); break; case BUSPHASE_SELECT: default: nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other"); break; } goto out;timer_out: nsp_start_timer(tmpSC, 1000/102); out: nsp_write(base, IRQCONTROL, 0); /* clear IRQ mask */ spin_unlock_irqrestore(HOST_LOCK, flags); //nsp_dbg(NSP_DEBUG_INTR, "out"); return IRQ_RETVAL(handled);}/*----------------------------------------------------------------*//* look for ninja3 card and init if found *//*----------------------------------------------------------------*/static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -