📄 nsp_cs.c
字号:
/* 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); return IRQ_HANDLED; 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); return IRQ_HANDLED; } /* fall thru */ default: if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { return IRQ_HANDLED; } 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); return IRQ_HANDLED; } return IRQ_HANDLED; } /* 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); return IRQ_HANDLED; } 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"); return IRQ_HANDLED; } 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; } //nsp_dbg(NSP_DEBUG_INTR, "out"); return IRQ_HANDLED; timer_out: nsp_start_timer(tmpSC, 1000/102); return IRQ_HANDLED;}#ifdef NSP_DEBUG#include "nsp_debug.c"#endif /* NSP_DEBUG *//*----------------------------------------------------------------*//* look for ninja3 card and init if found *//*----------------------------------------------------------------*/static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht){ struct Scsi_Host *host; /* registered host structure */ nsp_hw_data *data_b = &nsp_data_base, *data; nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));#else host = scsi_register(sht, sizeof(nsp_hw_data));#endif if (host == NULL) { nsp_dbg(NSP_DEBUG_INIT, "host failed"); return NULL; } memcpy(host->hostdata, data_b, sizeof(nsp_hw_data)); data = (nsp_hw_data *)host->hostdata; data->ScsiInfo->host = host;#ifdef NSP_DEBUG data->CmdId = 0;#endif nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber); host->unique_id = data->BaseAddress; host->io_port = data->BaseAddress; host->n_io_port = data->NumAddress; host->irq = data->IrqNumber; host->base = data->MmioAddress; spin_lock_init(&(data->Lock)); snprintf(data->nspinfo, sizeof(data->nspinfo), "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", host->io_port, host->io_port + host->n_io_port - 1, host->base, host->irq); sht->name = data->nspinfo; nsp_dbg(NSP_DEBUG_INIT, "end"); return host; /* detect done. */}#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))static int nsp_detect_old(struct scsi_host_template *sht){ if (nsp_detect(sht) == NULL) { return 0; } else { //MOD_INC_USE_COUNT; return 1; }}static int nsp_release_old(struct Scsi_Host *shpnt){ //nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; /* PCMCIA Card Service dose same things below. */ /* So we do nothing. */ //if (shpnt->irq) { // free_irq(shpnt->irq, data->ScsiInfo); //} //if (shpnt->io_port) { // release_region(shpnt->io_port, shpnt->n_io_port); //} //MOD_DEC_USE_COUNT; return 0;}#endif/*----------------------------------------------------------------*//* return info string *//*----------------------------------------------------------------*/static const char *nsp_info(struct Scsi_Host *shpnt){ nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; return data->nspinfo;}#undef SPRINTF#define SPRINTF(args...) \ do { \ if(length > (pos - buffer)) { \ pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ } \ } while(0)static intnsp_proc_info(#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) struct Scsi_Host *host,#endif char *buffer, char **start, off_t offset, int length,#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) int hostno,#endif int inout){ int id; char *pos = buffer; int thislength; int speed; unsigned long flags; nsp_hw_data *data;#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) struct Scsi_Host *host;#else int hostno;#endif if (inout) { return -EINVAL; }#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) hostno = host->host_no;#else /* search this HBA host */ host = scsi_host_hn_get(hostno); if (host == NULL) { return -ESRCH; }#endif data = (nsp_hw_data *)host->hostdata; SPRINTF("NinjaSCSI status\n\n"); SPRINTF("Driver version: $Revision: 1.23 $\n"); SPRINTF("SCSI host No.: %d\n", hostno); SPRINTF("IRQ: %d\n", host->irq); SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); SPRINTF("burst transfer mode: "); switch (nsp_burst_mode) { case BURST_IO8: SPRINTF("io8"); break; case BURST_IO32: SPRINTF("io32"); break; case BURST_MEM32: SPRINTF("mem32"); break; default: SPRINTF("???"); break; } SPRINTF("\n"); spin_lock_irqsave(&(data->Lock), flags); SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); spin_unlock_irqrestore(&(data->Lock), flags); SPRINTF("SDTR status\n"); for(id = 0; id < ARRAY_SIZE(data->Sync); id++) { SPRINTF("id %d: ", id); if (id == host->this_id) { SPRINTF("----- NinjaSCSI-3 host adapter\n"); continue; } switch(data->Sync[id].SyncNegotiation) { case SYNC_OK: SPRINTF(" sync"); break; case SYNC_NG: SPRINTF("async"); break; case SYNC_NOT_YET: SPRINTF(" none"); break; default: SPRINTF("?????"); break; } if (data->Sync[id].SyncPeriod != 0) { speed = 1000000 / (data->Sync[id].SyncPeriod * 4); SPRINTF(" transfer %d.%dMB/s, offset %d", speed / 1000, speed % 1000, data->Sync[id].SyncOffset ); } SPRINTF("\n"); } thislength = pos - (buffer + offset); if(thislength < 0) { *start = NULL; return 0; } thislength = min(thislength, length); *start = buffer + offset; return thislength;}#undef SPRINTF/*---------------------------------------------------------------*//* error handler *//*---------------------------------------------------------------*//*static int nsp_eh_abort(Scsi_Cmnd *SCpnt){ nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); return nsp_eh_bus_reset(SCpnt);}*/static int nsp_bus_reset(nsp_hw_data *data){ unsigned int base = data->BaseAddress; int i; nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); mdelay(100); /* 100ms */ nsp_index_write(base, SCSIBUSCTRL, 0); for(i = 0; i < 5; i++) { nsp_index_read(base, IRQPHASESENCE); /* dummy read */ } nsphw_init_sync(data); nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); return SUCCESS;}static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt){ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); return nsp_bus_reset(data);}static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt){ nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; nsp_dbg(NSP_DEBUG_BUSRESET, "in"); nsphw_init(data); return SUCCESS;}/********************************************************************** PCMCIA functions**********************************************************************//*====================================================================== nsp_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. The dev_link structure is initialized, but we don't actually configure the card at this point -- we wait until we receive a card insertion event.======================================================================*/static dev_link_t *nsp_cs_attach(void){ scsi_info_t *info; client_reg_t client_reg; dev_link_t *link; int ret; nsp_hw_data *data = &nsp_data_base; nsp_dbg(NSP_DEBUG_INIT, "in"); /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { return NULL; } memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; data->ScsiInfo = info; nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info); /* The io structure describes IO port mapping */ link->io.NumPorts1 = 0x10; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; /* not used */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; /* Interrupt handler */ link->irq.Handler = &nspintr; link->irq.Instance = info; link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM); /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Version = 0x0210;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -