📄 i60uscsi.c
字号:
/***************************************************************************/void setup_SCBs(ORC_HCS * hcsp){ ORC_SCB *pVirScb; int i; UCHAR j; ESCB *pVirEscb; PVOID pPhysEscb; PVOID tPhysEscb; j = 0; pVirScb = NULL; tPhysEscb = (PVOID) NULL; pPhysEscb = (PVOID) NULL; /* Setup SCB HCS_Base and SCB Size registers */ ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, orc_num_scb); /* Total number of SCBs */ /* SCB HCS_Base address 0 */ ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray); /* SCB HCS_Base address 1 */ ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray); /* setup scatter list address with one buffer */ pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; pVirEscb = (ESCB *) hcsp->HCS_virEscbArray; for (i = 0; i < orc_num_scb; i++) { pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i)); pVirScb->SCB_SGPAddr = (U32) pPhysEscb; pVirScb->SCB_SensePAddr = (U32) pPhysEscb; pVirScb->SCB_EScb = pVirEscb; pVirScb->SCB_ScbIdx = i; pVirScb++; pVirEscb++; } return;}/***************************************************************************/static void initAFlag(ORC_HCS * hcsp){ UCHAR i, j; for (i = 0; i < MAX_CHANNELS; i++) { for (j = 0; j < 8; j++) { hcsp->BitAllocFlag[i][j] = 0xffffffff; } }}/***************************************************************************/int init_orchid(ORC_HCS * hcsp){ UBYTE *readBytep; USHORT revision; UCHAR i; initAFlag(hcsp); ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */ if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */ revision = get_FW_version(hcsp); if (revision == 0xFFFF) { ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ if (waitChipReady(hcsp) == FALSE) return (-1); load_FW(hcsp); /* Download FW */ setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */ if (waitFWReady(hcsp) == FALSE) return (-1); /* Wait for firmware ready */ } else { setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ } } else { /* Orchid is not Ready */ ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */ if (waitChipReady(hcsp) == FALSE) return (-1); load_FW(hcsp); /* Download FW */ setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */ ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */ /* clear HOSTSTOP */ if (waitFWReady(hcsp) == FALSE) /* Wait for firmware ready */ return (-1); }/*------------- get serial EEProm settting -------*/ read_eeprom(hcsp); if (nvramp->Revision != 1) return (-1); hcsp->HCS_SCSI_ID = nvramp->SCSI0Id; hcsp->HCS_BIOS = nvramp->BIOSConfig1; hcsp->HCS_MaxTar = MAX_TARGETS; readBytep = (UCHAR *) & (nvramp->Target00Config); for (i = 0; i < 16; readBytep++, i++) { hcsp->TargetFlag[i] = *readBytep; hcsp->MaximumTags[i] = orc_num_scb; } /* for */ if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */ hcsp->HCS_Flags |= HCF_SCSI_RESET; } ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */ return (0);}/***************************************************************************** Function name : orc_reset_scsi_bus Description : Reset registers, reset a hanging bus and kill active and disconnected commands for target w/o soft reset Input : pHCB - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block.*****************************************************************************/int orc_reset_scsi_bus(ORC_HCS * pHCB){ /* I need Host Control Block Information */ ULONG flags; spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); initAFlag(pHCB); /* reset scsi bus */ ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); if (waitSCSIRSTdone(pHCB) == FALSE) { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); return (SCSI_RESET_ERROR); } else { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); return (SCSI_RESET_SUCCESS); }}/***************************************************************************** Function name : orc_device_reset Description : Reset registers, reset a hanging bus and kill active and disconnected commands for target w/o soft reset Input : pHCB - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block.*****************************************************************************/int orc_device_reset(ORC_HCS * pHCB, ULONG SCpnt, unsigned int target, unsigned int ResetFlags){ /* I need Host Control Block Information */ ORC_SCB *pScb; ESCB *pVirEscb; ORC_SCB *pVirScb; UCHAR i; ULONG flags; spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags); pScb = (ORC_SCB *) NULL; pVirEscb = (ESCB *) NULL; /* setup scatter list address with one buffer */ pVirScb = (ORC_SCB *) pHCB->HCS_virScbArray; initAFlag(pHCB); /* device reset */ for (i = 0; i < orc_num_scb; i++) { pVirEscb = pVirScb->SCB_EScb; if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) break; pVirScb++; } if (i == orc_num_scb) { printk("Unable to Reset - No SCB Found\n"); spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); return (SCSI_RESET_NOT_RUNNING); } if ((pScb = orc_alloc_scb(pHCB)) == NULL) { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); return (SCSI_RESET_NOT_RUNNING); } pScb->SCB_Opcode = ORC_BUSDEVRST; pScb->SCB_Target = target; pScb->SCB_HaStat = 0; pScb->SCB_TaStat = 0; pScb->SCB_Status = 0x0; pScb->SCB_Link = 0xFF; pScb->SCB_Reserved0 = 0; pScb->SCB_Reserved1 = 0; pScb->SCB_XferLen = 0; pScb->SCB_SGLen = 0; pVirEscb->SCB_Srb = 0; if (ResetFlags & SCSI_RESET_SYNCHRONOUS) { pVirEscb->SCB_Srb = (unsigned char *) SCpnt; } orc_exec_scb(pHCB, pScb); /* Start execute SCB */ spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); return SCSI_RESET_PENDING;}/***************************************************************************/ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp){ ORC_SCB *pTmpScb; UCHAR Ch; ULONG idx; UCHAR index; UCHAR i; Ch = hcsp->HCS_Index; for (i = 0; i < 8; i++) { for (index = 0; index < 32; index++) { if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) { hcsp->BitAllocFlag[Ch][i] &= ~(1 << index); break; } } idx = index + 32 * i; pTmpScb = (PVOID) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB))); return (pTmpScb); } return (NULL);}ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp){ ORC_SCB *pTmpScb; ULONG flags; spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); pTmpScb = __orc_alloc_scb(hcsp); spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); return (pTmpScb);}/***************************************************************************/void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp){ ULONG flags; UCHAR Index; UCHAR i; UCHAR Ch; spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); Ch = hcsp->HCS_Index; Index = scbp->SCB_ScbIdx; i = Index / 32; Index %= 32; hcsp->BitAllocFlag[Ch][i] |= (1 << Index); spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);}/***************************************************************************** Function name : Addinia100_into_Adapter_table Description : This function will scan PCI bus to get all Orchid card Input : None. Output : None. Return : SUCCESSFUL - Successful scan ohterwise - No drives founded*****************************************************************************/int Addinia100_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt, BYTE bBus, BYTE bDevice){ unsigned int i, j; for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { if (inia100_adpt[i].ADPT_BIOS < wBIOS) continue; if (inia100_adpt[i].ADPT_BIOS == wBIOS) { if (inia100_adpt[i].ADPT_BASE == wBASE) { if (inia100_adpt[i].ADPT_Bus != 0xFF) return (FAILURE); } else if (inia100_adpt[i].ADPT_BASE < wBASE) continue; } for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) { inia100_adpt[j].ADPT_BASE = inia100_adpt[j - 1].ADPT_BASE; inia100_adpt[j].ADPT_INTR = inia100_adpt[j - 1].ADPT_INTR; inia100_adpt[j].ADPT_BIOS = inia100_adpt[j - 1].ADPT_BIOS; inia100_adpt[j].ADPT_Bus = inia100_adpt[j - 1].ADPT_Bus; inia100_adpt[j].ADPT_Device = inia100_adpt[j - 1].ADPT_Device; } inia100_adpt[i].ADPT_BASE = wBASE; inia100_adpt[i].ADPT_INTR = bInterrupt; inia100_adpt[i].ADPT_BIOS = wBIOS; inia100_adpt[i].ADPT_Bus = bBus; inia100_adpt[i].ADPT_Device = bDevice; return (SUCCESSFUL); } return (FAILURE);}/***************************************************************************** Function name : init_inia100Adapter_table Description : This function will scan PCI bus to get all Orchid card Input : None. Output : None. Return : SUCCESSFUL - Successful scan ohterwise - No drives founded*****************************************************************************/void init_inia100Adapter_table(void){ int i; for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { /* Initialize adapter structure */ inia100_adpt[i].ADPT_BIOS = 0xffff; inia100_adpt[i].ADPT_BASE = 0xffff; inia100_adpt[i].ADPT_INTR = 0xff; inia100_adpt[i].ADPT_Bus = 0xff; inia100_adpt[i].ADPT_Device = 0xff; }}/***************************************************************************** Function name : get_orcPCIConfig Description : Input : pHCB - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block.*****************************************************************************/void get_orcPCIConfig(ORC_HCS * pCurHcb, int ch_idx){ pCurHcb->HCS_Base = inia100_adpt[ch_idx].ADPT_BASE; /* Supply base address */ pCurHcb->HCS_BIOS = inia100_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */ pCurHcb->HCS_Intr = inia100_adpt[ch_idx].ADPT_INTR; /* Supply interrupt line */ return;}/***************************************************************************** Function name : abort_SCB Description : Abort a queued command. (commands that are on the bus can't be aborted easily) Input : pHCB - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block.*****************************************************************************/int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb){ unsigned char bData, bStatus; ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */ ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ return (FALSE); ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */ ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); if (waitHDOoff(hcsp) == FALSE) /* Wait HDO off */ return (FALSE); if (waitHDIset(hcsp, &bData) == FALSE) /* Wait HDI set */ return (FALSE); bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA); ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */ if (bStatus == 1) /* 0 - Successfully */ return (FALSE); /* 1 - Fail */ return (TRUE);}/***************************************************************************** Function name : inia100_abort Description : Abort a queued command. (commands that are on the bus can't be aborted easily) Input : pHCB - Pointer to host adapter structure Output : None. Return : pSRB - Pointer to SCSI request block.*****************************************************************************/int orc_abort_srb(ORC_HCS * hcsp, ULONG SCpnt){ ESCB *pVirEscb; ORC_SCB *pVirScb; UCHAR i; ULONG flags; spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags); pVirScb = (ORC_SCB *) hcsp->HCS_virScbArray; for (i = 0; i < orc_num_scb; i++, pVirScb++) { pVirEscb = pVirScb->SCB_EScb; if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == (unsigned char *) SCpnt)) { if (pVirScb->SCB_TagMsg == 0) { spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); return (SCSI_ABORT_BUSY); } else { if (abort_SCB(hcsp, pVirScb)) { pVirEscb->SCB_Srb = NULL; spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); return (SCSI_ABORT_SUCCESS); } else { spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); return (SCSI_ABORT_NOT_RUNNING); } } } } spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); return (SCSI_ABORT_NOT_RUNNING);}/*********************************************************************** Routine Description: This is the interrupt service routine for the Orchid SCSI adapter. It reads the interrupt register to determine if the adapter is indeed the source of the interrupt and clears the interrupt at the device. Arguments: HwDeviceExtension - HBA miniport driver's adapter data storage Return Value:***********************************************************************/void orc_interrupt( ORC_HCS * hcsp){ BYTE bScbIdx; ORC_SCB *pScb; if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) { return; // (FALSE); } do { bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE); pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx)); pScb->SCB_Status = 0x0; inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb); } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT)); return; //(TRUE);} /* End of I1060Interrupt() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -