nsp32.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,409 行 · 第 1/5 页
C
2,409 行
default: nsp32_msg(KERN_WARNING, "phase chg/other phase?"); nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat); show_busphase(busphase); break; } goto out; } /* PCI_IRQ */ if (irq_stat & IRQSTATUS_PCI_IRQ) { nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred"); /* Do nothing */ } /* BMCNTERR_IRQ */ if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) { nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! "); /* * TODO: To be implemented improving bus master * transfer reliablity when BMCNTERR is occurred in * AutoSCSI phase described in specification. */ }#if 0 nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); show_busphase(busphase);#endif out: /* disable IRQ mask */ nsp32_write2(base, IRQ_CONTROL, 0); out2:#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) spin_unlock_irqrestore(host->host_lock, flags);#else spin_unlock_irqrestore(&io_request_lock, flags);#endif nsp32_dbg(NSP32_DEBUG_INTR, "exit"); return IRQ_RETVAL(handled);}#undef SPRINTF#define SPRINTF(args...) \ do { \ if(length > (pos - buffer)) { \ pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ } \ } while(0)static int nsp32_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){ char *pos = buffer; int thislength; unsigned long flags; nsp32_hw_data *data;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) int hostno;#else struct Scsi_Host *host;#endif unsigned int base; unsigned char mode_reg; int id, speed; long model; /* Write is not supported, just return. */ if (inout == TRUE) { 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 = (nsp32_hw_data *)host->hostdata; base = host->io_port; SPRINTF("NinjaSCSI-32 status\n\n"); SPRINTF("Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version); 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("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); mode_reg = nsp32_index_read1(base, CHIP_MODE); model = data->pci_devid->driver_data;#ifdef CONFIG_PM SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no");#endif SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); 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->target); id++) { SPRINTF("id %d: ", id); if (id == host->this_id) { SPRINTF("----- NinjaSCSI-32 host adapter\n"); continue; } if (data->target[id].sync_flag == SDTR_DONE) { if (data->target[id].period == 0 && data->target[id].offset == ASYNC_OFFSET ) { SPRINTF("async"); } else { SPRINTF(" sync"); } } else { SPRINTF(" none"); } if (data->target[id].period != 0) { speed = 1000000 / (data->target[id].period * 4); SPRINTF(" transfer %d.%dMB/s, offset %d", speed / 1000, speed % 1000, data->target[id].offset ); } SPRINTF("\n"); } thislength = pos - (buffer + offset); if(thislength < 0) { *start = NULL; return 0; } thislength = min(thislength, length); *start = buffer + offset; return thislength;}#undef SPRINTF/* * Reset parameters and call scsi_done for data->cur_lunt. * Be careful setting SCpnt->result = DID_* before calling this function. */static void nsp32_scsi_done(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; /* * unmap pci */ if (SCpnt->request_bufflen == 0) { goto skip; } if (SCpnt->use_sg) { pci_unmap_sg(data->Pci, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } else { pci_unmap_single(data->Pci, (u32)SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } skip: /* * clear TRANSFERCONTROL_BM_START */ nsp32_write2(base, TRANSFER_CONTROL, 0); nsp32_write4(base, BM_CNT, 0); /* * call scsi_done */ (*SCpnt->scsi_done)(SCpnt); /* * reset parameters */ data->cur_lunt->SCpnt = NULL; data->cur_lunt = NULL; data->cur_target = NULL; data->CurrentSC = NULL;}/* * Bus Free Occur * * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase * with ACK reply when below condition is matched: * MsgIn 00: Command Complete. * MsgIn 02: Save Data Pointer. * MsgIn 04: Diconnect. * In other case, unexpected BUSFREE is detected. */static int nsp32_busfree_occur(Scsi_Cmnd *SCpnt, unsigned short execph){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph); show_autophase(execph); nsp32_write4(base, BM_CNT, 0); nsp32_write2(base, TRANSFER_CONTROL, 0); /* * MsgIn 02: Save Data Pointer * * VALID: * Save Data Pointer is received. Adjust pointer. * * NO-VALID: * SCSI-3 says if Save Data Pointer is not received, then we restart * processing and we can't adjust any SCSI data pointer in next data * phase. */ if (execph & MSGIN_02_VALID) { nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid"); /* * Check sack_cnt/saved_sack_cnt, then adjust sg table if * needed. */ if (!(execph & MSGIN_00_VALID) && ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) { unsigned int sacklen, s_sacklen; /* * Read SACK count and SAVEDSACK count, then compare. */ sacklen = nsp32_read4(base, SACK_CNT ); s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); /* * If SAVEDSACKCNT == 0, it means SavedDataPointer is * come after data transfering. */ if (s_sacklen > 0) { /* * Comparing between sack and savedsack to * check the condition of AutoMsgIn03. * * If they are same, set msgin03 == TRUE, * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at * reselection. On the other hand, if they * aren't same, set msgin03 == FALSE, and * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at * reselection. */ if (sacklen != s_sacklen) { data->cur_lunt->msgin03 = FALSE; } else { data->cur_lunt->msgin03 = TRUE; } nsp32_adjust_busfree(SCpnt, s_sacklen); } } /* This value has not substitude with valid value yet... */ //data->cur_lunt->save_datp = data->cur_datp; } else { /* * no processing. */ } if (execph & MSGIN_03_VALID) { /* MsgIn03 was valid to be processed. No need processing. */ } /* * target SDTR check */ if (data->cur_target->sync_flag & SDTR_INITIATOR) { /* * SDTR negotiation pulled by the initiator has not * finished yet. Fall back to ASYNC mode. */ nsp32_set_async(data, data->cur_target); data->cur_target->sync_flag &= ~SDTR_INITIATOR; data->cur_target->sync_flag |= SDTR_DONE; } else if (data->cur_target->sync_flag & SDTR_TARGET) { /* * SDTR negotiation pulled by the target has been * negotiating. */ if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) { /* * If valid message is received, then * negotiation is succeeded. */ } else { /* * On the contrary, if unexpected bus free is * occurred, then negotiation is failed. Fall * back to ASYNC mode. */ nsp32_set_async(data, data->cur_target); } data->cur_target->sync_flag &= ~SDTR_TARGET; data->cur_target->sync_flag |= SDTR_DONE; } /* * It is always ensured by SCSI standard that initiator * switches into Bus Free Phase after * receiving message 00 (Command Complete), 04 (Disconnect). * It's the reason that processing here is valid. */ if (execph & MSGIN_00_VALID) { /* MsgIn 00: Command Complete */ nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete"); SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); SCpnt->SCp.Message = 0; nsp32_dbg(NSP32_DEBUG_BUSFREE, "normal end stat=0x%x resid=0x%x\n", SCpnt->SCp.Status, SCpnt->resid); SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); nsp32_scsi_done(SCpnt); /* All operation is done */ return TRUE; } else if (execph & MSGIN_04_VALID) { /* MsgIn 04: Disconnect */ SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); SCpnt->SCp.Message = 4; nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect"); return TRUE; } else { /* Unexpected bus free */ nsp32_msg(KERN_WARNING, "unexpected bus free occurred"); /* DID_ERROR? */ //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); SCpnt->result = DID_ERROR << 16; nsp32_scsi_done(SCpnt); return TRUE; } return FALSE;}/* * nsp32_adjust_busfree - adjusting SG table * * Note: This driver adjust the SG table using SCSI ACK * counter instead of BMCNT counter! */static void nsp32_adjust_busfree(Scsi_Cmnd *SCpnt, unsigned int s_sacklen){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; int old_entry = data->cur_entry; int new_entry; int sg_num = data->cur_lunt->sg_num; nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; unsigned int restlen, sentlen; u32_le len, addr; nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid); /* adjust saved SACK count with 4 byte start address boundary */ s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3; /* * calculate new_entry from sack count and each sgt[].len * calculate the byte which is intent to send */ sentlen = 0; for (new_entry = old_entry; new_entry < sg_num; new_entry++) { sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND); if (sentlen > s_sacklen) { break; } } /* all sgt is processed */ if (new_entry == sg_num) { goto last; } if (sentlen == s_sacklen) { /* XXX: confirm it's ok or not */ /* In this case, it's ok because we are at the head element of the sg. restlen is correctly calculated. */ } /* calculate the rest length for transfering */ restlen = sentlen - s_sacklen; /* update adjusting current SG table entry */ len = le32_to_cpu(sgt[new_entry].len); addr = le32_to_cpu(sgt[new_entry].addr); addr += (len - restlen); sgt[new_entry].addr = cpu_to_le32(addr); sgt[new_entry].len = cpu_to_le32(restlen); /* set cur_entry with new_entry */ data->cur_entry = new_entry; return; last: if (SCpnt->resid < sentlen) { nsp32_msg(KERN_ERR, "resid underflow"); } SCpnt->resid -= sentlen; nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid); /* update hostdata and lun */ return;}/* * It's called MsgOut phase occur. * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in * message out phase. It, however, has more than 3 messages, * HBA creates the interrupt and we have to process by hand. */static void nsp32_msgout_occur(Scsi_Cmnd *SCpnt){ nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; unsigned int base = SCpnt->device->host->io_port; //unsigned short command; long new_sgtp; int i; nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "enter: msgout_len: 0x%x", data->msgout_len); /* * If MsgOut phase is occurred without having any * message, then No_Operation is sent (SCSI-2). */ if (data->msgout_len == 0) { nsp32_build_nop(SCpnt);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?