/**************************************************************** * Name: release_ata_mem * * Description: free memory allocated to the PRD table * unmap the data buffers of the scsi command * free completion_info data structure. * Parameters: pInfo: pointer to the data structure returned by the * completion call back function to identify the origial command * ****************************************************************/ void release_ata_mem(struct mv_comp_info * pInfo) { IAL_ADAPTER_T *pAdapter = MV_IAL_ADAPTER(pInfo->SCpnt->device->host); IAL_HOST_T *pHost = HOSTDATA(pInfo->SCpnt->device->host); if (pInfo->cpu_PRDpnt) { mv_ial_lib_prd_free(pHost, pInfo->allocated_entries, pInfo->dma_PRDpnt, pInfo->cpu_PRDpnt); if (pInfo->SCpnt->use_sg) { pci64_unmap_sg(pAdapter->pcidev, (struct scatterlist *)pInfo->SCpnt->request_buffer, pInfo->SCpnt->use_sg, scsi_to_pci_dma_dir(pInfo->SCpnt->sc_data_direction)); } else { pci64_unmap_page(pAdapter->pcidev, pInfo->single_buff_busaddr, pInfo->SCpnt->request_bufflen, scsi_to_pci_dma_dir(pInfo->SCpnt->sc_data_direction)); } } pInfo->cpu_PRDpnt = NULL; kfree(pInfo->pSALBlock); }
/**************************************************************** * Name: BuildSgList :LOCAL * * Description: Build the scatter gather list for controller. * * Parameters: SCpnt - Pointer to SCSI command structure. * padapter - Pointer to adapter information structure. * pdev - Pointer to adapter device structure. * * Returns: Non-zero in not scatter gather. * ****************************************************************/ static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev) { int z; int zc; struct scatterlist *sg; if ( SCpnt->use_sg ) { sg = (struct scatterlist *)SCpnt->request_buffer; zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); for ( z = 0; z < zc; z++ ) { pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg)); pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++)); } outl (pdev->scatGathDma, padapter->mb2); outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3); return FALSE; } if ( !SCpnt->request_bufflen) { outl (0, padapter->mb2); outl (0, padapter->mb3); return TRUE; } SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction)); outl (SCpnt->SCp.have_data_in, padapter->mb2); outl (SCpnt->request_bufflen, padapter->mb3); return TRUE; }
/* map to pci */ int mv_ial_lib_generate_prd(MV_SATA_ADAPTER *pMvSataAdapter, struct scsi_cmnd *SCpnt, MV_SATA_EDMA_PRD_ENTRY **ppPRD_table, dma_addr_t *pPRD_dma_address, unsigned int *pPrd_size, dma_addr_t *pBusaddr) { IAL_ADAPTER_T *pAdapter = MV_IAL_ADAPTER(SCpnt->device->host); IAL_HOST_T *pHost = HOSTDATA(SCpnt->device->host); struct scatterlist *sg; unsigned int prd_count; /*should be removed*/ if (SCpnt->request_bufflen > (SCpnt->device->host->max_sectors << 9)) { printk("ERROR: request length exceeds the maximum alowed value, %x %x\n", pMvSataAdapter->pciConfigDeviceId, pMvSataAdapter->pciConfigRevisionId); } if (SCpnt->use_sg) { unsigned int sg_count; unsigned int i; sg = (struct scatterlist *) SCpnt->request_buffer; sg_count = pci64_map_sg(pAdapter->pcidev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); if (sg_count != SCpnt->use_sg) printk("WARNING sg_count(%d) != SCpnt->use_sg(%d)\n", (unsigned int)sg_count, SCpnt->use_sg); *pPrd_size = MV_PRD_TABLE_SIZE; *ppPRD_table = (MV_SATA_EDMA_PRD_ENTRY*)mv_ial_lib_prd_allocate(pHost); if (ppPRD_table == NULL) { mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG_ERROR, "Failed to allocate PRD table, requested size=%d\n" , *pPrd_size); pci64_unmap_sg(pAdapter->pcidev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); return -1; } prd_count=0; for (i=0; (i < sg_count) && (sg_dma_len(sg)); i++, sg++) { int isEOT; isEOT =((i+1 < sg_count) && (sg_dma_len(&sg[1]))) ? 0 : 1; if (mv_ial_lib_add_buffer_to_prd_table(pMvSataAdapter, *ppPRD_table, *pPrd_size, &prd_count, sg_dma_address(sg), sg_dma_len(sg), isEOT)) { mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG_ERROR," in building PRD table from scatterlist, " "prd_size=%d, prd_count=%d\n", *pPrd_size, prd_count); pci64_unmap_sg(pAdapter->pcidev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); return -1; } } *pPRD_dma_address = pci64_map_page(pAdapter->pcidev, *ppPRD_table, MV_EDMA_PRD_ENTRY_SIZE * (*pPrd_size), PCI_DMA_TODEVICE); } else if (SCpnt->request_bufflen && SCpnt->sc_data_direction != PCI_DMA_NONE) { *pPrd_size = MV_PRD_TABLE_SIZE; *ppPRD_table = (MV_SATA_EDMA_PRD_ENTRY*)mv_ial_lib_prd_allocate(pHost); if (*ppPRD_table == NULL) { mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG_ERROR, "Failed to allocate PRD table, requested size=%d\n", *pPrd_size); return -1; } *pBusaddr = pci64_map_page(pAdapter->pcidev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); prd_count = 0; if (mv_ial_lib_add_buffer_to_prd_table(pMvSataAdapter, *ppPRD_table, *pPrd_size, &prd_count, *pBusaddr, SCpnt->request_bufflen, 1)) { mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG_ERROR, " in building PRD table from buffer\n"); pci64_unmap_page(pAdapter->pcidev, *pBusaddr, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); return -1; } *pPRD_dma_address = pci64_map_page(pAdapter->pcidev, *ppPRD_table, MV_EDMA_PRD_ENTRY_SIZE* (*pPrd_size), PCI_DMA_TODEVICE); } mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG, "PRD table allocated %p\n", *ppPRD_table); mvLogMsg(MV_IAL_LOG_ID, MV_DEBUG, "PRD table allocated (dma) %x \n", *pPRD_dma_address); return 0; }
/**************************************************************** * Name: Irq_Handler :LOCAL * * Description: Interrupt handler. * * Parameters: irq - Hardware IRQ number. * dev_id - * regs - * * Returns: TRUE if drive is not ready in time. * ****************************************************************/ static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs) { struct Scsi_Host *shost = NULL; // Pointer to host data block PADAPTER2000 padapter; // Pointer to adapter control structure PDEV2000 pdev; Scsi_Cmnd *SCpnt; UCHAR tag = 0; UCHAR tag0; ULONG error; int pun; int bus; int z; unsigned long flags; /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); DEB(printk ("\npci2000 received interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process { if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) ) { tag = inb_p (HOSTDATA(PsiHost[z])->tag); if ( tag ) { shost = PsiHost[z]; break; } } } if ( !shost ) { DEB (printk ("\npci2000: not my interrupt")); goto irq_return; } padapter = HOSTDATA(shost); tag0 = tag & 0x7F; // mask off the error bit for ( bus = 0; bus < MAX_BUS; bus++ ) // scan the busses { for ( pun = 0; pun < MAX_UNITS; pun++ ) // scan the targets { pdev = &padapter->dev[bus][pun]; if ( !pdev->tag ) continue; if ( pdev->tag == tag0 ) // is this it? { pdev->tag = 0; SCpnt = pdev->SCpnt; goto unmapProceed; } } } outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op goto irq_return;; // done, but, with what? unmapProceed:; if ( !bus ) { switch ( SCpnt->cmnd[0] ) { case SCSIOP_TEST_UNIT_READY: pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE); goto irqProceed; case SCSIOP_READ_CAPACITY: pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE); goto irqProceed; case SCSIOP_VERIFY: case SCSIOP_START_STOP_UNIT: case SCSIOP_MEDIUM_REMOVAL: goto irqProceed; } } if ( SCpnt->SCp.have_data_in ) pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); else { if ( SCpnt->use_sg ) pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); } irqProceed:; if ( tag & ERR08_TAGGED ) // is there an error here? { if ( WaitReady (padapter) ) { OpDone (SCpnt, DID_TIME_OUT << 16); goto irq_return;; } outb_p (tag0, padapter->mb0); // get real error code outb_p (CMD_ERROR, padapter->cmd); if ( WaitReady (padapter) ) // wait for controller to suck up the op { OpDone (SCpnt, DID_TIME_OUT << 16); goto irq_return;; } error = inl (padapter->mb0); // get error data outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op DEB (printk ("status: %lX ", error)); if ( error == 0x00020002 ) // is this error a check condition? { if ( bus ) // are we doint SCSI commands? { OpDone (SCpnt, (DID_OK << 16) | 2); goto irq_return;; } if ( *SCpnt->cmnd == SCSIOP_TEST_UNIT_READY ) OpDone (SCpnt, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2); // test caller we have sense data too else OpDone (SCpnt, DID_ERROR << 16); goto irq_return;; } OpDone (SCpnt, DID_ERROR << 16); goto irq_return;; } outb_p (0xFF, padapter->tag); // clear the op interrupt outb_p (CMD_DONE, padapter->cmd); // complete the op OpDone (SCpnt, DID_OK << 16); irq_return:; /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); }