diff --git a/sys/dev/pms/freebsd/driver/ini/src/agtiapi.c b/sys/dev/pms/freebsd/driver/ini/src/agtiapi.c index a2b20c9e9264..a4efec572864 100644 --- a/sys/dev/pms/freebsd/driver/ini/src/agtiapi.c +++ b/sys/dev/pms/freebsd/driver/ini/src/agtiapi.c @@ -1,6638 +1,6641 @@ /******************************************************************************* ** *Copyright (c) 2014 PMC-Sierra, Inc. All rights reserved. * *Redistribution and use in source and binary forms, with or without modification, are permitted provided *that the following conditions are met: *1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. *2. Redistributions in binary form must reproduce the above copyright notice, *this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * *THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * *INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS *OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE ** *******************************************************************************/ #include __FBSDID("$FreeBSD$"); #include #define MAJOR_REVISION 1 #define MINOR_REVISION 3 #define BUILD_REVISION 10800 #include // defines used in kernel.h #include #include #include #include #include // types used in module initialization #include // cdevsw struct #include // uio struct #include #include #include // structs, prototypes for pci bus stuff #include #include #include #include // 1. for vtophys #include // 2. for vtophys #include // For pci_get macros #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #include #include #include #include #include #include #include #include #include #include MALLOC_DEFINE( M_PMC_MCCB, "CCB List", "CCB List for PMCS driver" ); MALLOC_DEFINE( M_PMC_MSTL, "STLock malloc", "allocated in agtiapi_attach as memory for lock use" ); MALLOC_DEFINE( M_PMC_MDVT, "ag_device_t malloc", "allocated in agtiapi_attach as mem for ag_device_t pDevList" ); MALLOC_DEFINE( M_PMC_MPRT, "ag_portal_data_t malloc", "allocated in agtiapi_attach as mem for *pPortalData" ); MALLOC_DEFINE( M_PMC_MDEV, "tiDeviceHandle_t * malloc", "allocated in agtiapi_GetDevHandle as local mem for **agDev" ); MALLOC_DEFINE( M_PMC_MFLG, "lDevFlags * malloc", "allocated in agtiapi_GetDevHandle as local mem for * flags" ); #ifdef LINUX_PERBI_SUPPORT MALLOC_DEFINE( M_PMC_MSLR, "ag_slr_map_t malloc", "mem allocated in agtiapi_attach for pSLRList" ); MALLOC_DEFINE( M_PMC_MTGT, "ag_tgt_map_t malloc", "mem allocated in agtiapi_attach for pWWNList" ); #endif MALLOC_DEFINE(TEMP,"tempbuff","buffer for payload"); MALLOC_DEFINE(TEMP2, "tempbuff", "buffer for agtiapi_getdevlist"); STATIC U32 agtiapi_intx_mode = 0; STATIC U08 ag_Perbi = 0; STATIC U32 agtiapi_polling_mode = 0; STATIC U32 ag_card_good = 0; // * total card initialized STATIC U32 ag_option_flag = 0; // * adjustable parameter flag STATIC U32 agtiapi_1st_time = 1; STATIC U32 ag_timeout_secs = 10; //Made timeout equivalent to linux U32 gTiDebugLevel = 1; S32 ag_encryption_enable = 0; atomic_t outstanding_encrypted_io_count; #define cache_line_size() CACHE_LINE_SIZE #define PMCoffsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define CPU_TO_LE32(dst, src) \ dst.lower = htole32(LOW_32_BITS(src)); \ dst.upper = htole32(HIGH_32_BITS(src)) #define CMND_TO_CHANNEL( ccb ) ( ccb->ccb_h.path_id ) #define CMND_TO_TARGET( ccb ) ( ccb->ccb_h.target_id ) #define CMND_TO_LUN( ccb ) ( ccb->ccb_h.target_lun ) STATIC U08 agtiapi_AddrModes[AGTIAPI_MAX_CHANNEL_NUM + 1] = { AGTIAPI_PERIPHERAL }; #ifdef LINUX_PERBI_SUPPORT // Holding area for target-WWN mapping assignments on the boot line static ag_mapping_t *agMappingList = NULL; // modified by agtiapi_Setup() #endif // * For Debugging Purpose #ifdef AGTIAPI_DEBUG #define AGTIAPI_WWN(name, len) wwnprintk(name, len) #else #define AGTIAPI_WWN(name, len) #endif #define AGTIAPI_WWNPRINTK(name, len, format, a...) \ AGTIAPI_PRINTK(format "name ", a); \ AGTIAPI_WWN((unsigned char*)name, len); #define AGTIAPI_ERR_WWNPRINTK(name, len, format, a...) \ printk(KERN_DEBUG format "name ", ## a); \ wwnprintk((unsigned char*)name, len); #define AGTIAPI_CPY_DEV_INFO(root, dev, pDev) \ tiINIGetDeviceInfo(root, dev, &pDev->devInfo); \ wwncpy(pDev); #ifdef AGTIAPI_LOCAL_LOCK #define AG_CARD_LOCAL_LOCK(lock) ,(lock) #define AG_SPIN_LOCK_IRQ(lock, flags) #define AG_SPIN_UNLOCK_IRQ(lock, flags) #define AG_SPIN_LOCK(lock) #define AG_SPIN_UNLOCK(lock) #define AG_GLOBAL_ARG(arg) #define AG_PERF_SPINLOCK(lock) #define AG_PERF_SPINLOCK_IRQ(lock, flags) #define AG_LOCAL_LOCK(lock) if (lock) \ mtx_lock(lock) #define AG_LOCAL_UNLOCK(lock) if (lock) \ mtx_unlock(lock) #define AG_LOCAL_FLAGS(_flags) unsigned long _flags = 0 #endif #define AG_GET_DONE_PCCB(pccb, pmcsc) \ { \ AG_LOCAL_LOCK(&pmcsc->doneLock); \ pccb = pmcsc->ccbDoneHead; \ if (pccb != NULL) \ { \ pmcsc->ccbDoneHead = NULL; \ pmcsc->ccbDoneTail = NULL; \ AG_LOCAL_UNLOCK(&pmcsc->doneLock); \ agtiapi_Done(pmcsc, pccb); \ } \ else \ AG_LOCAL_UNLOCK(&pmcsc->doneLock); \ } #define AG_GET_DONE_SMP_PCCB(pccb, pmcsc) \ { \ AG_LOCAL_LOCK(&pmcsc->doneSMPLock); \ pccb = pmcsc->smpDoneHead; \ if (pccb != NULL) \ { \ pmcsc->smpDoneHead = NULL; \ pmcsc->smpDoneTail = NULL; \ AG_LOCAL_UNLOCK(&pmcsc->doneSMPLock); \ agtiapi_SMPDone(pmcsc, pccb); \ } \ else \ AG_LOCAL_UNLOCK(&pmcsc->doneSMPLock); \ } #ifdef AGTIAPI_DUMP_IO_DEBUG #define AG_IO_DUMPCCB(pccb) agtiapi_DumpCCB(pccb) #else #define AG_IO_DUMPCCB(pccb) #endif #define SCHED_DELAY_JIFFIES 4 /* in seconds */ #ifdef HOTPLUG_SUPPORT #define AG_HOTPLUG_LOCK_INIT(lock) mxt_init(lock) #define AG_LIST_LOCK(lock) mtx_lock(lock) #define AG_LIST_UNLOCK(lock) mtx_unlock(lock) #else #define AG_HOTPLUG_LOCK_INIT(lock) #define AG_LIST_LOCK(lock) #define AG_LIST_UNLOCK(lock) #endif STATIC void agtiapi_CheckIOTimeout(void *data); static ag_card_info_t agCardInfoList[ AGTIAPI_MAX_CARDS ]; // card info list static void agtiapi_cam_action( struct cam_sim *, union ccb * ); static void agtiapi_cam_poll( struct cam_sim * ); // Function prototypes static d_open_t agtiapi_open; static d_close_t agtiapi_close; static d_read_t agtiapi_read; static d_write_t agtiapi_write; static d_ioctl_t agtiapi_CharIoctl; static void agtiapi_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg); void agtiapi_adjust_queue_depth(struct cam_path *path, bit32 QueueDepth); // Character device entry points static struct cdevsw agtiapi_cdevsw = { .d_version = D_VERSION, .d_open = agtiapi_open, .d_close = agtiapi_close, .d_read = agtiapi_read, .d_write = agtiapi_write, .d_ioctl = agtiapi_CharIoctl, .d_name = "pmspcv", }; U32 maxTargets = 0; U32 ag_portal_count = 0; // In the cdevsw routines, we find our softc by using the si_drv1 member // of struct cdev. We set this variable to point to our softc in our // attach routine when we create the /dev entry. int agtiapi_open( struct cdev *dev, int oflags, int devtype, struct thread *td ) { struct agtiapi_softc *sc; /* Look up our softc. */ sc = dev->si_drv1; AGTIAPI_PRINTK("agtiapi_open\n"); AGTIAPI_PRINTK("Opened successfully. sc->my_dev %p\n", sc->my_dev); return( 0 ); } int agtiapi_close( struct cdev *dev, int fflag, int devtype, struct thread *td ) { struct agtiapi_softc *sc; // Look up our softc sc = dev->si_drv1; AGTIAPI_PRINTK("agtiapi_close\n"); AGTIAPI_PRINTK("Closed. sc->my_dev %p\n", sc->my_dev); return( 0 ); } int agtiapi_read( struct cdev *dev, struct uio *uio, int ioflag ) { struct agtiapi_softc *sc; // Look up our softc sc = dev->si_drv1; AGTIAPI_PRINTK( "agtiapi_read\n" ); AGTIAPI_PRINTK( "Asked to read %lu bytes. sc->my_dev %p\n", uio->uio_resid, sc->my_dev ); return( 0 ); } int agtiapi_write( struct cdev *dev, struct uio *uio, int ioflag ) { struct agtiapi_softc *sc; // Look up our softc sc = dev->si_drv1; AGTIAPI_PRINTK( "agtiapi_write\n" ); AGTIAPI_PRINTK( "Asked to write %lu bytes. sc->my_dev %p\n", uio->uio_resid, sc->my_dev ); return( 0 ); } int agtiapi_getdevlist( struct agtiapi_softc *pCard, tiIOCTLPayload_t *agIOCTLPayload ) { tdDeviceListPayload_t *pIoctlPayload = (tdDeviceListPayload_t *) agIOCTLPayload->FunctionSpecificArea; tdDeviceInfoIOCTL_t *pDeviceInfo = NULL; bit8 *pDeviceInfoOrg; tdsaDeviceData_t *pDeviceData = NULL; tiDeviceHandle_t **devList = NULL; tiDeviceHandle_t **devHandleArray = NULL; tiDeviceHandle_t *pDeviceHandle = NULL; bit32 x, memNeeded1; bit32 count, total; bit32 MaxDeviceCount; bit32 ret_val=IOCTL_CALL_INVALID_CODE; ag_portal_data_t *pPortalData; bit8 *pDeviceHandleList = NULL; AGTIAPI_PRINTK( "agtiapi_getdevlist: Enter\n" ); pDeviceInfoOrg = pIoctlPayload -> pDeviceInfo; MaxDeviceCount = pCard->devDiscover; if (MaxDeviceCount > pIoctlPayload->deviceLength ) { AGTIAPI_PRINTK( "agtiapi_getdevlist: MaxDeviceCount: %d > Requested device length: %d\n", MaxDeviceCount, pIoctlPayload->deviceLength ); MaxDeviceCount = pIoctlPayload->deviceLength; ret_val = IOCTL_CALL_FAIL; } AGTIAPI_PRINTK( "agtiapi_getdevlist: MaxDeviceCount: %d > Requested device length: %d\n", MaxDeviceCount, pIoctlPayload->deviceLength ); memNeeded1 = AG_ALIGNSIZE( MaxDeviceCount * sizeof(tiDeviceHandle_t *), sizeof(void *) ); AGTIAPI_PRINTK("agtiapi_getdevlist: portCount %d\n", pCard->portCount); devList = malloc(memNeeded1, TEMP2, M_WAITOK); if (devList == NULL) { AGTIAPI_PRINTK("agtiapi_getdevlist: failed to allocate memory\n"); ret_val = IOCTL_CALL_FAIL; agIOCTLPayload->Status = IOCTL_ERR_STATUS_INTERNAL_ERROR; return ret_val; } osti_memset(devList, 0, memNeeded1); pPortalData = &pCard->pPortalData[0]; pDeviceHandleList = (bit8*)devList; for (total = x = 0; x < pCard->portCount; x++, pPortalData++) { count = tiINIGetDeviceHandlesForWinIOCTL(&pCard->tiRoot, &pPortalData->portalInfo.tiPortalContext, ( tiDeviceHandle_t **)pDeviceHandleList ,MaxDeviceCount ); if (count == DISCOVERY_IN_PROGRESS) { AGTIAPI_PRINTK( "agtiapi_getdevlist: DISCOVERY_IN_PROGRESS on " "portal %d\n", x ); free(devList, TEMP2); ret_val = IOCTL_CALL_FAIL; agIOCTLPayload->Status = IOCTL_ERR_STATUS_INTERNAL_ERROR; return ret_val; } total += count; pDeviceHandleList+= count*sizeof(tiDeviceHandle_t *); MaxDeviceCount-= count; } if (total > pIoctlPayload->deviceLength) { total = pIoctlPayload->deviceLength; } // dump device information from device handle list count = 0; devHandleArray = devList; for (x = 0; x < pCard->devDiscover; x++) { pDeviceHandle = (tiDeviceHandle_t*)devHandleArray[x]; if (devList[x] != agNULL) { pDeviceData = devList [x]->tdData; pDeviceInfo = (tdDeviceInfoIOCTL_t*)(pDeviceInfoOrg + sizeof(tdDeviceInfoIOCTL_t) * count); if (pDeviceData != agNULL && pDeviceInfo != agNULL) { osti_memcpy( &pDeviceInfo->sasAddressHi, pDeviceData->agDeviceInfo.sasAddressHi, sizeof(bit32) ); osti_memcpy( &pDeviceInfo->sasAddressLo, pDeviceData->agDeviceInfo.sasAddressLo, sizeof(bit32) ); #if 0 pDeviceInfo->sasAddressHi = DMA_BEBIT32_TO_BIT32( pDeviceInfo->sasAddressHi ); pDeviceInfo->sasAddressLo = DMA_BEBIT32_TO_BIT32( pDeviceInfo->sasAddressLo ); #endif pDeviceInfo->deviceType = ( pDeviceData->agDeviceInfo.devType_S_Rate & 0x30 ) >> 4; pDeviceInfo->linkRate = pDeviceData->agDeviceInfo.devType_S_Rate & 0x0F; pDeviceInfo->phyId = pDeviceData->phyID; pDeviceInfo->ishost = pDeviceData->target_ssp_stp_smp; pDeviceInfo->DeviceHandle= (unsigned long)pDeviceHandle; if(pDeviceInfo->deviceType == 0x02) { bit8 *sasAddressHi; bit8 *sasAddressLo; tiIniGetDirectSataSasAddr(&pCard->tiRoot, pDeviceData->phyID, &sasAddressHi, &sasAddressLo); pDeviceInfo->sasAddressHi = DMA_BEBIT32_TO_BIT32(*(bit32*)sasAddressHi); pDeviceInfo->sasAddressLo = DMA_BEBIT32_TO_BIT32(*(bit32*)sasAddressLo) + pDeviceData->phyID + 16; } else { pDeviceInfo->sasAddressHi = DMA_BEBIT32_TO_BIT32( pDeviceInfo->sasAddressHi ); pDeviceInfo->sasAddressLo = DMA_BEBIT32_TO_BIT32( pDeviceInfo->sasAddressLo ); } AGTIAPI_PRINTK( "agtiapi_getdevlist: devicetype %x\n", pDeviceInfo->deviceType ); AGTIAPI_PRINTK( "agtiapi_getdevlist: linkrate %x\n", pDeviceInfo->linkRate ); AGTIAPI_PRINTK( "agtiapi_getdevlist: phyID %x\n", pDeviceInfo->phyId ); AGTIAPI_PRINTK( "agtiapi_getdevlist: addresshi %x\n", pDeviceInfo->sasAddressHi ); AGTIAPI_PRINTK( "agtiapi_getdevlist: addresslo %x\n", pDeviceInfo->sasAddressHi ); } else { AGTIAPI_PRINTK( "agtiapi_getdevlist: pDeviceData %p or pDeviceInfo " "%p is NULL %d\n", pDeviceData, pDeviceInfo, x ); } count++; } } pIoctlPayload->realDeviceCount = count; AGTIAPI_PRINTK( "agtiapi_getdevlist: Exit RealDeviceCount = %d\n", count ); if (devList) { free(devList, TEMP2); } if(ret_val != IOCTL_CALL_FAIL) { ret_val = IOCTL_CALL_SUCCESS; } agIOCTLPayload->Status = IOCTL_ERR_STATUS_OK; return ret_val; } /****************************************************************************** agtiapi_getCardInfo() Purpose: This function retrives the Card information Parameters: Return: A number - error 0 - HBA has been detected Note: ******************************************************************************/ int agtiapi_getCardInfo ( struct agtiapi_softc *pCard, U32_64 size, void *buffer ) { CardInfo_t *pCardInfo; pCardInfo = (CardInfo_t *)buffer; pCardInfo->deviceId = pci_get_device(pCard->my_dev); pCardInfo->vendorId =pci_get_vendor(pCard->my_dev) ; memcpy( pCardInfo->pciMemBaseSpc, pCard->pCardInfo->pciMemBaseSpc, ((sizeof(U32_64))*PCI_NUMBER_BARS) ); pCardInfo->deviceNum = pci_get_slot(pCard->my_dev); pCardInfo->pciMemBase = pCard->pCardInfo->pciMemBase; pCardInfo->pciIOAddrLow = pCard->pCardInfo->pciIOAddrLow; pCardInfo->pciIOAddrUp = pCard->pCardInfo->pciIOAddrUp; pCardInfo->busNum =pci_get_bus(pCard->my_dev); return 0; } void agtiapi_adjust_queue_depth(struct cam_path *path, bit32 QueueDepth) { struct ccb_relsim crs; + memset(&crs, 0, sizeof(crs)); xpt_setup_ccb(&crs.ccb_h, path, 5); crs.ccb_h.func_code = XPT_REL_SIMQ; crs.ccb_h.flags = CAM_DEV_QFREEZE; crs.release_flags = RELSIM_ADJUST_OPENINGS; crs.openings = QueueDepth; xpt_action((union ccb *)&crs); if(crs.ccb_h.status != CAM_REQ_CMP) { printf("XPT_REL_SIMQ failed\n"); } } static void agtiapi_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) { struct agtiapi_softc *pmsc; U32 TID; ag_device_t *targ; pmsc = (struct agtiapi_softc*)callback_arg; switch (code) { case AC_FOUND_DEVICE: { struct ccb_getdev *cgd; cgd = (struct ccb_getdev *)arg; if (cgd == NULL) { break; } TID = cgd->ccb_h.target_id; if (TID >= 0 && TID < maxTargets){ if (pmsc != NULL){ TID = INDEX(pmsc, TID); targ = &pmsc->pDevList[TID]; agtiapi_adjust_queue_depth(path, targ->qdepth); } } break; } default: break; } } /****************************************************************************** agtiapi_CharIoctl() Purpose: This function handles the ioctl from application layer Parameters: Return: A number - error 0 - HBA has been detected Note: ******************************************************************************/ static int agtiapi_CharIoctl( struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td ) { struct sema mx; datatosend *load; // structure defined in lxcommon.h tiIOCTLPayload_t *pIoctlPayload; struct agtiapi_softc *pCard; pCard=dev->si_drv1; U32 status = 0; U32 retValue; int err = 0; int error = 0; tdDeviceListPayload_t *pDeviceList = NULL; unsigned long flags; switch (cmd) { case AGTIAPI_IOCTL: load=(datatosend*)data; pIoctlPayload = malloc(load->datasize,TEMP,M_WAITOK); AGTIAPI_PRINTK( "agtiapi_CharIoctl: old load->datasize = %d\n", load->datasize ); //Copy payload to kernel buffer, on success it returns 0 err = copyin(load->data,pIoctlPayload,load->datasize); if (err) { status = IOCTL_CALL_FAIL; return status; } sema_init(&mx,0,"sem"); pCard->pIoctlSem =&mx; pCard->up_count = pCard->down_count = 0; if ( pIoctlPayload->MajorFunction == IOCTL_MJ_GET_DEVICE_LIST ) { retValue = agtiapi_getdevlist(pCard, pIoctlPayload); if (retValue == 0) { pIoctlPayload->Status = IOCTL_CALL_SUCCESS; status = IOCTL_CALL_SUCCESS; } else { pIoctlPayload->Status = IOCTL_CALL_FAIL; status = IOCTL_CALL_FAIL; } //update new device length pDeviceList = (tdDeviceListPayload_t*)pIoctlPayload->FunctionSpecificArea; load->datasize =load->datasize - sizeof(tdDeviceInfoIOCTL_t) * (pDeviceList->deviceLength - pDeviceList->realDeviceCount); AGTIAPI_PRINTK( "agtiapi_CharIoctl: new load->datasize = %d\n", load->datasize ); } else if (pIoctlPayload->MajorFunction == IOCTL_MN_GET_CARD_INFO) { retValue = agtiapi_getCardInfo( pCard, pIoctlPayload->Length, (pIoctlPayload->FunctionSpecificArea) ); if (retValue == 0) { pIoctlPayload->Status = IOCTL_CALL_SUCCESS; status = IOCTL_CALL_SUCCESS; } else { pIoctlPayload->Status = IOCTL_CALL_FAIL; status = IOCTL_CALL_FAIL; } } else if ( pIoctlPayload->MajorFunction == IOCTL_MJ_CHECK_DPMC_EVENT ) { if ( pCard->flags & AGTIAPI_PORT_PANIC ) { strcpy ( pIoctlPayload->FunctionSpecificArea, "DPMC LEAN\n" ); } else { strcpy ( pIoctlPayload->FunctionSpecificArea, "do not dpmc lean\n" ); } pIoctlPayload->Status = IOCTL_CALL_SUCCESS; status = IOCTL_CALL_SUCCESS; } else if (pIoctlPayload->MajorFunction == IOCTL_MJ_CHECK_FATAL_ERROR ) { AGTIAPI_PRINTK("agtiapi_CharIoctl: IOCTL_MJ_CHECK_FATAL_ERROR call received for card %d\n", pCard->cardNo); //read port status to see if there is a fatal event if(pCard->flags & AGTIAPI_PORT_PANIC) { printf("agtiapi_CharIoctl: Port Panic Status For Card %d is True\n",pCard->cardNo); pIoctlPayload->Status = IOCTL_MJ_FATAL_ERR_CHK_SEND_TRUE; } else { AGTIAPI_PRINTK("agtiapi_CharIoctl: Port Panic Status For Card %d is False\n",pCard->cardNo); pIoctlPayload->Status = IOCTL_MJ_FATAL_ERR_CHK_SEND_FALSE; } status = IOCTL_CALL_SUCCESS; } else if (pIoctlPayload->MajorFunction == IOCTL_MJ_FATAL_ERROR_DUMP_COMPLETE) { AGTIAPI_PRINTK("agtiapi_CharIoctl: IOCTL_MJ_FATAL_ERROR_DUMP_COMPLETE call received for card %d\n", pCard->cardNo); //set flags bit status to be a soft reset pCard->flags |= AGTIAPI_SOFT_RESET; //trigger soft reset for the card retValue = agtiapi_ResetCard (pCard, &flags); if(retValue == AGTIAPI_SUCCESS) { //clear port panic status pCard->flags &= ~AGTIAPI_PORT_PANIC; pIoctlPayload->Status = IOCTL_MJ_FATAL_ERROR_SOFT_RESET_TRIG; status = IOCTL_CALL_SUCCESS; } else { pIoctlPayload->Status = IOCTL_CALL_FAIL; status = IOCTL_CALL_FAIL; } } else { status = tiCOMMgntIOCTL( &pCard->tiRoot, pIoctlPayload, pCard, NULL, NULL ); if (status == IOCTL_CALL_PENDING) { ostiIOCTLWaitForSignal(&pCard->tiRoot,NULL, NULL, NULL); status = IOCTL_CALL_SUCCESS; } } pCard->pIoctlSem = NULL; err = 0; //copy kernel buffer to userland buffer err=copyout(pIoctlPayload,load->data,load->datasize); if (err) { status = IOCTL_CALL_FAIL; return status; } free(pIoctlPayload,TEMP); pIoctlPayload=NULL; break; default: error = ENOTTY; break; } return(status); } /****************************************************************************** agtiapi_probe() Purpose: This function initialize and registere all detected HBAs. The first function being called in driver after agtiapi_probe() Parameters: device_t dev (IN) - device pointer Return: A number - error 0 - HBA has been detected Note: ******************************************************************************/ static int agtiapi_probe( device_t dev ) { int retVal; int thisCard; ag_card_info_t *thisCardInst; thisCard = device_get_unit( dev ); if ( thisCard >= AGTIAPI_MAX_CARDS ) { device_printf( dev, "Too many PMC-Sierra cards detected ERROR!\n" ); return (ENXIO); // maybe change to different return value? } thisCardInst = &agCardInfoList[ thisCard ]; retVal = agtiapi_ProbeCard( dev, thisCardInst, thisCard ); if ( retVal ) return (ENXIO); // maybe change to different return value? return( BUS_PROBE_DEFAULT ); // successful probe } /****************************************************************************** agtiapi_attach() Purpose: This function initialize and registere all detected HBAs. The first function being called in driver after agtiapi_probe() Parameters: device_t dev (IN) - device pointer Return: A number - error 0 - HBA has been detected Note: ******************************************************************************/ static int agtiapi_attach( device_t devx ) { // keeping get_unit call to once int thisCard = device_get_unit( devx ); struct agtiapi_softc *pmsc; ag_card_info_t *thisCardInst = &agCardInfoList[ thisCard ]; ag_resource_info_t *pRscInfo; int idx; int lenRecv; char buffer [256], *pLastUsedChar; union ccb *ccb; int bus, tid, lun; struct ccb_setasync csa; AGTIAPI_PRINTK("agtiapi_attach: start dev %p thisCard %d\n", devx, thisCard); // AGTIAPI_PRINTK( "agtiapi_attach: entry pointer values A %p / %p\n", // thisCardInst->pPCIDev, thisCardInst ); AGTIAPI_PRINTK( "agtiapi_attach: deviceID: 0x%x\n", pci_get_devid( devx ) ); TUNABLE_INT_FETCH( "DPMC_TIMEOUT_SECS", &ag_timeout_secs ); TUNABLE_INT_FETCH( "DPMC_TIDEBUG_LEVEL", &gTiDebugLevel ); // printf( "agtiapi_attach: debugLevel %d, timeout %d\n", // gTiDebugLevel, ag_timeout_secs ); if ( ag_timeout_secs < 1 ) { ag_timeout_secs = 1; // set minimum timeout value of 1 second } ag_timeout_secs = (ag_timeout_secs * 1000); // convert to millisecond notation // Look up our softc and initialize its fields. pmsc = device_get_softc( devx ); pmsc->my_dev = devx; /* Get NumberOfPortals */ if ((ostiGetTransportParam( &pmsc->tiRoot, "Global", "CardDefault", agNULL, agNULL, agNULL, agNULL, "NumberOfPortals", buffer, 255, &lenRecv ) == tiSuccess) && (lenRecv != 0)) { if (osti_strncmp(buffer, "0x", 2) == 0) { ag_portal_count = osti_strtoul (buffer, &pLastUsedChar, 0); } else { ag_portal_count = osti_strtoul (buffer, &pLastUsedChar, 10); } if (ag_portal_count > AGTIAPI_MAX_PORTALS) ag_portal_count = AGTIAPI_MAX_PORTALS; } else { ag_portal_count = AGTIAPI_MAX_PORTALS; } AGTIAPI_PRINTK( "agtiapi_attach: ag_portal_count=%d\n", ag_portal_count ); // initialize hostdata structure pmsc->flags |= AGTIAPI_INIT_TIME | AGTIAPI_SCSI_REGISTERED | AGTIAPI_INITIATOR; pmsc->cardNo = thisCard; pmsc->ccbTotal = 0; pmsc->portCount = ag_portal_count; pmsc->pCardInfo = thisCardInst; pmsc->tiRoot.osData = pmsc; pmsc->pCardInfo->pCard = (void *)pmsc; pmsc->VidDid = ( pci_get_vendor(devx) << 16 ) | pci_get_device( devx ); pmsc->SimQFrozen = agFALSE; pmsc->devq_flag = agFALSE; pRscInfo = &thisCardInst->tiRscInfo; osti_memset(buffer, 0, 256); lenRecv = 0; /* Get MaxTargets */ if ((ostiGetTransportParam( &pmsc->tiRoot, "Global", "InitiatorParms", agNULL, agNULL, agNULL, agNULL, "MaxTargets", buffer, sizeof(buffer), &lenRecv ) == tiSuccess) && (lenRecv != 0)) { if (osti_strncmp(buffer, "0x", 2) == 0) { maxTargets = osti_strtoul (buffer, &pLastUsedChar, 0); AGTIAPI_PRINTK( "agtiapi_attach: maxTargets = osti_strtoul 0 \n" ); } else { maxTargets = osti_strtoul (buffer, &pLastUsedChar, 10); AGTIAPI_PRINTK( "agtiapi_attach: maxTargets = osti_strtoul 10\n" ); } } else { if(Is_ADP8H(pmsc)) maxTargets = AGTIAPI_MAX_DEVICE_8H; else if(Is_ADP7H(pmsc)) maxTargets = AGTIAPI_MAX_DEVICE_7H; else maxTargets = AGTIAPI_MAX_DEVICE; } if (maxTargets > AGTIAPI_HW_LIMIT_DEVICE) { AGTIAPI_PRINTK( "agtiapi_attach: maxTargets: %d > AGTIAPI_HW_LIMIT_DEVICE: %d\n", maxTargets, AGTIAPI_HW_LIMIT_DEVICE ); AGTIAPI_PRINTK( "agtiapi_attach: change maxTargets = AGTIAPI_HW_LIMIT_DEVICE\n" ); maxTargets = AGTIAPI_HW_LIMIT_DEVICE; } pmsc->devDiscover = maxTargets ; #ifdef HIALEAH_ENCRYPTION ag_encryption_enable = 1; if(ag_encryption_enable && pci_get_device(pmsc->pCardInfo->pPCIDev) == PCI_DEVICE_ID_HIALEAH_HBA_SPCVE) { pmsc->encrypt = 1; pRscInfo->tiLoLevelResource.loLevelOption.encryption = agTRUE; printf("agtiapi_attach: Encryption Enabled\n" ); } #endif // ## for now, skip calls to ostiGetTransportParam(...) // ## for now, skip references to DIF & EDC // Create a /dev entry for this device. The kernel will assign us // a major number automatically. We use the unit number of this // device as the minor number and name the character device // "agtiapi". pmsc->my_cdev = make_dev( &agtiapi_cdevsw, thisCard, UID_ROOT, GID_WHEEL, 0600, "spcv%u", thisCard ); pmsc->my_cdev->si_drv1 = pmsc; mtx_init( &thisCardInst->pmIOLock, "pmc SAS I/O lock", NULL, MTX_DEF|MTX_RECURSE ); struct cam_devq *devq; /* set the maximum number of pending IOs */ devq = cam_simq_alloc( AGTIAPI_MAX_CAM_Q_DEPTH ); if (devq == NULL) { AGTIAPI_PRINTK("agtiapi_attach: cam_simq_alloc is NULL\n" ); return( EIO ); } struct cam_sim *lsim; lsim = cam_sim_alloc( agtiapi_cam_action, agtiapi_cam_poll, "pmspcbsd", pmsc, thisCard, &thisCardInst->pmIOLock, 1, // queued per target AGTIAPI_MAX_CAM_Q_DEPTH, // max tag depth devq ); if ( lsim == NULL ) { cam_simq_free( devq ); AGTIAPI_PRINTK("agtiapi_attach: cam_sim_alloc is NULL\n" ); return( EIO ); } pmsc->dev_scan = agFALSE; //one cam sim per scsi bus mtx_lock( &thisCardInst->pmIOLock ); if ( xpt_bus_register( lsim, devx, 0 ) != CAM_SUCCESS ) { // bus 0 cam_sim_free( lsim, TRUE ); mtx_unlock( &thisCardInst->pmIOLock ); AGTIAPI_PRINTK("agtiapi_attach: xpt_bus_register fails\n" ); return( EIO ); } pmsc->sim = lsim; bus = cam_sim_path(pmsc->sim); tid = CAM_TARGET_WILDCARD; lun = CAM_LUN_WILDCARD; ccb = xpt_alloc_ccb_nowait(); if (ccb == agNULL) { mtx_unlock( &thisCardInst->pmIOLock ); cam_sim_free( lsim, TRUE ); cam_simq_free( devq ); return ( EIO ); } if (xpt_create_path(&ccb->ccb_h.path, agNULL, bus, tid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { mtx_unlock( &thisCardInst->pmIOLock ); cam_sim_free( lsim, TRUE ); cam_simq_free( devq ); xpt_free_ccb(ccb); return( EIO ); } pmsc->path = ccb->ccb_h.path; + memset(&csa, 0, sizeof(csa)); xpt_setup_ccb(&csa.ccb_h, pmsc->path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = AC_FOUND_DEVICE; csa.callback = agtiapi_async; csa.callback_arg = pmsc; xpt_action((union ccb *)&csa); if (csa.ccb_h.status != CAM_REQ_CMP) { AGTIAPI_PRINTK("agtiapi_attach: Unable to register AC_FOUND_DEVICE\n" ); } lsim->devq = devq; mtx_unlock( &thisCardInst->pmIOLock ); // get TD and lower layer memory requirements tiCOMGetResource( &pmsc->tiRoot, &pRscInfo->tiLoLevelResource, &pRscInfo->tiInitiatorResource, NULL, &pRscInfo->tiSharedMem ); agtiapi_ScopeDMARes( thisCardInst ); AGTIAPI_PRINTK( "agtiapi_attach: size from the call agtiapi_ScopeDMARes" " 0x%x \n", pmsc->typhn ); // initialize card information and get resource ready if( agtiapi_InitResource( thisCardInst ) == AGTIAPI_FAIL ) { AGTIAPI_PRINTK( "agtiapi_attach: Card %d initialize resource ERROR\n", thisCard ); } // begin: allocate and initialize card portal info resource ag_portal_data_t *pPortalData; if (pmsc->portCount == 0) { pmsc->pPortalData = NULL; } else { pmsc->pPortalData = (ag_portal_data_t *) malloc( sizeof(ag_portal_data_t) * pmsc->portCount, M_PMC_MPRT, M_ZERO | M_WAITOK ); if (pmsc->pPortalData == NULL) { AGTIAPI_PRINTK( "agtiapi_attach: Portal memory allocation ERROR\n" ); } } pPortalData = pmsc->pPortalData; for( idx = 0; idx < pmsc->portCount; idx++ ) { pPortalData->pCard = pmsc; pPortalData->portalInfo.portID = idx; pPortalData->portalInfo.tiPortalContext.osData = (void *)pPortalData; pPortalData++; } // end: allocate and initialize card portal info resource // begin: enable msix // setup msix // map to interrupt handler int error = 0; int mesgs = MAX_MSIX_NUM_VECTOR; int i, cnt; void (*intrHandler[MAX_MSIX_NUM_ISR])(void *arg) = { agtiapi_IntrHandler0, agtiapi_IntrHandler1, agtiapi_IntrHandler2, agtiapi_IntrHandler3, agtiapi_IntrHandler4, agtiapi_IntrHandler5, agtiapi_IntrHandler6, agtiapi_IntrHandler7, agtiapi_IntrHandler8, agtiapi_IntrHandler9, agtiapi_IntrHandler10, agtiapi_IntrHandler11, agtiapi_IntrHandler12, agtiapi_IntrHandler13, agtiapi_IntrHandler14, agtiapi_IntrHandler15 }; cnt = pci_msix_count(devx); AGTIAPI_PRINTK("supported MSIX %d\n", cnt); //this should be 64 mesgs = MIN(mesgs, cnt); error = pci_alloc_msix(devx, &mesgs); if (error != 0) { printf( "pci_alloc_msix error %d\n", error ); AGTIAPI_PRINTK("error %d\n", error); return( EIO ); } for(i=0; i < mesgs; i++) { pmsc->rscID[i] = i + 1; pmsc->irq[i] = bus_alloc_resource_any( devx, SYS_RES_IRQ, &pmsc->rscID[i], RF_ACTIVE ); if( pmsc->irq[i] == NULL ) { printf( "RES_IRQ went terribly bad at %d\n", i ); return( EIO ); } if ( (error = bus_setup_intr( devx, pmsc->irq[i], INTR_TYPE_CAM | INTR_MPSAFE, NULL, intrHandler[i], pmsc, &pmsc->intrcookie[i] ) ) != 0 ) { device_printf( devx, "Failed to register handler" ); return( EIO ); } } pmsc->flags |= AGTIAPI_IRQ_REQUESTED; pmsc->pCardInfo->maxInterruptVectors = MAX_MSIX_NUM_VECTOR; // end: enable msix int ret = 0; ret = agtiapi_InitCardSW(pmsc); if (ret == AGTIAPI_FAIL || ret == AGTIAPI_UNKNOWN) { AGTIAPI_PRINTK( "agtiapi_attach: agtiapi_InitCardSW failure %d\n", ret ); return( EIO ); } pmsc->ccbFreeList = NULL; pmsc->ccbChainList = NULL; pmsc->ccbAllocList = NULL; pmsc->flags |= ( AGTIAPI_INSTALLED ); ret = agtiapi_alloc_requests( pmsc ); if( ret != 0 ) { AGTIAPI_PRINTK( "agtiapi_attach: agtiapi_alloc_requests failure %d\n", ret ); return( EIO ); } ret = agtiapi_alloc_ostimem( pmsc ); if (ret != AGTIAPI_SUCCESS) { AGTIAPI_PRINTK( "agtiapi_attach: agtiapi_alloc_ostimem failure %d\n", ret ); return( EIO ); } ret = agtiapi_InitCardHW( pmsc ); if (ret != 0) { AGTIAPI_PRINTK( "agtiapi_attach: agtiapi_InitCardHW failure %d\n", ret ); return( EIO ); } #ifdef HIALEAH_ENCRYPTION if(pmsc->encrypt) { if((agtiapi_SetupEncryption(pmsc)) < 0) AGTIAPI_PRINTK("SetupEncryption returned less than 0\n"); } #endif pmsc->flags &= ~AGTIAPI_INIT_TIME; return( 0 ); } /****************************************************************************** agtiapi_InitCardSW() Purpose: Host Bus Adapter Initialization Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure Return: AGTIAPI_SUCCESS - success AGTIAPI_FAIL - fail Note: TBD, need chip register information ******************************************************************************/ STATIC agBOOLEAN agtiapi_InitCardSW( struct agtiapi_softc *pmsc ) { ag_card_info_t *thisCardInst = pmsc->pCardInfo; ag_resource_info_t *pRscInfo = &thisCardInst->tiRscInfo; int initSWIdx; // begin: agtiapi_InitCardSW() // now init some essential locks n agtiapi_InitCardSW mtx_init( &pmsc->sendLock, "local q send lock", NULL, MTX_DEF ); mtx_init( &pmsc->doneLock, "local q done lock", NULL, MTX_DEF ); mtx_init( &pmsc->sendSMPLock, "local q send lock", NULL, MTX_DEF ); mtx_init( &pmsc->doneSMPLock, "local q done lock", NULL, MTX_DEF ); mtx_init( &pmsc->ccbLock, "ccb list lock", NULL, MTX_DEF ); mtx_init( &pmsc->devListLock, "hotP devListLock", NULL, MTX_DEF ); mtx_init( &pmsc->memLock, "dynamic memory lock", NULL, MTX_DEF ); mtx_init( &pmsc->freezeLock, "sim freeze lock", NULL, MTX_DEF | MTX_RECURSE); // initialize lower layer resources //## if (pCard->flags & AGTIAPI_INIT_TIME) { #ifdef HIALEAH_ENCRYPTION /* Enable encryption if chip supports it */ if (pci_get_device(pmsc->pCardInfo->pPCIDev) == PCI_DEVICE_ID_HIALEAH_HBA_SPCVE) pmsc->encrypt = 1; if (pmsc->encrypt) pRscInfo->tiLoLevelResource.loLevelOption.encryption = agTRUE; #endif pmsc->flags &= ~(AGTIAPI_PORT_INITIALIZED | AGTIAPI_SYS_INTR_ON); // For now, up to 16 MSIX vectors are supported thisCardInst->tiRscInfo.tiLoLevelResource.loLevelOption. maxInterruptVectors = pmsc->pCardInfo->maxInterruptVectors; AGTIAPI_PRINTK( "agtiapi_InitCardSW: maxInterruptVectors set to %d", pmsc->pCardInfo->maxInterruptVectors ); thisCardInst->tiRscInfo.tiLoLevelResource.loLevelOption.max_MSI_InterruptVectors = 0; thisCardInst->tiRscInfo.tiLoLevelResource.loLevelOption.flag = 0; pRscInfo->tiLoLevelResource.loLevelOption.maxNumOSLocks = 0; AGTIAPI_PRINTK( "agtiapi_InitCardSW: tiCOMInit root %p, dev %p, pmsc %p\n", &pmsc->tiRoot, pmsc->my_dev, pmsc ); if( tiCOMInit( &pmsc->tiRoot, &thisCardInst->tiRscInfo.tiLoLevelResource, &thisCardInst->tiRscInfo.tiInitiatorResource, NULL, &thisCardInst->tiRscInfo.tiSharedMem ) != tiSuccess ) { AGTIAPI_PRINTK( "agtiapi_InitCardSW: tiCOMInit ERROR\n" ); return AGTIAPI_FAIL; } int maxLocks; maxLocks = pRscInfo->tiLoLevelResource.loLevelOption.numOfQueuesPerPort; pmsc->STLock = malloc( ( maxLocks * sizeof(struct mtx) ), M_PMC_MSTL, M_ZERO | M_WAITOK ); for( initSWIdx = 0; initSWIdx < maxLocks; initSWIdx++ ) { // init all indexes mtx_init( &pmsc->STLock[initSWIdx], "LL & TD lock", NULL, MTX_DEF ); } if( tiCOMPortInit( &pmsc->tiRoot, agFALSE ) != tiSuccess ) { printf( "agtiapi_InitCardSW: tiCOMPortInit ERROR -- AGTIAPI_FAIL\n" ); return AGTIAPI_FAIL; } AGTIAPI_PRINTK( "agtiapi_InitCardSW: tiCOMPortInit" " root %p, dev %p, pmsc %p\n", &pmsc->tiRoot, pmsc->my_dev, pmsc ); pmsc->flags |= AGTIAPI_PORT_INITIALIZED; pmsc->freezeSim = agFALSE; #ifdef HIALEAH_ENCRYPTION atomic_set(&outstanding_encrypted_io_count, 0); /*fix below*/ /*if(pmsc->encrypt && (pmsc->flags & AGTIAPI_INIT_TIME)) if((agtiapi_SetupEncryptionPools(pmsc)) != 0) printf("SetupEncryptionPools failed\n"); */ #endif return AGTIAPI_SUCCESS; // end: agtiapi_InitCardSW() } /****************************************************************************** agtiapi_InitCardHW() Purpose: Host Bus Adapter Initialization Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure Return: AGTIAPI_SUCCESS - success AGTIAPI_FAIL - fail Note: TBD, need chip register information ******************************************************************************/ STATIC agBOOLEAN agtiapi_InitCardHW( struct agtiapi_softc *pmsc ) { U32 numVal; U32 count; U32 loop; // begin: agtiapi_InitCardHW() ag_portal_info_t *pPortalInfo = NULL; ag_portal_data_t *pPortalData; // ISR is registered, enable chip interrupt. tiCOMSystemInterruptsActive( &pmsc->tiRoot, agTRUE ); pmsc->flags |= AGTIAPI_SYS_INTR_ON; numVal = sizeof(ag_device_t) * pmsc->devDiscover; pmsc->pDevList = (ag_device_t *)malloc( numVal, M_PMC_MDVT, M_ZERO | M_WAITOK ); if( !pmsc->pDevList ) { AGTIAPI_PRINTK( "agtiapi_InitCardHW: kmalloc %d DevList ERROR\n", numVal ); panic( "agtiapi_InitCardHW\n" ); return AGTIAPI_FAIL; } #ifdef LINUX_PERBI_SUPPORT numVal = sizeof(ag_slr_map_t) * pmsc->devDiscover; pmsc->pSLRList = (ag_slr_map_t *)malloc( numVal, M_PMC_MSLR, M_ZERO | M_WAITOK ); if( !pmsc->pSLRList ) { AGTIAPI_PRINTK( "agtiapi_InitCardHW: kmalloc %d SLRList ERROR\n", numVal ); panic( "agtiapi_InitCardHW SLRL\n" ); return AGTIAPI_FAIL; } numVal = sizeof(ag_tgt_map_t) * pmsc->devDiscover; pmsc->pWWNList = (ag_tgt_map_t *)malloc( numVal, M_PMC_MTGT, M_ZERO | M_WAITOK ); if( !pmsc->pWWNList ) { AGTIAPI_PRINTK( "agtiapi_InitCardHW: kmalloc %d WWNList ERROR\n", numVal ); panic( "agtiapi_InitCardHW WWNL\n" ); return AGTIAPI_FAIL; } // Get the WWN_to_target_ID mappings from the // holding area which contains the input of the // system configuration file. if( ag_Perbi ) agtiapi_GetWWNMappings( pmsc, agMappingList ); else { agtiapi_GetWWNMappings( pmsc, 0 ); if( agMappingList ) printf( "agtiapi_InitCardHW: WWN PERBI disabled WARN\n" ); } #endif //agtiapi_DelaySec(5); DELAY( 500000 ); pmsc->tgtCount = 0; pmsc->flags &= ~AGTIAPI_CB_DONE; pPortalData = pmsc->pPortalData; //start port for (count = 0; count < pmsc->portCount; count++) { AG_SPIN_LOCK_IRQ( agtiapi_host_lock, flags ); pPortalInfo = &pPortalData->portalInfo; pPortalInfo->portStatus &= ~( AGTIAPI_PORT_START | AGTIAPI_PORT_DISC_READY | AGTIAPI_DISC_DONE | AGTIAPI_DISC_COMPLETE ); for (loop = 0; loop < AGTIAPI_LOOP_MAX; loop++) { AGTIAPI_PRINTK( "tiCOMPortStart entry data %p / %d / %p\n", &pmsc->tiRoot, pPortalInfo->portID, &pPortalInfo->tiPortalContext ); if( tiCOMPortStart( &pmsc->tiRoot, pPortalInfo->portID, &pPortalInfo->tiPortalContext, 0 ) != tiSuccess ) { AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); agtiapi_DelayMSec( AGTIAPI_EXTRA_DELAY ); AG_SPIN_LOCK_IRQ(agtiapi_host_lock, flags); AGTIAPI_PRINTK( "tiCOMPortStart failed -- no loop, portalData %p\n", pPortalData ); } else { AGTIAPI_PRINTK( "tiCOMPortStart success no loop, portalData %p\n", pPortalData ); break; } } // end of for loop /* release lock */ AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); if( loop >= AGTIAPI_LOOP_MAX ) { return AGTIAPI_FAIL; } tiCOMGetPortInfo( &pmsc->tiRoot, &pPortalInfo->tiPortalContext, &pPortalInfo->tiPortInfo ); pPortalData++; } /* discover target device */ #ifndef HOTPLUG_SUPPORT agtiapi_DiscoverTgt( pCard ); #endif pmsc->flags |= AGTIAPI_INSTALLED; if( pmsc->flags & AGTIAPI_INIT_TIME ) { agtiapi_TITimer( (void *)pmsc ); pmsc->flags |= AGTIAPI_TIMER_ON; } return 0; } /****************************************************************************** agtiapi_IntrHandlerx_() Purpose: Interrupt service routine. Parameters: void arg (IN) Pointer to the HBA data structure bit32 idx (IN) Vector index ******************************************************************************/ void agtiapi_IntrHandlerx_( void *arg, int index ) { struct agtiapi_softc *pCard; int rv; pCard = (struct agtiapi_softc *)arg; #ifndef AGTIAPI_DPC ccb_t *pccb; #endif AG_LOCAL_LOCK(&(pCard->pCardInfo->pmIOLock)); AG_PERF_SPINLOCK(agtiapi_host_lock); if (pCard->flags & AGTIAPI_SHUT_DOWN) goto ext; rv = tiCOMInterruptHandler(&pCard->tiRoot, index); if (rv == agFALSE) { /* not our irq */ AG_SPIN_UNLOCK(agtiapi_host_lock); AG_LOCAL_UNLOCK(&(pCard->pCardInfo->pmIOLock)); return; } #ifdef AGTIAPI_DPC tasklet_hi_schedule(&pCard->tasklet_dpc[idx]); #else /* consume all completed entries, 100 is random number to be big enough */ tiCOMDelayedInterruptHandler(&pCard->tiRoot, index, 100, tiInterruptContext); AG_GET_DONE_PCCB(pccb, pCard); AG_GET_DONE_SMP_PCCB(pccb, pCard); #endif ext: AG_SPIN_UNLOCK(agtiapi_host_lock); AG_LOCAL_UNLOCK(&(pCard->pCardInfo->pmIOLock)); return; } /****************************************************************************** agtiapi_IntrHandler0() Purpose: Interrupt service routine for interrupt vector index 0. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler0( void *arg ) { agtiapi_IntrHandlerx_( arg, 0 ); return; } /****************************************************************************** agtiapi_IntrHandler1() Purpose: Interrupt service routine for interrupt vector index 1. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler1( void *arg ) { agtiapi_IntrHandlerx_( arg, 1 ); return; } /****************************************************************************** agtiapi_IntrHandler2() Purpose: Interrupt service routine for interrupt vector index 2. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler2( void *arg ) { agtiapi_IntrHandlerx_( arg, 2 ); return; } /****************************************************************************** agtiapi_IntrHandler3() Purpose: Interrupt service routine for interrupt vector index 3. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler3( void *arg ) { agtiapi_IntrHandlerx_( arg, 3 ); return; } /****************************************************************************** agtiapi_IntrHandler4() Purpose: Interrupt service routine for interrupt vector index 4. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler4( void *arg ) { agtiapi_IntrHandlerx_( arg, 4 ); return; } /****************************************************************************** agtiapi_IntrHandler5() Purpose: Interrupt service routine for interrupt vector index 5. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler5( void *arg ) { agtiapi_IntrHandlerx_( arg, 5 ); return; } /****************************************************************************** agtiapi_IntrHandler6() Purpose: Interrupt service routine for interrupt vector index 6. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler6( void *arg ) { agtiapi_IntrHandlerx_( arg, 6 ); return; } /****************************************************************************** agtiapi_IntrHandler7() Purpose: Interrupt service routine for interrupt vector index 7. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler7( void *arg ) { agtiapi_IntrHandlerx_( arg, 7 ); return; } /****************************************************************************** agtiapi_IntrHandler8() Purpose: Interrupt service routine for interrupt vector index 8. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler8( void *arg ) { agtiapi_IntrHandlerx_( arg, 8 ); return; } /****************************************************************************** agtiapi_IntrHandler9() Purpose: Interrupt service routine for interrupt vector index 9. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler9( void *arg ) { agtiapi_IntrHandlerx_( arg, 9 ); return; } /****************************************************************************** agtiapi_IntrHandler10() Purpose: Interrupt service routine for interrupt vector index 10. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler10( void *arg ) { agtiapi_IntrHandlerx_( arg, 10 ); return; } /****************************************************************************** agtiapi_IntrHandler11() Purpose: Interrupt service routine for interrupt vector index 11. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler11( void *arg ) { agtiapi_IntrHandlerx_( arg, 11 ); return; } /****************************************************************************** agtiapi_IntrHandler12() Purpose: Interrupt service routine for interrupt vector index 12. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler12( void *arg ) { agtiapi_IntrHandlerx_( arg, 12 ); return; } /****************************************************************************** agtiapi_IntrHandler13() Purpose: Interrupt service routine for interrupt vector index 13. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler13( void *arg ) { agtiapi_IntrHandlerx_( arg, 13 ); return; } /****************************************************************************** agtiapi_IntrHandler14() Purpose: Interrupt service routine for interrupt vector index 14. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler14( void *arg ) { agtiapi_IntrHandlerx_( arg, 14 ); return; } /****************************************************************************** agtiapi_IntrHandler15() Purpose: Interrupt service routine for interrupt vector index 15. Parameters: void arg (IN) Pointer to the HBA data structure ******************************************************************************/ void agtiapi_IntrHandler15( void *arg ) { agtiapi_IntrHandlerx_( arg, 15 ); return; } static void agtiapi_SglMemoryCB( void *arg, bus_dma_segment_t *dm_segs, int nseg, int error ) { bus_addr_t *addr; AGTIAPI_PRINTK("agtiapi_SglMemoryCB: start\n"); if (error != 0) { AGTIAPI_PRINTK("agtiapi_SglMemoryCB: error %d\n", error); panic("agtiapi_SglMemoryCB: error %d\n", error); return; } addr = arg; *addr = dm_segs[0].ds_addr; return; } static void agtiapi_MemoryCB( void *arg, bus_dma_segment_t *dm_segs, int nseg, int error ) { bus_addr_t *addr; AGTIAPI_PRINTK("agtiapi_MemoryCB: start\n"); if (error != 0) { AGTIAPI_PRINTK("agtiapi_MemoryCB: error %d\n", error); panic("agtiapi_MemoryCB: error %d\n", error); return; } addr = arg; *addr = dm_segs[0].ds_addr; return; } /****************************************************************************** agtiapi_alloc_requests() Purpose: Allocates resources such as dma tag and timer Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure Return: AGTIAPI_SUCCESS - success AGTIAPI_FAIL - fail Note: ******************************************************************************/ int agtiapi_alloc_requests( struct agtiapi_softc *pmcsc ) { int rsize, nsegs; U32 next_tick; nsegs = AGTIAPI_NSEGS; rsize = AGTIAPI_MAX_DMA_SEGS; // 128 AGTIAPI_PRINTK( "agtiapi_alloc_requests: maxphys 0x%lx PAGE_SIZE 0x%x \n", maxphys, PAGE_SIZE ); AGTIAPI_PRINTK( "agtiapi_alloc_requests: nsegs %d rsize %d \n", nsegs, rsize ); // 32, 128 // This is for csio->data_ptr if( bus_dma_tag_create( agNULL, // parent 1, // alignment 0, // boundary BUS_SPACE_MAXADDR, // lowaddr BUS_SPACE_MAXADDR, // highaddr NULL, // filter NULL, // filterarg BUS_SPACE_MAXSIZE_32BIT, // maxsize nsegs, // nsegments BUS_SPACE_MAXSIZE_32BIT, // maxsegsize BUS_DMA_ALLOCNOW, // flags busdma_lock_mutex, // lockfunc &pmcsc->pCardInfo->pmIOLock, // lockarg &pmcsc->buffer_dmat ) ) { AGTIAPI_PRINTK( "agtiapi_alloc_requests: Cannot alloc request DMA tag\n" ); return( ENOMEM ); } // This is for tiSgl_t of pccb in agtiapi_PrepCCBs() rsize = (sizeof(tiSgl_t) * AGTIAPI_NSEGS) * AGTIAPI_CCB_PER_DEVICE * maxTargets; AGTIAPI_PRINTK( "agtiapi_alloc_requests: rsize %d \n", rsize ); // 32, 128 if( bus_dma_tag_create( agNULL, // parent 32, // alignment 0, // boundary BUS_SPACE_MAXADDR_32BIT, // lowaddr BUS_SPACE_MAXADDR, // highaddr NULL, // filter NULL, // filterarg rsize, // maxsize 1, // nsegments rsize, // maxsegsize BUS_DMA_ALLOCNOW, // flags NULL, // lockfunc NULL, // lockarg &pmcsc->tisgl_dmat ) ) { AGTIAPI_PRINTK( "agtiapi_alloc_requests: Cannot alloc request DMA tag\n" ); return( ENOMEM ); } if( bus_dmamem_alloc( pmcsc->tisgl_dmat, (void **)&pmcsc->tisgl_mem, BUS_DMA_NOWAIT, &pmcsc->tisgl_map ) ) { AGTIAPI_PRINTK( "agtiapi_alloc_requests: Cannot allocate SGL memory\n" ); return( ENOMEM ); } bzero( pmcsc->tisgl_mem, rsize ); bus_dmamap_load( pmcsc->tisgl_dmat, pmcsc->tisgl_map, pmcsc->tisgl_mem, rsize, agtiapi_SglMemoryCB, &pmcsc->tisgl_busaddr, BUS_DMA_NOWAIT /* 0 */ ); mtx_init( &pmcsc->OS_timer_lock, "OS timer lock", NULL, MTX_DEF ); mtx_init( &pmcsc->IO_timer_lock, "IO timer lock", NULL, MTX_DEF ); mtx_init( &pmcsc->devRmTimerLock, "targ rm timer lock", NULL, MTX_DEF ); callout_init_mtx( &pmcsc->OS_timer, &pmcsc->OS_timer_lock, 0 ); callout_init_mtx( &pmcsc->IO_timer, &pmcsc->IO_timer_lock, 0 ); callout_init_mtx( &pmcsc->devRmTimer, &pmcsc->devRmTimerLock, 0); next_tick = pmcsc->pCardInfo->tiRscInfo.tiLoLevelResource. loLevelOption.usecsPerTick / USEC_PER_TICK; AGTIAPI_PRINTK( "agtiapi_alloc_requests: before callout_reset, " "next_tick 0x%x\n", next_tick ); callout_reset( &pmcsc->OS_timer, next_tick, agtiapi_TITimer, pmcsc ); return 0; } /****************************************************************************** agtiapi_alloc_ostimem() Purpose: Allocates memory used later in ostiAllocMemory Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to the HBA data structure Return: AGTIAPI_SUCCESS - success AGTIAPI_FAIL - fail Note: This is a pre-allocation for ostiAllocMemory() "non-cacheable" function calls ******************************************************************************/ int agtiapi_alloc_ostimem( struct agtiapi_softc *pmcsc ) { int rsize, nomsize; nomsize = 4096; rsize = AGTIAPI_DYNAMIC_MAX * nomsize; // 8M AGTIAPI_PRINTK("agtiapi_alloc_ostimem: rsize %d \n", rsize); if( bus_dma_tag_create( agNULL, // parent 32, // alignment 0, // boundary BUS_SPACE_MAXADDR, // lowaddr BUS_SPACE_MAXADDR, // highaddr NULL, // filter NULL, // filterarg rsize, // maxsize (size) 1, // number of segments rsize, // maxsegsize 0, // flags NULL, // lockfunc NULL, // lockarg &pmcsc->osti_dmat ) ) { AGTIAPI_PRINTK( "agtiapi_alloc_ostimem: Can't create no-cache mem tag\n" ); return AGTIAPI_FAIL; } if( bus_dmamem_alloc( pmcsc->osti_dmat, &pmcsc->osti_mem, BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, &pmcsc->osti_mapp ) ) { AGTIAPI_PRINTK( "agtiapi_alloc_ostimem: Cannot allocate cache mem %d\n", rsize ); return AGTIAPI_FAIL; } bus_dmamap_load( pmcsc->osti_dmat, pmcsc->osti_mapp, pmcsc->osti_mem, rsize, agtiapi_MemoryCB, // try reuse of CB for same goal &pmcsc->osti_busaddr, BUS_DMA_NOWAIT ); // populate all the ag_dma_addr_t osti_busaddr/mem fields with addresses for // handy reference when driver is in motion int idx; ag_card_info_t *pCardInfo = pmcsc->pCardInfo; ag_dma_addr_t *pMem; for( idx = 0; idx < AGTIAPI_DYNAMIC_MAX; idx++ ) { pMem = &pCardInfo->dynamicMem[idx]; pMem->nocache_busaddr = pmcsc->osti_busaddr + ( idx * nomsize ); pMem->nocache_mem = (void*)((U64)pmcsc->osti_mem + ( idx * nomsize )); pCardInfo->freeDynamicMem[idx] = &pCardInfo->dynamicMem[idx]; } pCardInfo->topOfFreeDynamicMem = AGTIAPI_DYNAMIC_MAX; return AGTIAPI_SUCCESS; } /****************************************************************************** agtiapi_cam_action() Purpose: Parses CAM frames and triggers a corresponding action Parameters: struct cam_sim *sim (IN) Pointer to SIM data structure union ccb * ccb (IN) Pointer to CAM ccb data structure Return: Note: ******************************************************************************/ static void agtiapi_cam_action( struct cam_sim *sim, union ccb * ccb ) { struct agtiapi_softc *pmcsc; tiDeviceHandle_t *pDevHandle = NULL; // acts as flag as well tiDeviceInfo_t devInfo; int pathID, targetID, lunID; int lRetVal; U32 TID; U32 speed = 150000; pmcsc = cam_sim_softc( sim ); AGTIAPI_IO( "agtiapi_cam_action: start pmcs %p\n", pmcsc ); if (pmcsc == agNULL) { AGTIAPI_PRINTK( "agtiapi_cam_action: start pmcs is NULL\n" ); return; } mtx_assert( &(pmcsc->pCardInfo->pmIOLock), MA_OWNED ); AGTIAPI_IO( "agtiapi_cam_action: cardNO %d func_code 0x%x\n", pmcsc->cardNo, ccb->ccb_h.func_code ); pathID = xpt_path_path_id( ccb->ccb_h.path ); targetID = xpt_path_target_id( ccb->ccb_h.path ); lunID = xpt_path_lun_id( ccb->ccb_h.path ); AGTIAPI_IO( "agtiapi_cam_action: P 0x%x T 0x%x L 0x%x\n", pathID, targetID, lunID ); switch (ccb->ccb_h.func_code) { case XPT_PATH_INQ: { struct ccb_pathinq *cpi; /* See architecure book p180*/ cpi = &ccb->cpi; cpi->version_num = 1; cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16; cpi->target_sprt = 0; cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; cpi->hba_eng_cnt = 0; cpi->max_target = maxTargets - 1; cpi->max_lun = AGTIAPI_MAX_LUN; /* Max supported I/O size, in bytes. */ cpi->maxio = ctob(AGTIAPI_NSEGS - 1); cpi->initiator_id = 255; strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strlcpy(cpi->hba_vid, "PMC", HBA_IDLEN); strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = cam_sim_bus(sim); // rate is set when XPT_GET_TRAN_SETTINGS is processed cpi->base_transfer_speed = 150000; cpi->transport = XPORT_SAS; cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC3; cpi->ccb_h.status = CAM_REQ_CMP; break; } case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *cts; struct ccb_trans_settings_sas *sas; struct ccb_trans_settings_scsi *scsi; if ( pmcsc->flags & AGTIAPI_SHUT_DOWN ) { return; } cts = &ccb->cts; sas = &ccb->cts.xport_specific.sas; scsi = &cts->proto_specific.scsi; cts->protocol = PROTO_SCSI; cts->protocol_version = SCSI_REV_SPC3; cts->transport = XPORT_SAS; cts->transport_version = 0; sas->valid = CTS_SAS_VALID_SPEED; /* this sets the "MB/s transfers" */ if (pmcsc != NULL && targetID >= 0 && targetID < maxTargets) { if (pmcsc->pWWNList != NULL) { TID = INDEX(pmcsc, targetID); if (TID < maxTargets) { pDevHandle = pmcsc->pDevList[TID].pDevHandle; } } } if (pDevHandle) { tiINIGetDeviceInfo( &pmcsc->tiRoot, pDevHandle, &devInfo ); switch (devInfo.info.devType_S_Rate & 0xF) { case 0x8: speed = 150000; break; case 0x9: speed = 300000; break; case 0xA: speed = 600000; break; case 0xB: speed = 1200000; break; default: speed = 150000; break; } } sas->bitrate = speed; scsi->valid = CTS_SCSI_VALID_TQ; scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_RESET_BUS: { lRetVal = agtiapi_eh_HostReset( pmcsc, ccb ); // usually works first time if ( SUCCESS == lRetVal ) { AGTIAPI_PRINTK( "agtiapi_cam_action: bus reset success.\n" ); } else { AGTIAPI_PRINTK( "agtiapi_cam_action: bus reset failed.\n" ); } ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_RESET_DEV: { ccb->ccb_h.status = CAM_REQ_CMP; break; } case XPT_ABORT: { ccb->ccb_h.status = CAM_REQ_CMP; break; } #if __FreeBSD_version >= 900026 case XPT_SMP_IO: { agtiapi_QueueSMP( pmcsc, ccb ); return; } #endif /* __FreeBSD_version >= 900026 */ case XPT_SCSI_IO: { if(pmcsc->dev_scan == agFALSE) { ccb->ccb_h.status = CAM_SEL_TIMEOUT; break; } if (pmcsc->flags & AGTIAPI_SHUT_DOWN) { AGTIAPI_PRINTK( "agtiapi_cam_action: shutdown, XPT_SCSI_IO 0x%x\n", XPT_SCSI_IO ); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; break; } else { AGTIAPI_IO( "agtiapi_cam_action: Zero XPT_SCSI_IO 0x%x, doing IOs\n", XPT_SCSI_IO ); agtiapi_QueueCmnd_( pmcsc, ccb ); return; } } case XPT_CALC_GEOMETRY: { cam_calc_geometry(&ccb->ccg, 1); ccb->ccb_h.status = CAM_REQ_CMP; break; } default: { /* XPT_SET_TRAN_SETTINGS */ AGTIAPI_IO( "agtiapi_cam_action: default function code 0x%x\n", ccb->ccb_h.func_code ); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; break; } } /* switch */ xpt_done(ccb); } /****************************************************************************** agtiapi_GetCCB() Purpose: Get a ccb from free list or allocate a new one Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA structure Return: Pointer to a ccb structure, or NULL if not available Note: ******************************************************************************/ STATIC pccb_t agtiapi_GetCCB( struct agtiapi_softc *pmcsc ) { pccb_t pccb; AGTIAPI_IO( "agtiapi_GetCCB: start\n" ); AG_LOCAL_LOCK( &pmcsc->ccbLock ); /* get the ccb from the head of the free list */ if ((pccb = (pccb_t)pmcsc->ccbFreeList) != NULL) { pmcsc->ccbFreeList = (caddr_t *)pccb->pccbNext; pccb->pccbNext = NULL; pccb->flags = ACTIVE; pccb->startTime = 0; pmcsc->activeCCB++; AGTIAPI_IO( "agtiapi_GetCCB: re-allocated ccb %p\n", pccb ); } else { AGTIAPI_PRINTK( "agtiapi_GetCCB: kmalloc ERROR - no ccb allocated\n" ); } AG_LOCAL_UNLOCK( &pmcsc->ccbLock ); return pccb; } /****************************************************************************** agtiapi_QueueCmnd_() Purpose: Calls for sending CCB and excuting on HBA. Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure union ccb * ccb (IN) Pointer to CAM ccb data structure Return: 0 - Command is pending to execute 1 - Command returned without further process Note: ******************************************************************************/ int agtiapi_QueueCmnd_(struct agtiapi_softc *pmcsc, union ccb * ccb) { struct ccb_scsiio *csio = &ccb->csio; pccb_t pccb = agNULL; // call dequeue int status = tiSuccess; U32 Channel = CMND_TO_CHANNEL(ccb); U32 TID = CMND_TO_TARGET(ccb); U32 LUN = CMND_TO_LUN(ccb); AGTIAPI_IO( "agtiapi_QueueCmnd_: start\n" ); /* no support for CBD > 16 */ if (csio->cdb_len > 16) { AGTIAPI_PRINTK( "agtiapi_QueueCmnd_: unsupported CDB length %d\n", csio->cdb_len ); ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_INVALID;//CAM_REQ_CMP; xpt_done(ccb); return tiError; } if (TID < 0 || TID >= maxTargets) { AGTIAPI_PRINTK("agtiapi_QueueCmnd_: INVALID TID ERROR\n"); ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_DEV_NOT_THERE;//CAM_REQ_CMP; xpt_done(ccb); return tiError; } /* get a ccb */ if ((pccb = agtiapi_GetCCB(pmcsc)) == NULL) { AGTIAPI_PRINTK("agtiapi_QueueCmnd_: GetCCB ERROR\n"); if (pmcsc != NULL) { ag_device_t *targ; TID = INDEX(pmcsc, TID); targ = &pmcsc->pDevList[TID]; agtiapi_adjust_queue_depth(ccb->ccb_h.path,targ->qdepth); } ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; xpt_done(ccb); return tiBusy; } pccb->pmcsc = pmcsc; /* initialize Command Control Block (CCB) */ pccb->targetId = TID; pccb->lun = LUN; pccb->channel = Channel; pccb->ccb = ccb; /* for struct scsi_cmnd */ pccb->senseLen = csio->sense_len; pccb->startTime = ticks; pccb->pSenseData = (caddr_t) &csio->sense_data; pccb->tiSuperScsiRequest.flags = 0; /* each channel is reserved for different addr modes */ pccb->addrMode = agtiapi_AddrModes[Channel]; status = agtiapi_PrepareSGList(pmcsc, pccb); if (status != tiSuccess) { AGTIAPI_PRINTK("agtiapi_QueueCmnd_: agtiapi_PrepareSGList failure\n"); agtiapi_FreeCCB(pmcsc, pccb); if (status == tiReject) { ccb->ccb_h.status = CAM_REQ_INVALID; } else { ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done( ccb ); return tiError; } return status; } /****************************************************************************** agtiapi_DumpCDB() Purpose: Prints out CDB Parameters: const char *ptitle (IN) A string to be printed ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: ******************************************************************************/ STATIC void agtiapi_DumpCDB(const char *ptitle, ccb_t *pccb) { union ccb *ccb; struct ccb_scsiio *csio; bit8 cdb[64]; int len; if (pccb == NULL) { printf( "agtiapi_DumpCDB: no pccb here \n" ); panic("agtiapi_DumpCDB: pccb is NULL. called from %s\n", ptitle); return; } ccb = pccb->ccb; if (ccb == NULL) { printf( "agtiapi_DumpCDB: no ccb here \n" ); panic( "agtiapi_DumpCDB: pccb %p ccb %p flags %d ccb NULL! " "called from %s\n", pccb, pccb->ccb, pccb->flags, ptitle ); return; } csio = &ccb->csio; if (csio == NULL) { printf( "agtiapi_DumpCDB: no csio here \n" ); panic( "agtiapi_DumpCDB: pccb%p ccb%p flags%d csio NULL! called from %s\n", pccb, pccb->ccb, pccb->flags, ptitle ); return; } len = MIN(64, csio->cdb_len); if (csio->ccb_h.flags & CAM_CDB_POINTER) { bcopy(csio->cdb_io.cdb_ptr, &cdb[0], len); } else { bcopy(csio->cdb_io.cdb_bytes, &cdb[0], len); } AGTIAPI_IO( "agtiapi_DumpCDB: pccb%p CDB0x%x csio->cdb_len %d" " len %d from %s\n", pccb, cdb[0], csio->cdb_len, len, ptitle ); return; } /****************************************************************************** agtiapi_DoSoftReset() Purpose: Do card reset Parameters: *data (IN) point to pmcsc (struct agtiapi_softc *) Return: Note: ******************************************************************************/ int agtiapi_DoSoftReset (struct agtiapi_softc *pmcsc) { int ret; unsigned long flags; pmcsc->flags |= AGTIAPI_SOFT_RESET; AG_SPIN_LOCK_IRQ( agtiapi_host_lock, flags ); ret = agtiapi_ResetCard( pmcsc, &flags ); AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); if( ret != AGTIAPI_SUCCESS ) return tiError; return SUCCESS; } /****************************************************************************** agtiapi_CheckIOTimeout() Purpose: Timeout function for SCSI IO or TM Parameters: *data (IN) point to pCard (ag_card_t *) Return: Note: ******************************************************************************/ STATIC void agtiapi_CheckIOTimeout(void *data) { U32 status = AGTIAPI_SUCCESS; ccb_t *pccb; struct agtiapi_softc *pmcsc; pccb_t pccb_curr; pccb_t pccb_next; pmcsc = (struct agtiapi_softc *)data; //AGTIAPI_PRINTK("agtiapi_CheckIOTimeout: Enter\n"); //AGTIAPI_PRINTK("agtiapi_CheckIOTimeout: Active CCB %d\n", pmcsc->activeCCB); pccb = (pccb_t)pmcsc->ccbChainList; /* if link is down, do nothing */ if ((pccb == NULL) || (pmcsc->activeCCB == 0)) { //AGTIAPI_PRINTK("agtiapi_CheckIOTimeout: goto restart_timer\n"); goto restart_timer; } AG_SPIN_LOCK_IRQ(agtiapi_host_lock, flags); if (pmcsc->flags & AGTIAPI_SHUT_DOWN) goto ext; pccb_curr = pccb; /* Walk thorugh the IO Chain linked list to find the pending io */ /* Set the TM flag based on the pccb type, i.e SCSI IO or TM cmd */ while (pccb_curr != NULL) { /* start from 1st ccb in the chain */ pccb_next = pccb_curr->pccbChainNext; if( (pccb_curr->flags == 0) || (pccb_curr->tiIORequest.tdData == NULL) || (pccb_curr->startTime == 0) /* && (pccb->startTime == 0) */) { //AGTIAPI_PRINTK("agtiapi_CheckIOTimeout: move to next element\n"); } else if ( ( (ticks-pccb_curr->startTime) >= ag_timeout_secs ) && !(pccb_curr->flags & TIMEDOUT) ) { AGTIAPI_PRINTK( "agtiapi_CheckIOTimeout: pccb %p timed out, call TM " "function -- flags=%x startTime=%ld tdData = %p\n", pccb_curr, pccb_curr->flags, pccb->startTime, pccb_curr->tiIORequest.tdData ); pccb_curr->flags |= TIMEDOUT; status = agtiapi_StartTM(pmcsc, pccb_curr); if (status == AGTIAPI_SUCCESS) { AGTIAPI_PRINTK( "agtiapi_CheckIOTimeout: TM Request sent with " "success\n" ); goto restart_timer; } else { #ifdef AGTIAPI_LOCAL_RESET /* abort request did not go through */ AGTIAPI_PRINTK("agtiapi_CheckIOTimeout: Abort request failed\n"); /* TODO: call Soft reset here */ AGTIAPI_PRINTK( "agtiapi_CheckIOTimeout:in agtiapi_CheckIOTimeout() " "abort request did not go thru ==> soft reset#7, then " "restart timer\n" ); agtiapi_DoSoftReset (pmcsc); goto restart_timer; #endif } } pccb_curr = pccb_next; } restart_timer: callout_reset(&pmcsc->IO_timer, 1*hz, agtiapi_CheckIOTimeout, pmcsc); ext: AG_SPIN_UNLOCK_IRQ(agtiapi_host_lock, flags); return; } /****************************************************************************** agtiapi_StartTM() Purpose: DDI calls for aborting outstanding IO command Parameters: struct scsi_cmnd *pccb (IN) Pointer to the command to be aborted unsigned long flags (IN/out) spinlock flags used in locking from calling layers Return: AGTIAPI_SUCCESS - success AGTIAPI_FAIL - fail ******************************************************************************/ int agtiapi_StartTM(struct agtiapi_softc *pCard, ccb_t *pccb) { ccb_t *pTMccb = NULL; U32 status = AGTIAPI_SUCCESS; ag_device_t *pDevice = NULL; U32 TMstatus = tiSuccess; AGTIAPI_PRINTK( "agtiapi_StartTM: pccb %p, pccb->flags %x\n", pccb, pccb->flags ); if (pccb == NULL) { AGTIAPI_PRINTK("agtiapi_StartTM: %p not found\n",pccb); status = AGTIAPI_SUCCESS; goto ext; } if (!pccb->tiIORequest.tdData) { /* should not be the case */ AGTIAPI_PRINTK("agtiapi_StartTM: ccb %p flag 0x%x tid %d no tdData " "ERROR\n", pccb, pccb->flags, pccb->targetId); status = AGTIAPI_FAIL; } else { /* If timedout CCB is TM_ABORT_TASK command, issue LocalAbort first to clear pending TM_ABORT_TASK */ /* Else Device State will not be put back to Operational, (refer FW) */ if (pccb->flags & TASK_MANAGEMENT) { if (tiINIIOAbort(&pCard->tiRoot, &pccb->tiIORequest) != tiSuccess) { AGTIAPI_PRINTK( "agtiapi_StartTM: LocalAbort Request for Abort_TASK " "TM failed\n" ); /* TODO: call Soft reset here */ AGTIAPI_PRINTK( "agtiapi_StartTM: in agtiapi_StartTM() abort " "tiINIIOAbort() failed ==> soft reset#8\n" ); agtiapi_DoSoftReset( pCard ); } else { AGTIAPI_PRINTK( "agtiapi_StartTM: LocalAbort for Abort_TASK TM " "Request sent\n" ); status = AGTIAPI_SUCCESS; } } else { /* get a ccb */ if ((pTMccb = agtiapi_GetCCB(pCard)) == NULL) { AGTIAPI_PRINTK("agtiapi_StartTM: TM resource unavailable!\n"); status = AGTIAPI_FAIL; goto ext; } pTMccb->pmcsc = pCard; pTMccb->targetId = pccb->targetId; pTMccb->devHandle = pccb->devHandle; if (pTMccb->targetId >= pCard->devDiscover) { AGTIAPI_PRINTK("agtiapi_StartTM: Incorrect dev Id in TM!\n"); status = AGTIAPI_FAIL; goto ext; } if (pTMccb->targetId < 0 || pTMccb->targetId >= maxTargets) { return AGTIAPI_FAIL; } if (INDEX(pCard, pTMccb->targetId) >= maxTargets) { return AGTIAPI_FAIL; } pDevice = &pCard->pDevList[INDEX(pCard, pTMccb->targetId)]; if ((pDevice == NULL) || !(pDevice->flags & ACTIVE)) { return AGTIAPI_FAIL; } /* save pending io to issue local abort at Task mgmt CB */ pTMccb->pccbIO = pccb; AGTIAPI_PRINTK( "agtiapi_StartTM: pTMccb %p flag %x tid %d via TM " "request !\n", pTMccb, pTMccb->flags, pTMccb->targetId ); pTMccb->flags &= ~(TASK_SUCCESS | ACTIVE); pTMccb->flags |= TASK_MANAGEMENT; TMstatus = tiINITaskManagement(&pCard->tiRoot, pccb->devHandle, AG_ABORT_TASK, &pccb->tiSuperScsiRequest.scsiCmnd.lun, &pccb->tiIORequest, &pTMccb->tiIORequest); if (TMstatus == tiSuccess) { AGTIAPI_PRINTK( "agtiapi_StartTM: TM_ABORT_TASK request success ccb " "%p, pTMccb %p\n", pccb, pTMccb ); pTMccb->startTime = ticks; status = AGTIAPI_SUCCESS; } else if (TMstatus == tiIONoDevice) { AGTIAPI_PRINTK( "agtiapi_StartTM: TM_ABORT_TASK request tiIONoDevice ccb " "%p, pTMccb %p\n", pccb, pTMccb ); status = AGTIAPI_SUCCESS; } else { AGTIAPI_PRINTK( "agtiapi_StartTM: TM_ABORT_TASK request failed ccb %p, " "pTMccb %p\n", pccb, pTMccb ); status = AGTIAPI_FAIL; agtiapi_FreeTMCCB(pCard, pTMccb); /* TODO */ /* call TM_TARGET_RESET */ } } } ext: AGTIAPI_PRINTK("agtiapi_StartTM: return %d flgs %x\n", status, (pccb) ? pccb->flags : -1); return status; } /* agtiapi_StartTM */ #if __FreeBSD_version > 901000 /****************************************************************************** agtiapi_PrepareSGList() Purpose: This function prepares scatter-gather list for the given ccb Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - success 1 - failure Note: ******************************************************************************/ static int agtiapi_PrepareSGList(struct agtiapi_softc *pmcsc, ccb_t *pccb) { union ccb *ccb = pccb->ccb; struct ccb_scsiio *csio = &ccb->csio; struct ccb_hdr *ccbh = &ccb->ccb_h; AGTIAPI_IO( "agtiapi_PrepareSGList: start\n" ); // agtiapi_DumpCDB("agtiapi_PrepareSGList", pccb); AGTIAPI_IO( "agtiapi_PrepareSGList: dxfer_len %d\n", csio->dxfer_len ); if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { switch((ccbh->flags & CAM_DATA_MASK)) { int error; struct bus_dma_segment seg; case CAM_DATA_VADDR: /* Virtual address that needs to translated into one or more physical address ranges. */ // int error; // AG_LOCAL_LOCK(&(pmcsc->pCardInfo->pmIOLock)); AGTIAPI_IO( "agtiapi_PrepareSGList: virtual address\n" ); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csio->data_ptr, csio->dxfer_len, agtiapi_PrepareSGListCB, pccb, BUS_DMA_NOWAIT/* 0 */ ); // AG_LOCAL_UNLOCK( &(pmcsc->pCardInfo->pmIOLock) ); if (error == EINPROGRESS) { /* So as to maintain ordering, freeze the controller queue until our mapping is returned. */ AGTIAPI_PRINTK("agtiapi_PrepareSGList: EINPROGRESS\n"); xpt_freeze_simq(pmcsc->sim, 1); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } break; case CAM_DATA_PADDR: /* We have been given a pointer to single physical buffer. */ /* pccb->tiSuperScsiRequest.sglVirtualAddr = seg.ds_addr; */ //struct bus_dma_segment seg; AGTIAPI_PRINTK("agtiapi_PrepareSGList: physical address\n"); seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; seg.ds_len = csio->dxfer_len; // * 0xFF to be defined agtiapi_PrepareSGListCB(pccb, &seg, 1, 0xAABBCCDD); break; default: AGTIAPI_PRINTK("agtiapi_PrepareSGList: unexpected case\n"); return tiReject; } } else { agtiapi_PrepareSGListCB(pccb, NULL, 0, 0xAAAAAAAA); } return tiSuccess; } #else /****************************************************************************** agtiapi_PrepareSGList() Purpose: This function prepares scatter-gather list for the given ccb Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - success 1 - failure Note: ******************************************************************************/ static int agtiapi_PrepareSGList(struct agtiapi_softc *pmcsc, ccb_t *pccb) { union ccb *ccb = pccb->ccb; struct ccb_scsiio *csio = &ccb->csio; struct ccb_hdr *ccbh = &ccb->ccb_h; AGTIAPI_IO( "agtiapi_PrepareSGList: start\n" ); // agtiapi_DumpCDB("agtiapi_PrepareSGList", pccb); AGTIAPI_IO( "agtiapi_PrepareSGList: dxfer_len %d\n", csio->dxfer_len ); if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if ((ccbh->flags & CAM_SCATTER_VALID) == 0) { /* We've been given a pointer to a single buffer. */ if ((ccbh->flags & CAM_DATA_PHYS) == 0) { /* Virtual address that needs to translated into one or more physical address ranges. */ int error; // AG_LOCAL_LOCK(&(pmcsc->pCardInfo->pmIOLock)); AGTIAPI_IO( "agtiapi_PrepareSGList: virtual address\n" ); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csio->data_ptr, csio->dxfer_len, agtiapi_PrepareSGListCB, pccb, BUS_DMA_NOWAIT/* 0 */ ); // AG_LOCAL_UNLOCK( &(pmcsc->pCardInfo->pmIOLock) ); if (error == EINPROGRESS) { /* So as to maintain ordering, freeze the controller queue until our mapping is returned. */ AGTIAPI_PRINTK("agtiapi_PrepareSGList: EINPROGRESS\n"); xpt_freeze_simq(pmcsc->sim, 1); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } } else { /* We have been given a pointer to single physical buffer. */ /* pccb->tiSuperScsiRequest.sglVirtualAddr = seg.ds_addr; */ struct bus_dma_segment seg; AGTIAPI_PRINTK("agtiapi_PrepareSGList: physical address\n"); seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr; seg.ds_len = csio->dxfer_len; // * 0xFF to be defined agtiapi_PrepareSGListCB(pccb, &seg, 1, 0xAABBCCDD); } } else { AGTIAPI_PRINTK("agtiapi_PrepareSGList: unexpected case\n"); return tiReject; } } else { agtiapi_PrepareSGListCB(pccb, NULL, 0, 0xAAAAAAAA); } return tiSuccess; } #endif /****************************************************************************** agtiapi_PrepareSGListCB() Purpose: Callback function for bus_dmamap_load() This fuctions sends IO to LL layer. Parameters: void *arg (IN) Pointer to the HBA data structure bus_dma_segment_t *segs (IN) Pointer to dma segment int nsegs (IN) number of dma segment int error (IN) error Return: Note: ******************************************************************************/ static void agtiapi_PrepareSGListCB( void *arg, bus_dma_segment_t *segs, int nsegs, int error ) { pccb_t pccb = arg; union ccb *ccb = pccb->ccb; struct ccb_scsiio *csio = &ccb->csio; struct agtiapi_softc *pmcsc; tiIniScsiCmnd_t *pScsiCmnd; bit32 i; bus_dmasync_op_t op; U32_64 phys_addr; U08 *CDB; int io_is_encryptable = 0; unsigned long long start_lba = 0; ag_device_t *pDev; U32 TID = CMND_TO_TARGET(ccb); AGTIAPI_IO( "agtiapi_PrepareSGListCB: start, nsegs %d error 0x%x\n", nsegs, error ); pmcsc = pccb->pmcsc; if (error != tiSuccess) { if (error == 0xAABBCCDD || error == 0xAAAAAAAA) { // do nothing } else { AGTIAPI_PRINTK("agtiapi_PrepareSGListCB: error status 0x%x\n", error); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); agtiapi_FreeCCB(pmcsc, pccb); if (error == EFBIG) ccb->ccb_h.status = CAM_REQ_TOO_BIG; else ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); return; } } if (nsegs > AGTIAPI_MAX_DMA_SEGS) { AGTIAPI_PRINTK( "agtiapi_PrepareSGListCB: over the limit. nsegs %d" " AGTIAPI_MAX_DMA_SEGS %d\n", nsegs, AGTIAPI_MAX_DMA_SEGS ); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); agtiapi_FreeCCB(pmcsc, pccb); ccb->ccb_h.status = CAM_REQ_TOO_BIG; xpt_done(ccb); return; } /* fill in IO information */ pccb->dataLen = csio->dxfer_len; /* start fill in sgl structure */ if (nsegs == 1 && error == 0xAABBCCDD) { /* to be tested */ /* A single physical buffer */ AGTIAPI_PRINTK("agtiapi_PrepareSGListCB: nsegs is 1\n"); CPU_TO_LE32(pccb->tiSuperScsiRequest.agSgl1, segs[0].ds_addr); pccb->tiSuperScsiRequest.agSgl1.len = htole32(pccb->dataLen); pccb->tiSuperScsiRequest.agSgl1.type = htole32(tiSgl); pccb->tiSuperScsiRequest.sglVirtualAddr = (void *)segs->ds_addr; pccb->numSgElements = 1; } else if (nsegs == 0 && error == 0xAAAAAAAA) { /* no data transfer */ AGTIAPI_IO( "agtiapi_PrepareSGListCB: no data transfer\n" ); pccb->tiSuperScsiRequest.agSgl1.len = 0; pccb->dataLen = 0; pccb->numSgElements = 0; } else { /* virtual/logical buffer */ if (nsegs == 1) { pccb->dataLen = segs[0].ds_len; CPU_TO_LE32(pccb->tiSuperScsiRequest.agSgl1, segs[0].ds_addr); pccb->tiSuperScsiRequest.agSgl1.type = htole32(tiSgl); pccb->tiSuperScsiRequest.agSgl1.len = htole32(segs[0].ds_len); pccb->tiSuperScsiRequest.sglVirtualAddr = (void *)csio->data_ptr; pccb->numSgElements = nsegs; } else { pccb->dataLen = 0; /* loop */ for (i = 0; i < nsegs; i++) { pccb->sgList[i].len = htole32(segs[i].ds_len); CPU_TO_LE32(pccb->sgList[i], segs[i].ds_addr); pccb->sgList[i].type = htole32(tiSgl); pccb->dataLen += segs[i].ds_len; } /* for */ pccb->numSgElements = nsegs; /* set up sgl buffer address */ CPU_TO_LE32(pccb->tiSuperScsiRequest.agSgl1, pccb->tisgl_busaddr); pccb->tiSuperScsiRequest.agSgl1.type = htole32(tiSglList); pccb->tiSuperScsiRequest.agSgl1.len = htole32(pccb->dataLen); pccb->tiSuperScsiRequest.sglVirtualAddr = (void *)csio->data_ptr; pccb->numSgElements = nsegs; } /* else */ } /* set data transfer direction */ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { op = BUS_DMASYNC_PREWRITE; pccb->tiSuperScsiRequest.dataDirection = tiDirectionOut; } else { op = BUS_DMASYNC_PREREAD; pccb->tiSuperScsiRequest.dataDirection = tiDirectionIn; } pScsiCmnd = &pccb->tiSuperScsiRequest.scsiCmnd; pScsiCmnd->expDataLength = pccb->dataLen; if (csio->ccb_h.flags & CAM_CDB_POINTER) { bcopy(csio->cdb_io.cdb_ptr, &pScsiCmnd->cdb[0], csio->cdb_len); } else { bcopy(csio->cdb_io.cdb_bytes, &pScsiCmnd->cdb[0],csio->cdb_len); } CDB = &pScsiCmnd->cdb[0]; switch (CDB[0]) { case REQUEST_SENSE: /* requires different buffer */ /* This code should not be excercised because SAS support auto sense For the completeness, vtophys() is still used here. */ AGTIAPI_PRINTK("agtiapi_PrepareSGListCB: QueueCmnd - REQUEST SENSE new\n"); pccb->tiSuperScsiRequest.agSgl1.len = htole32(pccb->senseLen); phys_addr = vtophys(&csio->sense_data); CPU_TO_LE32(pccb->tiSuperScsiRequest.agSgl1, phys_addr); pccb->tiSuperScsiRequest.agSgl1.type = htole32(tiSgl); pccb->dataLen = pccb->senseLen; pccb->numSgElements = 1; break; case INQUIRY: /* only using lun 0 for device type detection */ pccb->flags |= AGTIAPI_INQUIRY; break; case TEST_UNIT_READY: case RESERVE: case RELEASE: case START_STOP: pccb->tiSuperScsiRequest.agSgl1.len = 0; pccb->dataLen = 0; break; case READ_6: case WRITE_6: /* Extract LBA */ start_lba = ((CDB[1] & 0x1f) << 16) | (CDB[2] << 8) | (CDB[3]); #ifdef HIALEAH_ENCRYPTION io_is_encryptable = 1; #endif break; case READ_10: case WRITE_10: case READ_12: case WRITE_12: /* Extract LBA */ start_lba = (CDB[2] << 24) | (CDB[3] << 16) | (CDB[4] << 8) | (CDB[5]); #ifdef HIALEAH_ENCRYPTION io_is_encryptable = 1; #endif break; case READ_16: case WRITE_16: /* Extract LBA */ start_lba = (CDB[2] << 24) | (CDB[3] << 16) | (CDB[4] << 8) | (CDB[5]); start_lba <<= 32; start_lba |= ((CDB[6] << 24) | (CDB[7] << 16) | (CDB[8] << 8) | (CDB[9])); #ifdef HIALEAH_ENCRYPTION io_is_encryptable = 1; #endif break; default: break; } /* fill device lun based one address mode */ agtiapi_SetLunField(pccb); if (pccb->targetId < 0 || pccb->targetId >= maxTargets) { pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_FreeCCB(pmcsc, pccb); ccb->ccb_h.status = CAM_DEV_NOT_THERE; // ## v. CAM_FUNC_NOTAVAIL xpt_done(ccb); pccb->ccb = NULL; return; } if (INDEX(pmcsc, pccb->targetId) >= maxTargets) { pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_FreeCCB(pmcsc, pccb); ccb->ccb_h.status = CAM_DEV_NOT_THERE; // ## v. CAM_FUNC_NOTAVAIL xpt_done(ccb); pccb->ccb = NULL; return; } pDev = &pmcsc->pDevList[INDEX(pmcsc, pccb->targetId)]; #if 1 if ((pmcsc->flags & EDC_DATA) && (pDev->flags & EDC_DATA)) { /* * EDC support: * * Possible command supported - * READ_6, READ_10, READ_12, READ_16, READ_LONG, READ_BUFFER, * READ_DEFECT_DATA, etc. * WRITE_6, WRITE_10, WRITE_12, WRITE_16, WRITE_LONG, WRITE_LONG2, * WRITE_BUFFER, WRITE_VERIFY, WRITE_VERIFY_12, etc. * * Do some data length adjustment and set chip operation instruction. */ switch (CDB[0]) { case READ_6: case READ_10: case READ_12: case READ_16: // BUG_ON(pccb->tiSuperScsiRequest.flags & TI_SCSI_INITIATOR_ENCRYPT); #ifdef AGTIAPI_TEST_DIF pccb->tiSuperScsiRequest.flags |= TI_SCSI_INITIATOR_DIF; #endif pccb->flags |= EDC_DATA; #ifdef TEST_VERIFY_AND_FORWARD pccb->tiSuperScsiRequest.Dif.flags = DIF_VERIFY_FORWARD | DIF_UDT_REF_BLOCK_COUNT; if(pDev->sector_size == 520) { pScsiCmnd->expDataLength += (pccb->dataLen / 512) * 8; } else if(pDev->sector_size == 4104) { pScsiCmnd->expDataLength += (pccb->dataLen / 4096) * 8; } #else #ifdef AGTIAPI_TEST_DIF pccb->tiSuperScsiRequest.Dif.flags = DIF_VERIFY_DELETE | DIF_UDT_REF_BLOCK_COUNT; #endif #endif #ifdef AGTIAPI_TEST_DIF switch(pDev->sector_size) { case 528: pccb->tiSuperScsiRequest.Dif.flags |= ( DIF_BLOCK_SIZE_520 << 16 ); break; case 4104: pccb->tiSuperScsiRequest.Dif.flags |= ( DIF_BLOCK_SIZE_4096 << 16 ); break; case 4168: pccb->tiSuperScsiRequest.Dif.flags |= ( DIF_BLOCK_SIZE_4160 << 16 ); break; } if(pCard->flags & EDC_DATA_CRC) pccb->tiSuperScsiRequest.Dif.flags |= DIF_CRC_VERIFICATION; /* Turn on upper 4 bits of UVM */ pccb->tiSuperScsiRequest.Dif.flags |= 0x03c00000; #endif #ifdef AGTIAPI_TEST_DPL if(agtiapi_SetupDifPerLA(pCard, pccb, start_lba) < 0) { printk(KERN_ERR "SetupDifPerLA Failed.\n"); cmnd->result = SCSI_HOST(DID_ERROR); goto err; } pccb->tiSuperScsiRequest.Dif.enableDIFPerLA = TRUE; #endif #ifdef AGTIAPI_TEST_DIF /* Set App Tag */ pccb->tiSuperScsiRequest.Dif.udtArray[0] = 0xaa; pccb->tiSuperScsiRequest.Dif.udtArray[1] = 0xbb; /* Set LBA in UDT array */ if(CDB[0] == READ_6) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[3]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[2]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[1] & 0x1f; pccb->tiSuperScsiRequest.Dif.udtArray[5] = 0; } else if(CDB[0] == READ_10 || CDB[0] == READ_12) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[5]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[4]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[3]; pccb->tiSuperScsiRequest.Dif.udtArray[5] = CDB[2]; } else if(CDB[0] == READ_16) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[9]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[8]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[7]; pccb->tiSuperScsiRequest.Dif.udtArray[5] = CDB[6]; /* Note: 32 bits lost */ } #endif break; case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: // BUG_ON(pccb->tiSuperScsiRequest.flags & TI_SCSI_INITIATOR_ENCRYPT); pccb->flags |= EDC_DATA; #ifdef AGTIAPI_TEST_DIF pccb->tiSuperScsiRequest.flags |= TI_SCSI_INITIATOR_DIF; pccb->tiSuperScsiRequest.Dif.flags = DIF_INSERT | DIF_UDT_REF_BLOCK_COUNT; switch(pDev->sector_size) { case 528: pccb->tiSuperScsiRequest.Dif.flags |= (DIF_BLOCK_SIZE_520 << 16); break; case 4104: pccb->tiSuperScsiRequest.Dif.flags |= ( DIF_BLOCK_SIZE_4096 << 16 ); break; case 4168: pccb->tiSuperScsiRequest.Dif.flags |= ( DIF_BLOCK_SIZE_4160 << 16 ); break; } /* Turn on upper 4 bits of UUM */ pccb->tiSuperScsiRequest.Dif.flags |= 0xf0000000; #endif #ifdef AGTIAPI_TEST_DPL if(agtiapi_SetupDifPerLA(pCard, pccb, start_lba) < 0) { printk(KERN_ERR "SetupDifPerLA Failed.\n"); cmnd->result = SCSI_HOST(DID_ERROR); goto err; } pccb->tiSuperScsiRequest.Dif.enableDIFPerLA = TRUE; #endif #ifdef AGTIAPI_TEST_DIF /* Set App Tag */ pccb->tiSuperScsiRequest.Dif.udtArray[0] = 0xaa; pccb->tiSuperScsiRequest.Dif.udtArray[1] = 0xbb; /* Set LBA in UDT array */ if(CDB[0] == WRITE_6) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[3]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[2]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[1] & 0x1f; } else if(CDB[0] == WRITE_10 || CDB[0] == WRITE_12) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[5]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[4]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[3]; pccb->tiSuperScsiRequest.Dif.udtArray[5] = CDB[2]; } else if(CDB[0] == WRITE_16) { pccb->tiSuperScsiRequest.Dif.udtArray[2] = CDB[5]; pccb->tiSuperScsiRequest.Dif.udtArray[3] = CDB[4]; pccb->tiSuperScsiRequest.Dif.udtArray[4] = CDB[3]; pccb->tiSuperScsiRequest.Dif.udtArray[5] = CDB[2]; /* Note: 32 bits lost */ } #endif break; } } #endif /* end of DIF */ if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) { switch(csio->tag_action) { case MSG_HEAD_OF_Q_TAG: pScsiCmnd->taskAttribute = TASK_HEAD_OF_QUEUE; break; case MSG_ACA_TASK: pScsiCmnd->taskAttribute = TASK_ACA; break; case MSG_ORDERED_Q_TAG: pScsiCmnd->taskAttribute = TASK_ORDERED; break; case MSG_SIMPLE_Q_TAG: /* fall through */ default: pScsiCmnd->taskAttribute = TASK_SIMPLE; break; } } if (pccb->tiSuperScsiRequest.agSgl1.len != 0 && pccb->dataLen != 0) { /* should be just before start IO */ bus_dmamap_sync(pmcsc->buffer_dmat, pccb->CCB_dmamap, op); } /* * If assigned pDevHandle is not available * then there is no need to send it to StartIO() */ if (pccb->targetId < 0 || pccb->targetId >= maxTargets) { pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_FreeCCB(pmcsc, pccb); ccb->ccb_h.status = CAM_DEV_NOT_THERE; // ## v. CAM_FUNC_NOTAVAIL xpt_done(ccb); pccb->ccb = NULL; return; } TID = INDEX(pmcsc, pccb->targetId); if ((TID >= pmcsc->devDiscover) || !(pccb->devHandle = pmcsc->pDevList[TID].pDevHandle)) { /* AGTIAPI_PRINTK( "agtiapi_PrepareSGListCB: not sending ccb devH %p," " target %d tid %d/%d card %p ERROR pccb %p\n", pccb->devHandle, pccb->targetId, TID, pmcsc->devDiscover, pmcsc, pccb ); */ pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_FreeCCB(pmcsc, pccb); ccb->ccb_h.status = CAM_DEV_NOT_THERE; // ## v. CAM_FUNC_NOTAVAIL xpt_done(ccb); pccb->ccb = NULL; return; } AGTIAPI_IO( "agtiapi_PrepareSGListCB: send ccb pccb->devHandle %p, " "pccb->targetId %d TID %d pmcsc->devDiscover %d card %p\n", pccb->devHandle, pccb->targetId, TID, pmcsc->devDiscover, pmcsc ); #ifdef HIALEAH_ENCRYPTION if(pmcsc->encrypt && io_is_encryptable) { agtiapi_SetupEncryptedIO(pmcsc, pccb, start_lba); } else{ io_is_encryptable = 0; pccb->tiSuperScsiRequest.flags = 0; } #endif // put the request in send queue agtiapi_QueueCCB( pmcsc, &pmcsc->ccbSendHead, &pmcsc->ccbSendTail AG_CARD_LOCAL_LOCK(&pmcsc->sendLock), pccb ); agtiapi_StartIO(pmcsc); return; } /****************************************************************************** agtiapi_StartIO() Purpose: Send IO request down for processing. Parameters: (struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure Return: Note: ******************************************************************************/ STATIC void agtiapi_StartIO( struct agtiapi_softc *pmcsc ) { ccb_t *pccb; int TID; ag_device_t *targ; AGTIAPI_IO( "agtiapi_StartIO: start\n" ); AG_LOCAL_LOCK( &pmcsc->sendLock ); pccb = pmcsc->ccbSendHead; /* if link is down, do nothing */ if ((pccb == NULL) || pmcsc->flags & AGTIAPI_RESET) { AG_LOCAL_UNLOCK( &pmcsc->sendLock ); AGTIAPI_PRINTK( "agtiapi_StartIO: goto ext\n" ); goto ext; } if (pmcsc != NULL && pccb->targetId >= 0 && pccb->targetId < maxTargets) { TID = INDEX(pmcsc, pccb->targetId); targ = &pmcsc->pDevList[TID]; } /* clear send queue */ pmcsc->ccbSendHead = NULL; pmcsc->ccbSendTail = NULL; AG_LOCAL_UNLOCK( &pmcsc->sendLock ); /* send all ccbs down */ while (pccb) { pccb_t pccb_next; U32 status; pccb_next = pccb->pccbNext; pccb->pccbNext = NULL; if (!pccb->ccb) { AGTIAPI_PRINTK( "agtiapi_StartIO: pccb->ccb is NULL ERROR!\n" ); pccb = pccb_next; continue; } AG_IO_DUMPCCB( pccb ); if (!pccb->devHandle) { agtiapi_DumpCCB( pccb ); AGTIAPI_PRINTK( "agtiapi_StartIO: ccb NULL device ERROR!\n" ); pccb = pccb_next; continue; } AGTIAPI_IO( "agtiapi_StartIO: ccb %p retry %d\n", pccb, pccb->retryCount ); #ifndef ABORT_TEST if( !pccb->devHandle || !pccb->devHandle->osData || /* in rmmod case */ !(((ag_device_t *)(pccb->devHandle->osData))->flags & ACTIVE)) { AGTIAPI_PRINTK( "agtiapi_StartIO: device %p not active! ERROR\n", pccb->devHandle ); if( pccb->devHandle ) { AGTIAPI_PRINTK( "agtiapi_StartIO: device not active detail" " -- osData:%p\n", pccb->devHandle->osData ); if( pccb->devHandle->osData ) { AGTIAPI_PRINTK( "agtiapi_StartIO: more device not active detail" " -- active flag:%d\n", ( (ag_device_t *) (pccb->devHandle->osData))->flags & ACTIVE ); } } pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_Done( pmcsc, pccb ); pccb = pccb_next; continue; } #endif #ifdef FAST_IO_TEST status = agtiapi_FastIOTest( pmcsc, pccb ); #else status = tiINISuperIOStart( &pmcsc->tiRoot, &pccb->tiIORequest, pccb->devHandle, &pccb->tiSuperScsiRequest, (void *)&pccb->tdIOReqBody, tiInterruptContext ); #endif switch( status ) { case tiSuccess: /* static int squelchCount = 0; if ( 200000 == squelchCount++ ) // squelch prints { AGTIAPI_PRINTK( "agtiapi_StartIO: tiINIIOStart stat tiSuccess %p\n", pccb ); squelchCount = 0; // reset count } */ break; case tiDeviceBusy: AGTIAPI_PRINTK( "agtiapi_StartIO: tiINIIOStart status tiDeviceBusy %p\n", pccb->ccb ); #ifdef LOGEVENT agtiapi_LogEvent( pmcsc, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "tiINIIOStart tiDeviceBusy " ); #endif pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDeviceBusy; agtiapi_Done(pmcsc, pccb); break; case tiBusy: AGTIAPI_PRINTK( "agtiapi_StartIO: tiINIIOStart status tiBusy %p\n", pccb->ccb ); #ifdef LOGEVENT agtiapi_LogEvent( pmcsc, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "tiINIIOStart tiBusy " ); #endif pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiBusy; agtiapi_Done(pmcsc, pccb); break; case tiIONoDevice: AGTIAPI_PRINTK( "agtiapi_StartIO: tiINIIOStart status tiNoDevice %p " "ERROR\n", pccb->ccb ); #ifdef LOGEVENT agtiapi_LogEvent( pmcsc, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "tiINIIOStart invalid device handle " ); #endif #ifndef ABORT_TEST /* return command back to OS due to no device available */ ((ag_device_t *)(pccb->devHandle->osData))->flags &= ~ACTIVE; pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailNoLogin; agtiapi_Done(pmcsc, pccb); #else /* for short cable pull, we want IO retried - 3-18-2005 */ agtiapi_QueueCCB(pmcsc, &pmcsc->ccbSendHead, &pmcsc->ccbSendTail AG_CARD_LOCAL_LOCK(&pmcsc->sendLock), pccb); #endif break; case tiError: AGTIAPI_PRINTK("agtiapi_StartIO: tiINIIOStart status tiError %p\n", pccb->ccb); #ifdef LOGEVENT agtiapi_LogEvent(pmcsc, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "tiINIIOStart tiError "); #endif pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailOtherError; agtiapi_Done(pmcsc, pccb); break; default: AGTIAPI_PRINTK("agtiapi_StartIO: tiINIIOStart status default %x %p\n", status, pccb->ccb); #ifdef LOGEVENT agtiapi_LogEvent(pmcsc, IOCTL_EVT_SEV_ERROR, 0, agNULL, 0, "tiINIIOStart unexpected status "); #endif pccb->ccbStatus = tiIOFailed; pccb->scsiStatus = tiDetailOtherError; agtiapi_Done(pmcsc, pccb); } pccb = pccb_next; } ext: /* some IO requests might have been completed */ AG_GET_DONE_PCCB(pccb, pmcsc); return; } /****************************************************************************** agtiapi_StartSMP() Purpose: Send SMP request down for processing. Parameters: (struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure Return: Note: ******************************************************************************/ STATIC void agtiapi_StartSMP(struct agtiapi_softc *pmcsc) { ccb_t *pccb; AGTIAPI_PRINTK("agtiapi_StartSMP: start\n"); AG_LOCAL_LOCK(&pmcsc->sendSMPLock); pccb = pmcsc->smpSendHead; /* if link is down, do nothing */ if ((pccb == NULL) || pmcsc->flags & AGTIAPI_RESET) { AG_LOCAL_UNLOCK(&pmcsc->sendSMPLock); AGTIAPI_PRINTK("agtiapi_StartSMP: goto ext\n"); goto ext; } /* clear send queue */ pmcsc->smpSendHead = NULL; pmcsc->smpSendTail = NULL; AG_LOCAL_UNLOCK(&pmcsc->sendSMPLock); /* send all ccbs down */ while (pccb) { pccb_t pccb_next; U32 status; pccb_next = pccb->pccbNext; pccb->pccbNext = NULL; if (!pccb->ccb) { AGTIAPI_PRINTK("agtiapi_StartSMP: pccb->ccb is NULL ERROR!\n"); pccb = pccb_next; continue; } if (!pccb->devHandle) { AGTIAPI_PRINTK("agtiapi_StartSMP: ccb NULL device ERROR!\n"); pccb = pccb_next; continue; } pccb->flags |= TAG_SMP; // mark as SMP for later tracking AGTIAPI_PRINTK( "agtiapi_StartSMP: ccb %p retry %d\n", pccb, pccb->retryCount ); status = tiINISMPStart( &pmcsc->tiRoot, &pccb->tiIORequest, pccb->devHandle, &pccb->tiSMPFrame, (void *)&pccb->tdIOReqBody, tiInterruptContext); switch (status) { case tiSuccess: break; case tiBusy: AGTIAPI_PRINTK("agtiapi_StartSMP: tiINISMPStart status tiBusy %p\n", pccb->ccb); /* pending ccb back to send queue */ agtiapi_QueueCCB(pmcsc, &pmcsc->smpSendHead, &pmcsc->smpSendTail AG_CARD_LOCAL_LOCK(&pmcsc->sendSMPLock), pccb); break; case tiError: AGTIAPI_PRINTK("agtiapi_StartIO: tiINIIOStart status tiError %p\n", pccb->ccb); pccb->ccbStatus = tiSMPFailed; agtiapi_SMPDone(pmcsc, pccb); break; default: AGTIAPI_PRINTK("agtiapi_StartIO: tiINIIOStart status default %x %p\n", status, pccb->ccb); pccb->ccbStatus = tiSMPFailed; agtiapi_SMPDone(pmcsc, pccb); } pccb = pccb_next; } ext: /* some SMP requests might have been completed */ AG_GET_DONE_SMP_PCCB(pccb, pmcsc); return; } #if __FreeBSD_version > 901000 /****************************************************************************** agtiapi_PrepareSMPSGList() Purpose: This function prepares scatter-gather list for the given ccb Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - success 1 - failure Note: ******************************************************************************/ static int agtiapi_PrepareSMPSGList( struct agtiapi_softc *pmcsc, ccb_t *pccb ) { /* Pointer to CAM's ccb */ union ccb *ccb = pccb->ccb; struct ccb_smpio *csmpio = &ccb->smpio; struct ccb_hdr *ccbh = &ccb->ccb_h; AGTIAPI_PRINTK("agtiapi_PrepareSMPSGList: start\n"); switch((ccbh->flags & CAM_DATA_MASK)) { case CAM_DATA_PADDR: case CAM_DATA_SG_PADDR: AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: Physical Address not supported\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return tiReject; case CAM_DATA_SG: /* * Currently we do not support Multiple SG list * return error for now */ if ( (csmpio->smp_request_sglist_cnt > 1) || (csmpio->smp_response_sglist_cnt > 1) ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: Multiple SG list not supported\n"); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return tiReject; } } if ( csmpio->smp_request_sglist_cnt != 0 ) { /* * Virtual address that needs to translated into * one or more physical address ranges. */ int error; //AG_LOCAL_LOCK(&(pmcsc->pCardInfo->pmIOLock)); AGTIAPI_PRINTK("agtiapi_PrepareSGList: virtual address\n"); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csmpio->smp_request, csmpio->smp_request_len, agtiapi_PrepareSMPSGListCB, pccb, BUS_DMA_NOWAIT /* 0 */ ); //AG_LOCAL_UNLOCK(&(pmcsc->pCardInfo->pmIOLock)); if (error == EINPROGRESS) { /* * So as to maintain ordering, * freeze the controller queue * until our mapping is * returned. */ AGTIAPI_PRINTK( "agtiapi_PrepareSGList: EINPROGRESS\n" ); xpt_freeze_simq( pmcsc->sim, 1 ); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } } if( csmpio->smp_response_sglist_cnt != 0 ) { /* * Virtual address that needs to translated into * one or more physical address ranges. */ int error; //AG_LOCAL_LOCK( &(pmcsc->pCardInfo->pmIOLock) ); AGTIAPI_PRINTK( "agtiapi_PrepareSGList: virtual address\n" ); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csmpio->smp_response, csmpio->smp_response_len, agtiapi_PrepareSMPSGListCB, pccb, BUS_DMA_NOWAIT /* 0 */ ); //AG_LOCAL_UNLOCK( &(pmcsc->pCardInfo->pmIOLock) ); if ( error == EINPROGRESS ) { /* * So as to maintain ordering, * freeze the controller queue * until our mapping is * returned. */ AGTIAPI_PRINTK( "agtiapi_PrepareSGList: EINPROGRESS\n" ); xpt_freeze_simq( pmcsc->sim, 1 ); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } } else { if ( (csmpio->smp_request_sglist_cnt == 0) && (csmpio->smp_response_sglist_cnt == 0) ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: physical address\n" ); pccb->tiSMPFrame.outFrameBuf = (void *)csmpio->smp_request; pccb->tiSMPFrame.outFrameLen = csmpio->smp_request_len; pccb->tiSMPFrame.expectedRespLen = csmpio->smp_response_len; // 0xFF to be defined agtiapi_PrepareSMPSGListCB( pccb, NULL, 0, 0xAABBCCDD ); } pccb->tiSMPFrame.flag = 0; } return tiSuccess; } #else /****************************************************************************** agtiapi_PrepareSMPSGList() Purpose: This function prepares scatter-gather list for the given ccb Parameters: struct agtiapi_softc *pmsc (IN) Pointer to the HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - success 1 - failure Note: ******************************************************************************/ static int agtiapi_PrepareSMPSGList( struct agtiapi_softc *pmcsc, ccb_t *pccb ) { /* Pointer to CAM's ccb */ union ccb *ccb = pccb->ccb; struct ccb_smpio *csmpio = &ccb->smpio; struct ccb_hdr *ccbh = &ccb->ccb_h; AGTIAPI_PRINTK("agtiapi_PrepareSMPSGList: start\n"); if (ccbh->flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: Physical Address " "not supported\n" ); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return tiReject; } if (ccbh->flags & CAM_SCATTER_VALID) { /* * Currently we do not support Multiple SG list * return error for now */ if ( (csmpio->smp_request_sglist_cnt > 1) || (csmpio->smp_response_sglist_cnt > 1) ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: Multiple SG list " "not supported\n" ); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); return tiReject; } if ( csmpio->smp_request_sglist_cnt != 0 ) { /* * Virtual address that needs to translated into * one or more physical address ranges. */ int error; //AG_LOCAL_LOCK(&(pmcsc->pCardInfo->pmIOLock)); AGTIAPI_PRINTK("agtiapi_PrepareSGList: virtual address\n"); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csmpio->smp_request, csmpio->smp_request_len, agtiapi_PrepareSMPSGListCB, pccb, BUS_DMA_NOWAIT /* 0 */ ); //AG_LOCAL_UNLOCK(&(pmcsc->pCardInfo->pmIOLock)); if (error == EINPROGRESS) { /* * So as to maintain ordering, * freeze the controller queue * until our mapping is * returned. */ AGTIAPI_PRINTK( "agtiapi_PrepareSGList: EINPROGRESS\n" ); xpt_freeze_simq( pmcsc->sim, 1 ); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } } if( csmpio->smp_response_sglist_cnt != 0 ) { /* * Virtual address that needs to translated into * one or more physical address ranges. */ int error; //AG_LOCAL_LOCK( &(pmcsc->pCardInfo->pmIOLock) ); AGTIAPI_PRINTK( "agtiapi_PrepareSGList: virtual address\n" ); error = bus_dmamap_load( pmcsc->buffer_dmat, pccb->CCB_dmamap, csmpio->smp_response, csmpio->smp_response_len, agtiapi_PrepareSMPSGListCB, pccb, BUS_DMA_NOWAIT /* 0 */ ); //AG_LOCAL_UNLOCK( &(pmcsc->pCardInfo->pmIOLock) ); if ( error == EINPROGRESS ) { /* * So as to maintain ordering, * freeze the controller queue * until our mapping is * returned. */ AGTIAPI_PRINTK( "agtiapi_PrepareSGList: EINPROGRESS\n" ); xpt_freeze_simq( pmcsc->sim, 1 ); pmcsc->SimQFrozen = agTRUE; ccbh->status |= CAM_RELEASE_SIMQ; } } } else { if ( (csmpio->smp_request_sglist_cnt == 0) && (csmpio->smp_response_sglist_cnt == 0) ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGList: physical address\n" ); pccb->tiSMPFrame.outFrameBuf = (void *)csmpio->smp_request; pccb->tiSMPFrame.outFrameLen = csmpio->smp_request_len; pccb->tiSMPFrame.expectedRespLen = csmpio->smp_response_len; // 0xFF to be defined agtiapi_PrepareSMPSGListCB( pccb, NULL, 0, 0xAABBCCDD ); } pccb->tiSMPFrame.flag = 0; } return tiSuccess; } #endif /****************************************************************************** agtiapi_PrepareSMPSGListCB() Purpose: Callback function for bus_dmamap_load() This fuctions sends IO to LL layer. Parameters: void *arg (IN) Pointer to the HBA data structure bus_dma_segment_t *segs (IN) Pointer to dma segment int nsegs (IN) number of dma segment int error (IN) error Return: Note: ******************************************************************************/ static void agtiapi_PrepareSMPSGListCB( void *arg, bus_dma_segment_t *segs, int nsegs, int error ) { pccb_t pccb = arg; union ccb *ccb = pccb->ccb; struct agtiapi_softc *pmcsc; U32 TID = CMND_TO_TARGET(ccb); int status; tiDeviceHandle_t *tiExpDevHandle; tiPortalContext_t *tiExpPortalContext; ag_portal_info_t *tiExpPortalInfo; AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: start, nsegs %d error 0x%x\n", nsegs, error ); pmcsc = pccb->pmcsc; if ( error != tiSuccess ) { if (error == 0xAABBCCDD) { // do nothing } else { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: error status 0x%x\n", error ); bus_dmamap_unload( pmcsc->buffer_dmat, pccb->CCB_dmamap ); agtiapi_FreeCCB( pmcsc, pccb ); if (error == EFBIG) ccb->ccb_h.status = CAM_REQ_TOO_BIG; else ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done( ccb ); return; } } if ( nsegs > AGTIAPI_MAX_DMA_SEGS ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: over the limit. nsegs %d " "AGTIAPI_MAX_DMA_SEGS %d\n", nsegs, AGTIAPI_MAX_DMA_SEGS ); bus_dmamap_unload( pmcsc->buffer_dmat, pccb->CCB_dmamap ); agtiapi_FreeCCB( pmcsc, pccb ); ccb->ccb_h.status = CAM_REQ_TOO_BIG; xpt_done( ccb ); return; } /* * If assigned pDevHandle is not available * then there is no need to send it to StartIO() */ /* TODO: Add check for deviceType */ if ( pccb->targetId < 0 || pccb->targetId >= maxTargets ) { agtiapi_FreeCCB( pmcsc, pccb ); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; xpt_done(ccb); pccb->ccb = NULL; return; } TID = INDEX( pmcsc, pccb->targetId ); if ( (TID >= pmcsc->devDiscover) || !(pccb->devHandle = pmcsc->pDevList[TID].pDevHandle) ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: not sending ccb devH %p, " "target %d tid %d/%d " "card %p ERROR pccb %p\n", pccb->devHandle, pccb->targetId, TID, pmcsc->devDiscover, pmcsc, pccb ); agtiapi_FreeCCB( pmcsc, pccb ); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; xpt_done( ccb ); pccb->ccb = NULL; return; } /* TODO: add indirect handling */ /* set the flag correctly based on Indiret SMP request and response */ AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: send ccb pccb->devHandle %p, " "pccb->targetId %d TID %d pmcsc->devDiscover %d card %p\n", pccb->devHandle, pccb->targetId, TID, pmcsc->devDiscover, pmcsc ); tiExpDevHandle = pccb->devHandle; tiExpPortalInfo = pmcsc->pDevList[TID].pPortalInfo; tiExpPortalContext = &tiExpPortalInfo->tiPortalContext; /* Look for the expander associated with the ses device */ status = tiINIGetExpander( &pmcsc->tiRoot, tiExpPortalContext, pccb->devHandle, &tiExpDevHandle ); if ( status != tiSuccess ) { AGTIAPI_PRINTK( "agtiapi_PrepareSMPSGListCB: Error getting Expander " "device\n" ); agtiapi_FreeCCB( pmcsc, pccb ); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; xpt_done( ccb ); pccb->ccb = NULL; return; } /* this is expander device */ pccb->devHandle = tiExpDevHandle; /* put the request in send queue */ agtiapi_QueueCCB( pmcsc, &pmcsc->smpSendHead, &pmcsc->smpSendTail AG_CARD_LOCAL_LOCK(&pmcsc->sendSMPLock), pccb ); agtiapi_StartSMP( pmcsc ); return; } /****************************************************************************** agtiapi_Done() Purpose: Processing completed ccbs Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: ******************************************************************************/ STATIC void agtiapi_Done(struct agtiapi_softc *pmcsc, ccb_t *pccb) { pccb_t pccb_curr = pccb; pccb_t pccb_next; tiIniScsiCmnd_t *cmnd; union ccb * ccb; AGTIAPI_IO("agtiapi_Done: start\n"); while (pccb_curr) { /* start from 1st ccb in the chain */ pccb_next = pccb_curr->pccbNext; if (agtiapi_CheckError(pmcsc, pccb_curr) != 0) { /* send command back and release the ccb */ cmnd = &pccb_curr->tiSuperScsiRequest.scsiCmnd; if (cmnd->cdb[0] == RECEIVE_DIAGNOSTIC) { AGTIAPI_PRINTK("agtiapi_Done: RECEIVE_DIAG pg %d id %d cmnd %p pccb " "%p\n", cmnd->cdb[2], pccb_curr->targetId, cmnd, pccb_curr); } CMND_DMA_UNMAP(pmcsc, ccb); /* send the request back to the CAM */ ccb = pccb_curr->ccb; agtiapi_FreeCCB(pmcsc, pccb_curr); xpt_done(ccb); } pccb_curr = pccb_next; } return; } /****************************************************************************** agtiapi_SMPDone() Purpose: Processing completed ccbs Parameters: struct agtiapi_softc *pmcsc (IN) Ponter to HBA data structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: ******************************************************************************/ STATIC void agtiapi_SMPDone(struct agtiapi_softc *pmcsc, ccb_t *pccb) { pccb_t pccb_curr = pccb; pccb_t pccb_next; union ccb * ccb; AGTIAPI_PRINTK("agtiapi_SMPDone: start\n"); while (pccb_curr) { /* start from 1st ccb in the chain */ pccb_next = pccb_curr->pccbNext; if (agtiapi_CheckSMPError(pmcsc, pccb_curr) != 0) { CMND_DMA_UNMAP(pmcsc, ccb); /* send the request back to the CAM */ ccb = pccb_curr->ccb; agtiapi_FreeSMPCCB(pmcsc, pccb_curr); xpt_done(ccb); } pccb_curr = pccb_next; } AGTIAPI_PRINTK("agtiapi_SMPDone: Done\n"); return; } /****************************************************************************** agtiapi_hexdump() Purpose: Utility function for dumping in hex Parameters: const char *ptitle (IN) A string to be printed bit8 *pbuf (IN) A pointer to a buffer to be printed. int len (IN) The lengther of the buffer Return: Note: ******************************************************************************/ void agtiapi_hexdump(const char *ptitle, bit8 *pbuf, int len) { int i; AGTIAPI_PRINTK("%s - hexdump(len=%d):\n", ptitle, (int)len); if (!pbuf) { AGTIAPI_PRINTK("pbuf is NULL\n"); return; } for (i = 0; i < len; ) { if (len - i > 4) { AGTIAPI_PRINTK( " 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", pbuf[i], pbuf[i+1], pbuf[i+2], pbuf[i+3] ); i += 4; } else { AGTIAPI_PRINTK(" 0x%02x,", pbuf[i]); i++; } } AGTIAPI_PRINTK("\n"); } /****************************************************************************** agtiapi_CheckError() Purpose: Processes status pertaining to the ccb -- whether it was completed successfully, aborted, or error encountered. Parameters: ag_card_t *pCard (IN) Pointer to HBA data structure ccb_t *pccd (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - the command retry is required 1 - the command process is completed Note: ******************************************************************************/ STATIC U32 agtiapi_CheckError(struct agtiapi_softc *pmcsc, ccb_t *pccb) { ag_device_t *pDevice; // union ccb * ccb = pccb->ccb; union ccb * ccb; int is_error, TID; if (pccb == NULL) { return 0; } ccb = pccb->ccb; AGTIAPI_IO("agtiapi_CheckError: start\n"); if (ccb == NULL) { /* shouldn't be here but just in case we do */ AGTIAPI_PRINTK("agtiapi_CheckError: CCB orphan = %p ERROR\n", pccb); agtiapi_FreeCCB(pmcsc, pccb); return 0; } is_error = 1; pDevice = NULL; if (pmcsc != NULL && pccb->targetId >= 0 && pccb->targetId < maxTargets) { if (pmcsc->pWWNList != NULL) { TID = INDEX(pmcsc, pccb->targetId); if (TID < maxTargets) { pDevice = &pmcsc->pDevList[TID]; if (pDevice != NULL) { is_error = 0; } } } } if (is_error) { AGTIAPI_PRINTK("agtiapi_CheckError: pDevice == NULL\n"); agtiapi_FreeCCB(pmcsc, pccb); return 0; } /* SCSI status */ ccb->csio.scsi_status = pccb->scsiStatus; if(pDevice->CCBCount > 0){ atomic_subtract_int(&pDevice->CCBCount,1); } AG_LOCAL_LOCK(&pmcsc->freezeLock); if(pmcsc->freezeSim == agTRUE) { pmcsc->freezeSim = agFALSE; xpt_release_simq(pmcsc->sim, 1); } AG_LOCAL_UNLOCK(&pmcsc->freezeLock); switch (pccb->ccbStatus) { case tiIOSuccess: AGTIAPI_IO("agtiapi_CheckError: tiIOSuccess pccb %p\n", pccb); /* CAM status */ if (pccb->scsiStatus == SCSI_STATUS_OK) { ccb->ccb_h.status = CAM_REQ_CMP; } else if (pccb->scsiStatus == SCSI_TASK_ABORTED) { ccb->ccb_h.status = CAM_REQ_ABORTED; } else { ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; } if (ccb->csio.scsi_status == SCSI_CHECK_CONDITION) { ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } break; case tiIOOverRun: AGTIAPI_PRINTK("agtiapi_CheckError: tiIOOverRun pccb %p\n", pccb); /* resid is ignored for this condition */ ccb->csio.resid = 0; ccb->ccb_h.status = CAM_DATA_RUN_ERR; break; case tiIOUnderRun: AGTIAPI_PRINTK("agtiapi_CheckError: tiIOUnderRun pccb %p\n", pccb); ccb->csio.resid = pccb->scsiStatus; ccb->ccb_h.status = CAM_REQ_CMP; ccb->csio.scsi_status = SCSI_STATUS_OK; break; case tiIOFailed: AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed %d id %d ERROR\n", pccb, pccb->scsiStatus, pccb->targetId ); if (pccb->scsiStatus == tiDeviceBusy) { AGTIAPI_IO( "agtiapi_CheckError: pccb %p tiIOFailed - tiDetailBusy\n", pccb ); ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; if ((ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, /*count*/1); } } else if(pccb->scsiStatus == tiBusy) { AG_LOCAL_LOCK(&pmcsc->freezeLock); if(pmcsc->freezeSim == agFALSE) { pmcsc->freezeSim = agTRUE; xpt_freeze_simq(pmcsc->sim, 1); } AG_LOCAL_UNLOCK(&pmcsc->freezeLock); ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status |= CAM_REQUEUE_REQ; } else if (pccb->scsiStatus == tiDetailNoLogin) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailNoLogin ERROR\n", pccb ); ccb->ccb_h.status = CAM_DEV_NOT_THERE; } else if (pccb->scsiStatus == tiDetailNotValid) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailNotValid ERROR\n", pccb ); ccb->ccb_h.status = CAM_REQ_INVALID; } else if (pccb->scsiStatus == tiDetailAbortLogin) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailAbortLogin ERROR\n", pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; } else if (pccb->scsiStatus == tiDetailAbortReset) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailAbortReset ERROR\n", pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; } else if (pccb->scsiStatus == tiDetailAborted) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailAborted ERROR\n", pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; } else if (pccb->scsiStatus == tiDetailOtherError) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailOtherError ERROR\n", pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; } break; case tiIODifError: AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed %d id %d ERROR\n", pccb, pccb->scsiStatus, pccb->targetId ); if (pccb->scsiStatus == tiDetailDifAppTagMismatch) { AGTIAPI_IO( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailDifAppTagMismatch\n", pccb ); ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else if (pccb->scsiStatus == tiDetailDifRefTagMismatch) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailDifRefTagMismatch\n", pccb ); ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else if (pccb->scsiStatus == tiDetailDifCrcMismatch) { AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed - " "tiDetailDifCrcMismatch\n", pccb ); ccb->ccb_h.status = CAM_REQ_CMP_ERR; } break; #ifdef HIALEAH_ENCRYPTION case tiIOEncryptError: AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOFailed %d id %d ERROR\n", pccb, pccb->scsiStatus, pccb->targetId ); if (pccb->scsiStatus == tiDetailDekKeyCacheMiss) { AGTIAPI_PRINTK( "agtiapi_CheckError: %s: pccb %p tiIOFailed - " "tiDetailDekKeyCacheMiss ERROR\n", __FUNCTION__, pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; agtiapi_HandleEncryptedIOFailure(pDevice, pccb); } else if (pccb->scsiStatus == tiDetailDekIVMismatch) { AGTIAPI_PRINTK( "agtiapi_CheckError: %s: pccb %p tiIOFailed - " "tiDetailDekIVMismatch ERROR\n", __FUNCTION__, pccb ); ccb->ccb_h.status = CAM_REQ_ABORTED; agtiapi_HandleEncryptedIOFailure(pDevice, pccb); } break; #endif default: AGTIAPI_PRINTK( "agtiapi_CheckError: pccb %p tiIOdefault %d id %d ERROR\n", pccb, pccb->ccbStatus, pccb->targetId ); ccb->ccb_h.status = CAM_REQ_CMP_ERR; break; } return 1; } /****************************************************************************** agtiapi_SMPCheckError() Purpose: Processes status pertaining to the ccb -- whether it was completed successfully, aborted, or error encountered. Parameters: ag_card_t *pCard (IN) Pointer to HBA data structure ccb_t *pccd (IN) A pointer to the driver's own CCB, not CAM's CCB Return: 0 - the command retry is required 1 - the command process is completed Note: ******************************************************************************/ STATIC U32 agtiapi_CheckSMPError( struct agtiapi_softc *pmcsc, ccb_t *pccb ) { union ccb * ccb = pccb->ccb; AGTIAPI_PRINTK("agtiapi_CheckSMPError: start\n"); if (!ccb) { /* shouldn't be here but just in case we do */ AGTIAPI_PRINTK( "agtiapi_CheckSMPError: CCB orphan = %p ERROR\n", pccb ); agtiapi_FreeSMPCCB(pmcsc, pccb); return 0; } switch (pccb->ccbStatus) { case tiSMPSuccess: AGTIAPI_PRINTK( "agtiapi_CheckSMPError: tiSMPSuccess pccb %p\n", pccb ); /* CAM status */ ccb->ccb_h.status = CAM_REQ_CMP; break; case tiSMPFailed: AGTIAPI_PRINTK( "agtiapi_CheckSMPError: tiSMPFailed pccb %p\n", pccb ); /* CAM status */ ccb->ccb_h.status = CAM_REQ_CMP_ERR; break; default: AGTIAPI_PRINTK( "agtiapi_CheckSMPError: pccb %p tiSMPdefault %d " "id %d ERROR\n", pccb, pccb->ccbStatus, pccb->targetId ); ccb->ccb_h.status = CAM_REQ_CMP_ERR; break; } return 1; } /****************************************************************************** agtiapi_HandleEncryptedIOFailure(): Purpose: Parameters: Return: Note: Currently not used. ******************************************************************************/ void agtiapi_HandleEncryptedIOFailure(ag_device_t *pDev, ccb_t *pccb) { AGTIAPI_PRINTK("agtiapi_HandleEncryptedIOFailure: start\n"); return; } /****************************************************************************** agtiapi_Retry() Purpose: Retry a ccb. Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to the HBA structure ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: Currently not used. ******************************************************************************/ STATIC void agtiapi_Retry(struct agtiapi_softc *pmcsc, ccb_t *pccb) { pccb->retryCount++; pccb->flags = ACTIVE | AGTIAPI_RETRY; pccb->ccbStatus = 0; pccb->scsiStatus = 0; pccb->startTime = ticks; AGTIAPI_PRINTK( "agtiapi_Retry: start\n" ); AGTIAPI_PRINTK( "agtiapi_Retry: ccb %p retry %d flgs x%x\n", pccb, pccb->retryCount, pccb->flags ); agtiapi_QueueCCB(pmcsc, &pmcsc->ccbSendHead, &pmcsc->ccbSendTail AG_CARD_LOCAL_LOCK(&pmcsc->sendLock), pccb); return; } /****************************************************************************** agtiapi_DumpCCB() Purpose: Dump CCB for debuging Parameters: ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: ******************************************************************************/ STATIC void agtiapi_DumpCCB(ccb_t *pccb) { AGTIAPI_PRINTK("agtiapi_DumpCCB: pccb %p, devHandle %p, tid %d, lun %d\n", pccb, pccb->devHandle, pccb->targetId, pccb->lun); AGTIAPI_PRINTK("flag 0x%x, add_mode 0x%x, ccbStatus 0x%x, scsiStatus 0x%x\n", pccb->flags, pccb->addrMode, pccb->ccbStatus, pccb->scsiStatus); AGTIAPI_PRINTK("scsi comand = 0x%x, numSgElements = %d\n", pccb->tiSuperScsiRequest.scsiCmnd.cdb[0], pccb->numSgElements); AGTIAPI_PRINTK("dataLen = 0x%x, sens_len = 0x%x\n", pccb->dataLen, pccb->senseLen); AGTIAPI_PRINTK("tiSuperScsiRequest:\n"); AGTIAPI_PRINTK("scsiCmnd: expDataLength 0x%x, taskAttribute 0x%x\n", pccb->tiSuperScsiRequest.scsiCmnd.expDataLength, pccb->tiSuperScsiRequest.scsiCmnd.taskAttribute); AGTIAPI_PRINTK("cdb[0] = 0x%x, cdb[1] = 0x%x, cdb[2] = 0x%x, cdb[3] = 0x%x\n", pccb->tiSuperScsiRequest.scsiCmnd.cdb[0], pccb->tiSuperScsiRequest.scsiCmnd.cdb[1], pccb->tiSuperScsiRequest.scsiCmnd.cdb[2], pccb->tiSuperScsiRequest.scsiCmnd.cdb[3]); AGTIAPI_PRINTK("cdb[4] = 0x%x, cdb[5] = 0x%x, cdb[6] = 0x%x, cdb[7] = 0x%x\n", pccb->tiSuperScsiRequest.scsiCmnd.cdb[4], pccb->tiSuperScsiRequest.scsiCmnd.cdb[5], pccb->tiSuperScsiRequest.scsiCmnd.cdb[6], pccb->tiSuperScsiRequest.scsiCmnd.cdb[7]); AGTIAPI_PRINTK( "cdb[8] = 0x%x, cdb[9] = 0x%x, cdb[10] = 0x%x, " "cdb[11] = 0x%x\n", pccb->tiSuperScsiRequest.scsiCmnd.cdb[8], pccb->tiSuperScsiRequest.scsiCmnd.cdb[9], pccb->tiSuperScsiRequest.scsiCmnd.cdb[10], pccb->tiSuperScsiRequest.scsiCmnd.cdb[11] ); AGTIAPI_PRINTK("agSgl1: upper 0x%x, lower 0x%x, len 0x%x, type %d\n", pccb->tiSuperScsiRequest.agSgl1.upper, pccb->tiSuperScsiRequest.agSgl1.lower, pccb->tiSuperScsiRequest.agSgl1.len, pccb->tiSuperScsiRequest.agSgl1.type); } /****************************************************************************** agtiapi_eh_HostReset() Purpose: A new error handler of Host Reset command. Parameters: scsi_cmnd *cmnd (IN) Pointer to a command to the HBA to be reset Return: SUCCESS - success FAILED - fail Note: ******************************************************************************/ int agtiapi_eh_HostReset( struct agtiapi_softc *pmcsc, union ccb *cmnd ) { AGTIAPI_PRINTK( "agtiapi_eh_HostReset: ccb pointer %p\n", cmnd ); if( cmnd == NULL ) { printf( "agtiapi_eh_HostReset: null command, skipping reset.\n" ); return tiInvalidHandle; } #ifdef LOGEVENT agtiapi_LogEvent( pmcsc, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "agtiapi_eh_HostReset! " ); #endif return agtiapi_DoSoftReset( pmcsc ); } /****************************************************************************** agtiapi_QueueCCB() Purpose: Put ccb in ccb queue at the tail Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure pccb_t *phead (IN) Double pointer to ccb queue head pccb_t *ptail (IN) Double pointer to ccb queue tail ccb_t *pccb (IN) Poiner to a ccb to be queued Return: Note: Put the ccb to the tail of queue ******************************************************************************/ STATIC void agtiapi_QueueCCB( struct agtiapi_softc *pmcsc, pccb_t *phead, pccb_t *ptail, #ifdef AGTIAPI_LOCAL_LOCK struct mtx *mutex, #endif ccb_t *pccb ) { AGTIAPI_IO( "agtiapi_QueueCCB: start\n" ); AGTIAPI_IO( "agtiapi_QueueCCB: %p to %p\n", pccb, phead ); if (phead == NULL || ptail == NULL) { panic( "agtiapi_QueueCCB: phead %p ptail %p", phead, ptail ); } pccb->pccbNext = NULL; AG_LOCAL_LOCK( mutex ); if (*phead == NULL) { //WARN_ON(*ptail != NULL); /* critical, just get more logs */ *phead = pccb; } else { //WARN_ON(*ptail == NULL); /* critical, just get more logs */ if (*ptail) (*ptail)->pccbNext = pccb; } *ptail = pccb; AG_LOCAL_UNLOCK( mutex ); return; } /****************************************************************************** agtiapi_QueueCCB() Purpose: Parameters: Return: Note: ******************************************************************************/ static int agtiapi_QueueSMP(struct agtiapi_softc *pmcsc, union ccb * ccb) { pccb_t pccb = agNULL; /* call dequeue */ int status = tiSuccess; int targetID = xpt_path_target_id(ccb->ccb_h.path); AGTIAPI_PRINTK("agtiapi_QueueSMP: start\n"); /* get a ccb */ if ((pccb = agtiapi_GetCCB(pmcsc)) == NULL) { AGTIAPI_PRINTK("agtiapi_QueueSMP: GetCCB ERROR\n"); ccb->ccb_h.status = CAM_REQ_CMP_ERR; xpt_done(ccb); return tiBusy; } pccb->pmcsc = pmcsc; /* initialize Command Control Block (CCB) */ pccb->targetId = targetID; pccb->ccb = ccb; /* for struct scsi_cmnd */ status = agtiapi_PrepareSMPSGList(pmcsc, pccb); if (status != tiSuccess) { AGTIAPI_PRINTK("agtiapi_QueueSMP: agtiapi_PrepareSMPSGList failure\n"); agtiapi_FreeCCB(pmcsc, pccb); if (status == tiReject) { ccb->ccb_h.status = CAM_REQ_INVALID; } else { ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); return tiError; } return status; } /****************************************************************************** agtiapi_SetLunField() Purpose: Set LUN field based on different address mode Parameters: ccb_t *pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Return: Note: ******************************************************************************/ void agtiapi_SetLunField(ccb_t *pccb) { U08 *pchar; pchar = (U08 *)&pccb->tiSuperScsiRequest.scsiCmnd.lun; // AGTIAPI_PRINTK("agtiapi_SetLunField: start\n"); switch (pccb->addrMode) { case AGTIAPI_PERIPHERAL: *pchar++ = 0; *pchar = (U08)pccb->lun; break; case AGTIAPI_VOLUME_SET: *pchar++ = (AGTIAPI_VOLUME_SET << AGTIAPI_ADDRMODE_SHIFT) | (U08)((pccb->lun >> 8) & 0x3F); *pchar = (U08)pccb->lun; break; case AGTIAPI_LUN_ADDR: *pchar++ = (AGTIAPI_LUN_ADDR << AGTIAPI_ADDRMODE_SHIFT) | pccb->targetId; *pchar = (U08)pccb->lun; break; } } /***************************************************************************** agtiapi_FreeCCB() Purpose: Free a ccb and put it back to ccbFreeList. Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure pccb_t pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Returns: Note: *****************************************************************************/ STATIC void agtiapi_FreeCCB(struct agtiapi_softc *pmcsc, pccb_t pccb) { union ccb *ccb = pccb->ccb; bus_dmasync_op_t op; AG_LOCAL_LOCK(&pmcsc->ccbLock); AGTIAPI_IO( "agtiapi_FreeCCB: start %p\n", pccb ); #ifdef AGTIAPI_TEST_EPL tiEncrypt_t *encrypt; #endif agtiapi_DumpCDB( "agtiapi_FreeCCB", pccb ); if (pccb->sgList != agNULL) { AGTIAPI_IO( "agtiapi_FreeCCB: pccb->sgList is NOT null\n" ); } else { AGTIAPI_PRINTK( "agtiapi_FreeCCB: pccb->sgList is null\n" ); } /* set data transfer direction */ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { op = BUS_DMASYNC_POSTWRITE; } else { op = BUS_DMASYNC_POSTREAD; } if (pccb->numSgElements == 0) { // do nothing AGTIAPI_IO( "agtiapi_FreeCCB: numSgElements zero\n" ); } else if (pccb->numSgElements == 1) { AGTIAPI_IO( "agtiapi_FreeCCB: numSgElements is one\n" ); //op is either BUS_DMASYNC_POSTWRITE or BUS_DMASYNC_POSTREAD bus_dmamap_sync(pmcsc->buffer_dmat, pccb->CCB_dmamap, op); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); } else { AGTIAPI_PRINTK( "agtiapi_FreeCCB: numSgElements 2 or higher \n" ); //op is either BUS_DMASYNC_POSTWRITE or BUS_DMASYNC_POSTREAD bus_dmamap_sync(pmcsc->buffer_dmat, pccb->CCB_dmamap, op); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); } #ifdef AGTIAPI_TEST_DPL if (pccb->tiSuperScsiRequest.Dif.enableDIFPerLA == TRUE) { if(pccb->dplPtr) memset( (char *) pccb->dplPtr, 0, MAX_DPL_REGIONS * sizeof(dplaRegion_t) ); pccb->tiSuperScsiRequest.Dif.enableDIFPerLA = FALSE; pccb->tiSuperScsiRequest.Dif.DIFPerLAAddrLo = 0; pccb->tiSuperScsiRequest.Dif.DIFPerLAAddrHi = 0; } #endif #ifdef AGTIAPI_TEST_EPL encrypt = &pccb->tiSuperScsiRequest.Encrypt; if (encrypt->enableEncryptionPerLA == TRUE) { encrypt->enableEncryptionPerLA = FALSE; encrypt->EncryptionPerLAAddrLo = 0; encrypt->EncryptionPerLAAddrHi = 0; } #endif #ifdef ENABLE_SATA_DIF if (pccb->holePtr && pccb->dmaHandleHole) pci_free_consistent( pmcsc->pCardInfo->pPCIDev, 512, pccb->holePtr, pccb->dmaHandleHole ); pccb->holePtr = 0; pccb->dmaHandleHole = 0; #endif pccb->dataLen = 0; pccb->retryCount = 0; pccb->ccbStatus = 0; pccb->scsiStatus = 0; pccb->startTime = 0; pccb->dmaHandle = 0; pccb->numSgElements = 0; pccb->tiIORequest.tdData = 0; memset((void *)&pccb->tiSuperScsiRequest, 0, AGSCSI_INIT_XCHG_LEN); #ifdef HIALEAH_ENCRYPTION if (pmcsc->encrypt) agtiapi_CleanupEncryptedIO(pmcsc, pccb); #endif pccb->flags = 0; pccb->ccb = NULL; pccb->pccbIO = NULL; pccb->pccbNext = (pccb_t)pmcsc->ccbFreeList; pmcsc->ccbFreeList = (caddr_t *)pccb; pmcsc->activeCCB--; AG_LOCAL_UNLOCK(&pmcsc->ccbLock); return; } /****************************************************************************** agtiapi_FlushCCBs() Purpose: Flush all in processed ccbs. Parameters: ag_card_t *pCard (IN) Pointer to HBA data structure U32 flag (IN) Flag to call back Return: Note: ******************************************************************************/ STATIC void agtiapi_FlushCCBs( struct agtiapi_softc *pCard, U32 flag ) { union ccb *ccb; ccb_t *pccb; AGTIAPI_PRINTK( "agtiapi_FlushCCBs: enter \n" ); for( pccb = (pccb_t)pCard->ccbChainList; pccb != NULL; pccb = pccb->pccbChainNext ) { if( pccb->flags == 0 ) { // printf( "agtiapi_FlushCCBs: nothing, continue \n" ); continue; } ccb = pccb->ccb; if ( pccb->flags & ( TASK_MANAGEMENT | DEV_RESET ) ) { AGTIAPI_PRINTK( "agtiapi_FlushCCBs: agtiapi_FreeTMCCB \n" ); agtiapi_FreeTMCCB( pCard, pccb ); } else { if ( pccb->flags & TAG_SMP ) { AGTIAPI_PRINTK( "agtiapi_FlushCCBs: agtiapi_FreeSMPCCB \n" ); agtiapi_FreeSMPCCB( pCard, pccb ); } else { AGTIAPI_PRINTK( "agtiapi_FlushCCBs: agtiapi_FreeCCB \n" ); agtiapi_FreeCCB( pCard, pccb ); } if( ccb ) { CMND_DMA_UNMAP( pCard, ccb ); if( flag == AGTIAPI_CALLBACK ) { ccb->ccb_h.status = CAM_SCSI_BUS_RESET; xpt_done( ccb ); } } } } } /***************************************************************************** agtiapi_FreeSMPCCB() Purpose: Free a ccb and put it back to ccbFreeList. Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure pccb_t pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Returns: Note: *****************************************************************************/ STATIC void agtiapi_FreeSMPCCB(struct agtiapi_softc *pmcsc, pccb_t pccb) { union ccb *ccb = pccb->ccb; bus_dmasync_op_t op; AG_LOCAL_LOCK(&pmcsc->ccbLock); AGTIAPI_PRINTK("agtiapi_FreeSMPCCB: start %p\n", pccb); /* set data transfer direction */ if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) { op = BUS_DMASYNC_POSTWRITE; } else { op = BUS_DMASYNC_POSTREAD; } if (pccb->numSgElements == 0) { // do nothing AGTIAPI_PRINTK("agtiapi_FreeSMPCCB: numSgElements 0\n"); } else if (pccb->numSgElements == 1) { AGTIAPI_PRINTK("agtiapi_FreeSMPCCB: numSgElements 1\n"); //op is either BUS_DMASYNC_POSTWRITE or BUS_DMASYNC_POSTREAD bus_dmamap_sync(pmcsc->buffer_dmat, pccb->CCB_dmamap, op); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); } else { AGTIAPI_PRINTK("agtiapi_FreeSMPCCB: numSgElements 2 or higher \n"); //op is either BUS_DMASYNC_POSTWRITE or BUS_DMASYNC_POSTREAD bus_dmamap_sync(pmcsc->buffer_dmat, pccb->CCB_dmamap, op); bus_dmamap_unload(pmcsc->buffer_dmat, pccb->CCB_dmamap); } /*dma api cleanning*/ pccb->dataLen = 0; pccb->retryCount = 0; pccb->ccbStatus = 0; pccb->startTime = 0; pccb->dmaHandle = 0; pccb->numSgElements = 0; pccb->tiIORequest.tdData = 0; memset((void *)&pccb->tiSMPFrame, 0, AGSMP_INIT_XCHG_LEN); pccb->flags = 0; pccb->ccb = NULL; pccb->pccbNext = (pccb_t)pmcsc->ccbFreeList; pmcsc->ccbFreeList = (caddr_t *)pccb; pmcsc->activeCCB--; AG_LOCAL_UNLOCK(&pmcsc->ccbLock); return; } /***************************************************************************** agtiapi_FreeTMCCB() Purpose: Free a ccb and put it back to ccbFreeList. Parameters: struct agtiapi_softc *pmcsc (IN) Pointer to HBA data structure pccb_t pccb (IN) A pointer to the driver's own CCB, not CAM's CCB Returns: Note: *****************************************************************************/ STATIC void agtiapi_FreeTMCCB(struct agtiapi_softc *pmcsc, pccb_t pccb) { AG_LOCAL_LOCK(&pmcsc->ccbLock); AGTIAPI_PRINTK("agtiapi_FreeTMCCB: start %p\n", pccb); pccb->dataLen = 0; pccb->retryCount = 0; pccb->ccbStatus = 0; pccb->scsiStatus = 0; pccb->startTime = 0; pccb->dmaHandle = 0; pccb->numSgElements = 0; pccb->tiIORequest.tdData = 0; memset((void *)&pccb->tiSuperScsiRequest, 0, AGSCSI_INIT_XCHG_LEN); pccb->flags = 0; pccb->ccb = NULL; pccb->pccbIO = NULL; pccb->pccbNext = (pccb_t)pmcsc->ccbFreeList; pmcsc->ccbFreeList = (caddr_t *)pccb; pmcsc->activeCCB--; AG_LOCAL_UNLOCK(&pmcsc->ccbLock); return; } /****************************************************************************** agtiapi_CheckAllVectors(): Purpose: Parameters: Return: Note: Currently, not used. ******************************************************************************/ void agtiapi_CheckAllVectors( struct agtiapi_softc *pCard, bit32 context ) { #ifdef SPC_MSIX_INTR if (!agtiapi_intx_mode) { int i; for (i = 0; i < pCard->pCardInfo->maxInterruptVectors; i++) if (tiCOMInterruptHandler(&pCard->tiRoot, i) == agTRUE) tiCOMDelayedInterruptHandler(&pCard->tiRoot, i, 100, context); } else if (tiCOMInterruptHandler(&pCard->tiRoot, 0) == agTRUE) tiCOMDelayedInterruptHandler(&pCard->tiRoot, 0, 100, context); #else if (tiCOMInterruptHandler(&pCard->tiRoot, 0) == agTRUE) tiCOMDelayedInterruptHandler(&pCard->tiRoot, 0, 100, context); #endif } /****************************************************************************** agtiapi_CheckCB() Purpose: Check call back function returned event for process completion Parameters: struct agtiapi_softc *pCard Pointer to card data structure U32 milisec (IN) Waiting time for expected event U32 flag (IN) Flag of the event to check U32 *pStatus (IN) Pointer to status of the card or port to check Return: AGTIAPI_SUCCESS - event comes as expected AGTIAPI_FAIL - event not coming Note: Currently, not used ******************************************************************************/ agBOOLEAN agtiapi_CheckCB( struct agtiapi_softc *pCard, U32 milisec, U32 flag, volatile U32 *pStatus ) { U32 msecsPerTick = pCard->pCardInfo->tiRscInfo.tiInitiatorResource. initiatorOption.usecsPerTick / 1000; S32 i = milisec/msecsPerTick; AG_GLOBAL_ARG( _flags ); AGTIAPI_PRINTK( "agtiapi_CheckCB: start\n" ); AGTIAPI_FLOW( "agtiapi_CheckCB: start\n" ); if( i <= 0 ) i = 1; while (i > 0) { if (*pStatus & TASK_MANAGEMENT) { if (*pStatus & AGTIAPI_CB_DONE) { if( flag == 0 || *pStatus & flag ) return AGTIAPI_SUCCESS; else return AGTIAPI_FAIL; } } else if (pCard->flags & AGTIAPI_CB_DONE) { if( flag == 0 || *pStatus & flag ) return AGTIAPI_SUCCESS; else return AGTIAPI_FAIL; } agtiapi_DelayMSec( msecsPerTick ); AG_SPIN_LOCK_IRQ( agtiapi_host_lock, _flags ); tiCOMTimerTick( &pCard->tiRoot ); agtiapi_CheckAllVectors( pCard, tiNonInterruptContext ); AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, _flags ); i--; } if( *pStatus & TASK_MANAGEMENT ) *pStatus |= TASK_TIMEOUT; return AGTIAPI_FAIL; } /****************************************************************************** agtiapi_DiscoverTgt() Purpose: Discover available devices Parameters: struct agtiapi_softc *pCard (IN) Pointer to the HBA data structure Return: Note: ******************************************************************************/ STATIC void agtiapi_DiscoverTgt(struct agtiapi_softc *pCard) { ag_portal_data_t *pPortalData; U32 count; AGTIAPI_PRINTK("agtiapi_DiscoverTgt: start\n"); AGTIAPI_FLOW("agtiapi_DiscoverTgt\n"); AGTIAPI_INIT("agtiapi_DiscoverTgt\n"); pPortalData = pCard->pPortalData; for (count = 0; count < pCard->portCount; count++, pPortalData++) { pCard->flags &= ~AGTIAPI_CB_DONE; if (!(PORTAL_STATUS(pPortalData) & AGTIAPI_PORT_DISC_READY)) { if (pCard->flags & AGTIAPI_INIT_TIME) { if (agtiapi_CheckCB(pCard, 5000, AGTIAPI_PORT_DISC_READY, &PORTAL_STATUS(pPortalData)) == AGTIAPI_FAIL) { AGTIAPI_PRINTK( "agtiapi_DiscoverTgt: Port %p / %d not ready for " "discovery\n", pPortalData, count ); /* * There is no need to spend time on discovering device * if port is not ready to do so. */ continue; } } else continue; } AGTIAPI_FLOW( "agtiapi_DiscoverTgt: Portal %p DiscoverTargets starts\n", pPortalData ); AGTIAPI_INIT_DELAY(1000); pCard->flags &= ~AGTIAPI_CB_DONE; if (tiINIDiscoverTargets(&pCard->tiRoot, &pPortalData->portalInfo.tiPortalContext, FORCE_PERSISTENT_ASSIGN_MASK) != tiSuccess) AGTIAPI_PRINTK("agtiapi_DiscoverTgt: tiINIDiscoverTargets ERROR\n"); /* * Should wait till discovery completion to start * next portal. However, lower layer have issue on * multi-portal case under Linux. */ } pPortalData = pCard->pPortalData; for (count = 0; count < pCard->portCount; count++, pPortalData++) { if ((PORTAL_STATUS(pPortalData) & AGTIAPI_PORT_DISC_READY)) { if (agtiapi_CheckCB(pCard, 20000, AGTIAPI_DISC_COMPLETE, &PORTAL_STATUS(pPortalData)) == AGTIAPI_FAIL) { if ((PORTAL_STATUS(pPortalData) & AGTIAPI_DISC_COMPLETE)) AGTIAPI_PRINTK( "agtiapi_DiscoverTgt: Portal %p discover complete, " "status 0x%x\n", pPortalData, PORTAL_STATUS(pPortalData) ); else AGTIAPI_PRINTK( "agtiapi_DiscoverTgt: Portal %p discover is not " "completed, status 0x%x\n", pPortalData, PORTAL_STATUS(pPortalData) ); continue; } AGTIAPI_PRINTK( "agtiapi_DiscoverTgt: Portal %d discover target " "success\n", count ); } } /* * Calling to get device handle should be done per portal based * and better right after discovery is done. However, lower iscsi * layer may not returns discovery complete in correct sequence or we * ran out time. We get device handle for all portals together * after discovery is done or timed out. */ pPortalData = pCard->pPortalData; for (count = 0; count < pCard->portCount; count++, pPortalData++) { /* * We try to get device handle no matter * if discovery is completed or not. */ if (PORTAL_STATUS(pPortalData) & AGTIAPI_PORT_DISC_READY) { U32 i; for (i = 0; i < AGTIAPI_GET_DEV_MAX; i++) { if (agtiapi_GetDevHandle(pCard, &pPortalData->portalInfo, 0, 0) != 0) break; agtiapi_DelayMSec(AGTIAPI_EXTRA_DELAY); } if ((PORTAL_STATUS(pPortalData) & AGTIAPI_DISC_COMPLETE) || (pCard->tgtCount > 0)) PORTAL_STATUS(pPortalData) |= ( AGTIAPI_DISC_DONE | AGTIAPI_PORT_LINK_UP ); } } return; } /****************************************************************************** agtiapi_PrepCCBs() Purpose: Prepares CCB including DMA map. Parameters: struct agtiapi_softc *pCard (IN) Pointer to the HBA data structure ccb_hdr_t *hdr (IN) Pointer to the CCB header U32 size (IN) size U32 max_ccb (IN) count Return: Note: ******************************************************************************/ STATIC void agtiapi_PrepCCBs( struct agtiapi_softc *pCard, ccb_hdr_t *hdr, U32 size, U32 max_ccb, int tid ) { int i; U32 hdr_sz, ccb_sz; ccb_t *pccb = NULL; int offset = 0; int nsegs = 0; int sgl_sz = 0; AGTIAPI_PRINTK("agtiapi_PrepCCBs: start\n"); offset = tid * AGTIAPI_CCB_PER_DEVICE; nsegs = AGTIAPI_NSEGS; sgl_sz = sizeof(tiSgl_t) * nsegs; AGTIAPI_PRINTK( "agtiapi_PrepCCBs: tid %d offset %d nsegs %d sizeof(tiSgl_t) " "%lu, max_ccb %d\n", tid, offset, nsegs, sizeof(tiSgl_t), max_ccb ); ccb_sz = roundup2(AGTIAPI_CCB_SIZE, cache_line_size()); hdr_sz = roundup2(sizeof(*hdr), cache_line_size()); AGTIAPI_PRINTK("agtiapi_PrepCCBs: after cache line\n"); memset((void *)hdr, 0, size); hdr->next = pCard->ccbAllocList; pCard->ccbAllocList = hdr; AGTIAPI_PRINTK("agtiapi_PrepCCBs: after memset\n"); pccb = (ccb_t*) ((char*)hdr + hdr_sz); for (i = 0; i < max_ccb; i++, pccb = (ccb_t*)((char*)pccb + ccb_sz)) { pccb->tiIORequest.osData = (void *)pccb; /* * Initially put all the ccbs on the free list * in addition to chainlist. * ccbChainList is a list of all available ccbs * (free/active everything) */ pccb->pccbChainNext = (pccb_t)pCard->ccbChainList; pccb->pccbNext = (pccb_t)pCard->ccbFreeList; pCard->ccbChainList = (caddr_t *)pccb; pCard->ccbFreeList = (caddr_t *)pccb; pCard->ccbTotal++; #ifdef AGTIAPI_ALIGN_CHECK if (&pccb & 0x63) AGTIAPI_PRINTK("pccb = %p\n", pccb); if (pccb->devHandle & 0x63) AGTIAPI_PRINTK("devHandle addr = %p\n", &pccb->devHandle); if (&pccb->lun & 0x63) AGTIAPI_PRINTK("lun addr = %p\n", &pccb->lun); if (&pccb->targetId & 0x63) AGTIAPI_PRINTK("tig addr = %p\n", &pccb->targetId); if (&pccb->ccbStatus & 0x63) AGTIAPI_PRINTK("ccbStatus addr = %p\n", &pccb->ccbStatus); if (&pccb->scsiStatus & 0x63) AGTIAPI_PRINTK("scsiStatus addr = %p\n", &pccb->scsiStatus); if (&pccb->dataLen & 0x63) AGTIAPI_PRINTK("dataLen addr = %p\n", &pccb->dataLen); if (&pccb->senseLen & 0x63) AGTIAPI_PRINTK("senseLen addr = %p\n", &pccb->senseLen); if (&pccb->numSgElements & 0x63) AGTIAPI_PRINTK("numSgElements addr = %p\n", &pccb->numSgElements); if (&pccb->retryCount & 0x63) AGTIAPI_PRINTK("retry cnt addr = %p\n", &pccb->retryCount); if (&pccb->flags & 0x63) AGTIAPI_PRINTK("flag addr = %p\n", &pccb->flags); if (&pccb->pSenseData & 0x63) AGTIAPI_PRINTK("senseData addr = %p\n", &pccb->pSenseData); if (&pccb->sgList[0] & 0x63) AGTIAPI_PRINTK("SgList 0 = %p\n", &pccb->sgList[0]); if (&pccb->pccbNext & 0x63) AGTIAPI_PRINTK("ccb next = %p\n", &pccb->pccbNext); if (&pccb->pccbChainNext & 0x63) AGTIAPI_PRINTK("ccbChainNext = %p\n", &pccb->pccbChainNext); if (&pccb->cmd & 0x63) AGTIAPI_PRINTK("command = %p\n", &pccb->cmd); if( &pccb->startTime & 0x63 ) AGTIAPI_PRINTK( "startTime = %p\n", &pccb->startTime ); if (&pccb->tiIORequest & 0x63) AGTIAPI_PRINTK("tiIOReq addr = %p\n", &pccb->tiIORequest); if (&pccb->tdIOReqBody & 0x63) AGTIAPI_PRINTK("tdIORequestBody addr = %p\n", &pccb->tdIOReqBody); if (&pccb->tiSuperScsiRequest & 0x63) AGTIAPI_PRINTK( "InitiatorExchange addr = %p\n", &pccb->tiSuperScsiRequest ); #endif if ( bus_dmamap_create( pCard->buffer_dmat, 0, &pccb->CCB_dmamap ) != tiSuccess) { AGTIAPI_PRINTK("agtiapi_PrepCCBs: can't create dma\n"); return; } /* assigns tiSgl_t memory to pccb */ pccb->sgList = (void*)((U64)pCard->tisgl_mem + ((i + offset) * sgl_sz)); pccb->tisgl_busaddr = pCard->tisgl_busaddr + ((i + offset) * sgl_sz); pccb->ccb = NULL; pccb->pccbIO = NULL; pccb->startTime = 0; } #ifdef AGTIAPI_ALIGN_CHECK AGTIAPI_PRINTK("ccb size = %d / %d\n", sizeof(ccb_t), ccb_sz); #endif return; } /****************************************************************************** agtiapi_InitCCBs() Purpose: Create and initialize per card based CCB pool. Parameters: struct agtiapi_softc *pCard (IN) Pointer to the HBA data structure int tgtCount (IN) Count Return: Total number of ccb allocated Note: ******************************************************************************/ STATIC U32 agtiapi_InitCCBs(struct agtiapi_softc *pCard, int tgtCount, int tid) { U32 max_ccb, size, ccb_sz, hdr_sz; int no_allocs = 0, i; ccb_hdr_t *hdr = NULL; AGTIAPI_PRINTK("agtiapi_InitCCBs: start\n"); AGTIAPI_PRINTK("agtiapi_InitCCBs: tgtCount %d tid %d\n", tgtCount, tid); AGTIAPI_FLOW("agtiapi_InitCCBs: tgtCount %d tid %d\n", tgtCount, tid); #ifndef HOTPLUG_SUPPORT if (pCard->tgtCount > AGSA_MAX_INBOUND_Q) return 1; #else if (tgtCount > AGSA_MAX_INBOUND_Q) tgtCount = AGSA_MAX_INBOUND_Q; #endif max_ccb = tgtCount * AGTIAPI_CCB_PER_DEVICE;// / 4; // TBR ccb_sz = roundup2(AGTIAPI_CCB_SIZE, cache_line_size()); hdr_sz = roundup2(sizeof(*hdr), cache_line_size()); size = ccb_sz * max_ccb + hdr_sz; for (i = 0; i < (1 << no_allocs); i++) { hdr = (ccb_hdr_t*)malloc( size, M_PMC_MCCB, M_NOWAIT ); if( !hdr ) { panic( "agtiapi_InitCCBs: bug!!!\n" ); } else { agtiapi_PrepCCBs( pCard, hdr, size, max_ccb, tid ); } } return 1; } #ifdef LINUX_PERBI_SUPPORT /****************************************************************************** agtiapi_GetWWNMappings() Purpose: Get the mappings from target IDs to WWNs, if any. Store them in the WWN_list array, indexed by target ID. Leave the devListIndex field blank; this will be filled-in later. Parameters: ag_card_t *pCard (IN) Pointer to HBA data structure ag_mapping_t *pMapList (IN) Pointer to mapped device list Return: Note: The boot command line parameters are used to load the mapping information, which is contained in the system configuration file. ******************************************************************************/ STATIC void agtiapi_GetWWNMappings( struct agtiapi_softc *pCard, ag_mapping_t *pMapList ) { int devDisc; int lIdx = 0; ag_tgt_map_t *pWWNList; ag_slr_map_t *pSLRList; ag_device_t *pDevList; if( !pCard ) panic( "agtiapi_GetWWNMappings: no pCard \n" ); AGTIAPI_PRINTK( "agtiapi_GetWWNMappings: start\n" ); pWWNList = pCard->pWWNList; pSLRList = pCard->pSLRList; pDevList = pCard->pDevList; pCard->numTgtHardMapped = 0; devDisc = pCard->devDiscover; pWWNList[devDisc-1].devListIndex = maxTargets; pSLRList[devDisc-1].localeNameLen = -2; pSLRList[devDisc-1].remoteNameLen = -2; pDevList[devDisc-1].targetId = maxTargets; /* * Get the mappings from holding area which contains * the input of the system file and store them * in the WWN_list array, indexed by target ID. */ for ( lIdx = 0; lIdx < devDisc - 1; lIdx++) { pWWNList[lIdx].flags = 0; pWWNList[lIdx].devListIndex = maxTargets; pSLRList[lIdx].localeNameLen = -1; pSLRList[lIdx].remoteNameLen = -1; } // this is where we would propagate values fed to pMapList } /* agtiapi_GetWWNMappings */ #endif /****************************************************************************** agtiapi_FindWWNListNext() Purpose: finds first available new (unused) wwn list entry Parameters: ag_tgt_map_t *pWWNList Pointer to head of wwn list int lstMax Number of entries in WWNList Return: index into WWNList indicating available entry space; if available entry space is not found, return negative value ******************************************************************************/ STATIC int agtiapi_FindWWNListNext( ag_tgt_map_t *pWWNList, int lstMax ) { int lLstIdx; for ( lLstIdx = 0; lLstIdx < lstMax; lLstIdx++ ) { if ( pWWNList[lLstIdx].devListIndex == lstMax && pWWNList[lLstIdx].targetLen == 0 ) { AGTIAPI_PRINTK( "agtiapi_FindWWNListNext: %d %d %d %d v. %d\n", lLstIdx, pWWNList[lLstIdx].devListIndex, pWWNList[lLstIdx].targetLen, pWWNList[lLstIdx].portId, lstMax ); return lLstIdx; } } return -1; } /****************************************************************************** agtiapi_GetDevHandle() Purpose: Get device handle. Handles will be placed in the devlist array with same order as TargetList provided and will be mapped to a scsi target id and registered to OS later. Parameters: struct agtiapi_softc *pCard (IN) Pointer to the HBA data structure ag_portal_info_t *pPortalInfo (IN) Pointer to the portal data structure U32 eType (IN) Port event U32 eStatus (IN) Port event status Return: Number of device handle slot present Note: The sequence of device handle will match the sequence of taregt list ******************************************************************************/ STATIC U32 agtiapi_GetDevHandle( struct agtiapi_softc *pCard, ag_portal_info_t *pPortalInfo, U32 eType, U32 eStatus ) { ag_device_t *pDevice; // tiDeviceHandle_t *agDev[pCard->devDiscover]; tiDeviceHandle_t **agDev; int devIdx, szdv, devTotal, cmpsetRtn; int lDevIndex = 0, lRunScanFlag = FALSE; int *lDevFlags; tiPortInfo_t portInfT; ag_device_t lTmpDevice; ag_tgt_map_t *pWWNList; ag_slr_map_t *pSLRList; bit32 lReadRm; bit16 lReadCt; AGTIAPI_PRINTK( "agtiapi_GetDevHandle: start\n" ); AGTIAPI_PRINTK( "agtiapi_GetDevHandle: pCard->devDiscover %d / tgtCt %d\n", pCard->devDiscover, pCard->tgtCount ); AGTIAPI_FLOW( "agtiapi_GetDevHandle: portalInfo %p\n", pPortalInfo ); AGTIAPI_INIT_DELAY( 1000 ); agDev = (tiDeviceHandle_t **) malloc( sizeof(tiDeviceHandle_t *) * pCard->devDiscover, M_PMC_MDEV, M_ZERO | M_NOWAIT); if (agDev == NULL) { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: failed to alloc agDev[]\n" ); return 0; } lDevFlags = (int *) malloc( sizeof(int) * pCard->devDiscover, M_PMC_MFLG, M_ZERO | M_NOWAIT ); if (lDevFlags == NULL) { free((caddr_t)agDev, M_PMC_MDEV); AGTIAPI_PRINTK( "agtiapi_GetDevHandle: failed to alloc lDevFlags[]\n" ); return 0; } pWWNList = pCard->pWWNList; pSLRList = pCard->pSLRList; memset( (void *)agDev, 0, sizeof(void *) * pCard->devDiscover ); memset( lDevFlags, 0, sizeof(int) * pCard->devDiscover ); // get device handles devTotal = tiINIGetDeviceHandles( &pCard->tiRoot, &pPortalInfo->tiPortalContext, (tiDeviceHandle_t **)agDev, pCard->devDiscover ); AGTIAPI_PRINTK( "agtiapi_GetDevHandle: portalInfo %p port id %d event %u " "status %u card %p pCard->devDiscover %d devTotal %d " "pPortalInfo->devTotal %d pPortalInfo->devPrev %d " "AGTIAPI_INIT_TIME %x\n", pPortalInfo, pPortalInfo->portID, eType, eStatus, pCard, pCard->devDiscover, devTotal, pPortalInfo->devTotal, pPortalInfo->devPrev, pCard->flags & AGTIAPI_INIT_TIME ); // reset devTotal from any previous runs of this pPortalInfo->devPrev = devTotal; pPortalInfo->devTotal = devTotal; AG_LIST_LOCK( &pCard->devListLock ); if ( tiCOMGetPortInfo( &pCard->tiRoot, &pPortalInfo->tiPortalContext, &portInfT ) != tiSuccess) { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: tiCOMGetPortInfo did not succeed. \n" ); } szdv = sizeof( pPortalInfo->pDevList ) / sizeof( pPortalInfo->pDevList[0] ); if (szdv > pCard->devDiscover) { szdv = pCard->devDiscover; } // reconstructing dev list via comparison of wwn for ( devIdx = 0; devIdx < pCard->devDiscover; devIdx++ ) { if ( agDev[devIdx] != NULL ) { // AGTIAPI_PRINTK( "agtiapi_GetDevHandle: agDev %d not NULL %p\n", // devIdx, agDev[devIdx] ); // pack temp device structure for tiINIGetDeviceInfo call pDevice = &lTmpDevice; pDevice->devType = DIRECT_DEVICE; pDevice->pCard = (void *)pCard; pDevice->flags = ACTIVE; pDevice->pPortalInfo = pPortalInfo; pDevice->pDevHandle = agDev[devIdx]; pDevice->qbusy = agFALSE; //AGTIAPI_PRINTK( "agtiapi_GetDevHandle: idx %d / %d : %p \n", // devIdx, pCard->devDiscover, agDev[devIdx] ); tiINIGetDeviceInfo( &pCard->tiRoot, agDev[devIdx], &pDevice->devInfo ); //AGTIAPI_PRINTK( "agtiapi_GetDevHandle: wwn sizes %ld %d/%d ", // sizeof(pDevice->targetName), // pDevice->devInfo.osAddress1, // pDevice->devInfo.osAddress2 ); wwncpy( pDevice ); wwnprintk( (unsigned char*)pDevice->targetName, pDevice->targetLen ); for ( lDevIndex = 0; lDevIndex < szdv; lDevIndex++ ) // match w/ wwn list { if ( (pCard->pDevList[lDevIndex].portalId == pPortalInfo->portID) && pDevice->targetLen > 0 && portInfT.localNameLen > 0 && portInfT.remoteNameLen > 0 && pSLRList[pWWNList[lDevIndex].sasLrIdx].localeNameLen > 0 && pSLRList[pWWNList[lDevIndex].sasLrIdx].remoteNameLen > 0 && ( portInfT.localNameLen == pSLRList[pWWNList[lDevIndex].sasLrIdx].localeNameLen ) && ( portInfT.remoteNameLen == pSLRList[pWWNList[lDevIndex].sasLrIdx].remoteNameLen ) && memcmp( pWWNList[lDevIndex].targetName, pDevice->targetName, pDevice->targetLen ) == 0 && memcmp( pSLRList[pWWNList[lDevIndex].sasLrIdx].localeName, portInfT.localName, portInfT.localNameLen ) == 0 && memcmp( pSLRList[pWWNList[lDevIndex].sasLrIdx].remoteName, portInfT.remoteName, portInfT.remoteNameLen ) == 0 ) { AGTIAPI_PRINTK( " pWWNList match @ %d/%d/%d \n", lDevIndex, devIdx, pPortalInfo->portID ); if ( (pCard->pDevList[lDevIndex].targetId == lDevIndex) && ( pPortalInfo->pDevList[lDevIndex] == &pCard->pDevList[lDevIndex] ) ) // active { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: dev in use %d of %d/%d\n", lDevIndex, devTotal, pPortalInfo->portID ); lDevFlags[devIdx] |= DPMC_LEANFLAG_AGDEVUSED; // agDev handle lDevFlags[lDevIndex] |= DPMC_LEANFLAG_PDEVSUSED; // pDevice used lReadRm = atomic_readandclear_32( &pWWNList[lDevIndex].devRemoved ); if ( lReadRm ) // cleared timeout, now remove count for timer { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: clear timer count for" " %d of %d\n", lDevIndex, pPortalInfo->portID ); atomic_subtract_16( &pCard->rmChkCt, 1 ); lReadCt = atomic_load_acq_16( &pCard->rmChkCt ); if ( 0 == lReadCt ) { callout_stop( &pCard->devRmTimer ); } } break; } AGTIAPI_PRINTK( "agtiapi_GetDevHandle: goin fresh on %d of %d/%d\n", lDevIndex, // reactivate now devTotal, pPortalInfo->portID ); // pDevice going fresh lRunScanFlag = TRUE; // scan and clear outstanding removals // pCard->tgtCount++; ## pDevice->targetId = lDevIndex; pDevice->portalId = pPortalInfo->portID; memcpy ( &pCard->pDevList[lDevIndex], pDevice, sizeof(lTmpDevice) ); agDev[devIdx]->osData = (void *)&pCard->pDevList[lDevIndex]; if ( agtiapi_InitCCBs( pCard, 1, pDevice->targetId ) == 0 ) { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: InitCCB " "tgtCnt %d ERROR!\n", pCard->tgtCount ); AG_LIST_UNLOCK( &pCard->devListLock ); free((caddr_t)lDevFlags, M_PMC_MFLG); free((caddr_t)agDev, M_PMC_MDEV); return 0; } pPortalInfo->pDevList[lDevIndex] = &pCard->pDevList[lDevIndex]; // (ag_device_t *) if ( 0 == lDevFlags[devIdx] ) { pPortalInfo->devTotal++; lDevFlags[devIdx] |= DPMC_LEANFLAG_AGDEVUSED; // agDev used lDevFlags[lDevIndex] |= DPMC_LEANFLAG_PDEVSUSED; // pDevice used } else { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: odd dev handle " "status inspect %d %d %d\n", lDevFlags[devIdx], devIdx, lDevIndex ); pPortalInfo->devTotal++; lDevFlags[devIdx] |= DPMC_LEANFLAG_AGDEVUSED; // agDev used lDevFlags[lDevIndex] |= DPMC_LEANFLAG_PDEVSUSED; // pDevice used } break; } } // end: match this wwn with previous wwn list // we have an agDev entry, but no pWWNList target for it if ( !(lDevFlags[devIdx] & DPMC_LEANFLAG_AGDEVUSED) ) { // flag dev handle not accounted for yet lDevFlags[devIdx] |= DPMC_LEANFLAG_NOWWNLIST; // later, get an empty pDevice and map this agDev. // AGTIAPI_PRINTK( "agtiapi_GetDevHandle: devIdx %d flags 0x%x, %d\n", // devIdx, lDevFlags[devIdx], (lDevFlags[devIdx] & 8) ); } } else { lDevFlags[devIdx] |= DPMC_LEANFLAG_NOAGDEVYT; // known empty agDev handle } } // AGTIAPI_PRINTK( "agtiapi_GetDevHandle: all WWN all the time, " // "devLstIdx/flags/(WWNL)portId ... \n" ); // review device list for further action needed for ( devIdx = 0; devIdx < pCard->devDiscover; devIdx++ ) { if ( lDevFlags[devIdx] & DPMC_LEANFLAG_NOWWNLIST ) // new target, register { int lNextDyad; // find next available dyad entry AGTIAPI_PRINTK( "agtiapi_GetDevHandle: register new target, " "devIdx %d -- %d \n", devIdx, pCard->devDiscover ); lRunScanFlag = TRUE; // scan and clear outstanding removals for ( lNextDyad = 0; lNextDyad < pCard->devDiscover; lNextDyad++ ) { if ( pSLRList[lNextDyad].localeNameLen < 0 && pSLRList[lNextDyad].remoteNameLen < 0 ) break; } if ( lNextDyad == pCard->devDiscover ) { printf( "agtiapi_GetDevHandle: failed to find available SAS LR\n" ); AG_LIST_UNLOCK( &pCard->devListLock ); free( (caddr_t)lDevFlags, M_PMC_MFLG ); free( (caddr_t)agDev, M_PMC_MDEV ); return 0; } // index of new entry lDevIndex = agtiapi_FindWWNListNext( pWWNList, pCard->devDiscover ); AGTIAPI_PRINTK( "agtiapi_GetDevHandle: listIdx new target %d of %d/%d\n", lDevIndex, devTotal, pPortalInfo->portID ); if ( 0 > lDevIndex ) { printf( "agtiapi_GetDevHandle: WARNING -- WWNList exhausted.\n" ); continue; } pDevice = &pCard->pDevList[lDevIndex]; tiINIGetDeviceInfo( &pCard->tiRoot, agDev[devIdx], &pDevice->devInfo ); wwncpy( pDevice ); agtiapi_InitCCBs( pCard, 1, lDevIndex ); pDevice->pCard = (void *)pCard; pDevice->devType = DIRECT_DEVICE; // begin to populate new WWNList entry memcpy( pWWNList[lDevIndex].targetName, pDevice->targetName, pDevice->targetLen ); pWWNList[lDevIndex].targetLen = pDevice->targetLen; pWWNList[lDevIndex].flags = SOFT_MAPPED; pWWNList[lDevIndex].portId = pPortalInfo->portID; pWWNList[lDevIndex].devListIndex = lDevIndex; pWWNList[lDevIndex].sasLrIdx = lNextDyad; pSLRList[lNextDyad].localeNameLen = portInfT.localNameLen; pSLRList[lNextDyad].remoteNameLen = portInfT.remoteNameLen; memcpy( pSLRList[lNextDyad].localeName, portInfT.localName, portInfT.localNameLen ); memcpy( pSLRList[lNextDyad].remoteName, portInfT.remoteName, portInfT.remoteNameLen ); // end of populating new WWNList entry pDevice->targetId = lDevIndex; pDevice->flags = ACTIVE; pDevice->CCBCount = 0; pDevice->pDevHandle = agDev[devIdx]; agDev[devIdx]->osData = (void*)pDevice; pDevice->pPortalInfo = pPortalInfo; pDevice->portalId = pPortalInfo->portID; pPortalInfo->pDevList[lDevIndex] = (void*)pDevice; lDevFlags[lDevIndex] |= DPMC_LEANFLAG_PDEVSUSED; // mark pDevice slot used } if ( (pCard->pDevList[devIdx].portalId == pPortalInfo->portID) && !(lDevFlags[devIdx] & DPMC_LEANFLAG_PDEVSUSED) ) // pDevice not used { pDevice = &pCard->pDevList[devIdx]; //pDevice->flags &= ~ACTIVE; if ( ( pDevice->pDevHandle != NULL || pPortalInfo->pDevList[devIdx] != NULL ) ) { atomic_add_16( &pCard->rmChkCt, 1 ); // show count of lost device if (FALSE == lRunScanFlag) { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: targ dropped out %d of %d/%d\n", devIdx, devTotal, pPortalInfo->portID ); // if ( 0 == pWWNList[devIdx].devRemoved ) '.devRemoved = 5; cmpsetRtn = atomic_cmpset_32( &pWWNList[devIdx].devRemoved, 0, 5 ); if ( 0 == cmpsetRtn ) { AGTIAPI_PRINTK( "agtiapi_GetDevHandle: target %d timer already set\n", devIdx ); } else { callout_reset( &pCard->devRmTimer, 1 * hz, agtiapi_devRmCheck, pCard ); } } // else ... scan coming soon enough anyway, ignore timer for dropout } } } // end of for ( devIdx = 0; ... AG_LIST_UNLOCK( &pCard->devListLock ); free((caddr_t)lDevFlags, M_PMC_MFLG); free((caddr_t)agDev, M_PMC_MDEV); if ( TRUE == lRunScanFlag ) agtiapi_clrRmScan( pCard ); return devTotal; } // end agtiapi_GetDevHandle /****************************************************************************** agtiapi_scan() Purpose: Triggers CAM's scan Parameters: struct agtiapi_softc *pCard (IN) Pointer to the HBA data structure Return: Note: ******************************************************************************/ static void agtiapi_scan(struct agtiapi_softc *pmcsc) { union ccb *ccb; int bus, tid, lun; AGTIAPI_PRINTK("agtiapi_scan: start cardNO %d \n", pmcsc->cardNo); bus = cam_sim_path(pmcsc->sim); tid = CAM_TARGET_WILDCARD; lun = CAM_LUN_WILDCARD; mtx_lock(&(pmcsc->pCardInfo->pmIOLock)); ccb = xpt_alloc_ccb_nowait(); if (ccb == agNULL) { mtx_unlock(&(pmcsc->pCardInfo->pmIOLock)); return; } if (xpt_create_path(&ccb->ccb_h.path, agNULL, bus, tid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { mtx_unlock(&(pmcsc->pCardInfo->pmIOLock)); xpt_free_ccb(ccb); return; } mtx_unlock(&(pmcsc->pCardInfo->pmIOLock)); pmcsc->dev_scan = agTRUE; xpt_rescan(ccb); return; } /****************************************************************************** agtiapi_DeQueueCCB() Purpose: Remove a ccb from a queue Parameters: struct agtiapi_softc *pCard (IN) Pointer to the card structure pccb_t *phead (IN) Pointer to a head of ccb queue ccb_t *pccd (IN) Pointer to the ccb to be processed Return: AGTIAPI_SUCCESS - the ccb is removed from queue AGTIAPI_FAIL - the ccb is not found from queue Note: ******************************************************************************/ STATIC agBOOLEAN agtiapi_DeQueueCCB(struct agtiapi_softc *pCard, pccb_t *phead, pccb_t *ptail, #ifdef AGTIAPI_LOCAL_LOCK struct mtx *lock, #endif ccb_t *pccb) { ccb_t *pccb_curr; U32 status = AGTIAPI_FAIL; AGTIAPI_PRINTK("agtiapi_DeQueueCCB: %p from %p\n", pccb, phead); if (pccb == NULL || *phead == NULL) { return AGTIAPI_FAIL; } AGTIAPI_PRINTK("agtiapi_DeQueueCCB: %p from %p\n", pccb, phead); AG_LOCAL_LOCK(lock); if (pccb == *phead) { *phead = (*phead)->pccbNext; if (pccb == *ptail) { *ptail = NULL; } else pccb->pccbNext = NULL; status = AGTIAPI_SUCCESS; } else { pccb_curr = *phead; while (pccb_curr->pccbNext != NULL) { if (pccb_curr->pccbNext == pccb) { pccb_curr->pccbNext = pccb->pccbNext; pccb->pccbNext = NULL; if (pccb == *ptail) { *ptail = pccb_curr; } else pccb->pccbNext = NULL; status = AGTIAPI_SUCCESS; break; } pccb_curr = pccb_curr->pccbNext; } } AG_LOCAL_UNLOCK(lock); return status; } STATIC void wwnprintk( unsigned char *name, int len ) { int i; for (i = 0; i < len; i++, name++) AGTIAPI_PRINTK("%02x", *name); AGTIAPI_PRINTK("\n"); } /* * SAS and SATA behind expander has 8 byte long unique address. * However, direct connect SATA device use 512 byte unique device id. * SPC uses remoteName to indicate length of ID and remoteAddress for the * address of memory that holding ID. */ STATIC int wwncpy( ag_device_t *pDevice ) { int rc = 0; if (sizeof(pDevice->targetName) >= pDevice->devInfo.osAddress1 + pDevice->devInfo.osAddress2) { memcpy(pDevice->targetName, pDevice->devInfo.remoteName, pDevice->devInfo.osAddress1); memcpy(pDevice->targetName + pDevice->devInfo.osAddress1, pDevice->devInfo.remoteAddress, pDevice->devInfo.osAddress2); pDevice->targetLen = pDevice->devInfo.osAddress1 + pDevice->devInfo.osAddress2; rc = pDevice->targetLen; } else { AGTIAPI_PRINTK("WWN wrong size: %d + %d ERROR\n", pDevice->devInfo.osAddress1, pDevice->devInfo.osAddress2); rc = -1; } return rc; } /****************************************************************************** agtiapi_ReleaseCCBs() Purpose: Free all allocated CCB memories for the Host Adapter. Parameters: struct agtiapi_softc *pCard (IN) Pointer to HBA data structure Return: Note: ******************************************************************************/ STATIC void agtiapi_ReleaseCCBs( struct agtiapi_softc *pCard ) { ccb_hdr_t *hdr; U32 hdr_sz; ccb_t *pccb = NULL; AGTIAPI_PRINTK( "agtiapi_ReleaseCCBs: start\n" ); #if ( defined AGTIAPI_TEST_DPL || defined AGTIAPI_TEST_EPL ) ccb_t *pccb; #endif #ifdef AGTIAPI_TEST_DPL for (pccb = (pccb_t)pCard->ccbChainList; pccb != NULL; pccb = pccb->pccbChainNext) { if(pccb->dplPtr && pccb->dplDma) pci_pool_free(pCard->dpl_ctx_pool, pccb->dplPtr, pccb->dplDma); } #endif #ifdef AGTIAPI_TEST_EPL for (pccb = (pccb_t)pCard->ccbChainList; pccb != NULL; pccb = pccb->pccbChainNext) { if(pccb->epl_ptr && pccb->epl_dma_ptr) pci_pool_free( pCard->epl_ctx_pool, pccb->epl_ptr, pccb->epl_dma_ptr ); } #endif while ((hdr = pCard->ccbAllocList) != NULL) { pCard->ccbAllocList = hdr->next; hdr_sz = roundup2(sizeof(*hdr), cache_line_size()); pccb = (ccb_t*) ((char*)hdr + hdr_sz); if (pCard->buffer_dmat != NULL && pccb->CCB_dmamap != NULL) { bus_dmamap_destroy(pCard->buffer_dmat, pccb->CCB_dmamap); } free(hdr, M_PMC_MCCB); } pCard->ccbAllocList = NULL; return; } /****************************************************************************** agtiapi_TITimer() Purpose: Timer tick for tisa common layer Parameters: void *data (IN) Pointer to the HBA data structure Return: Note: ******************************************************************************/ STATIC void agtiapi_TITimer( void *data ) { U32 next_tick; struct agtiapi_softc *pCard; pCard = (struct agtiapi_softc *)data; // AGTIAPI_PRINTK("agtiapi_TITimer: start\n"); AG_GLOBAL_ARG( flags ); next_tick = pCard->pCardInfo->tiRscInfo.tiLoLevelResource. loLevelOption.usecsPerTick / USEC_PER_TICK; if( next_tick == 0 ) /* no timer required */ return; AG_SPIN_LOCK_IRQ( agtiapi_host_lock, flags ); if( pCard->flags & AGTIAPI_SHUT_DOWN ) goto ext; tiCOMTimerTick( &pCard->tiRoot ); /* tisa common layer timer tick */ //add for polling mode #ifdef PMC_SPC if( agtiapi_polling_mode ) agtiapi_CheckAllVectors( pCard, tiNonInterruptContext ); #endif callout_reset( &pCard->OS_timer, next_tick, agtiapi_TITimer, pCard ); ext: AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); return; } /****************************************************************************** agtiapi_clrRmScan() Purpose: Clears device list entries scheduled for timeout and calls scan Parameters: struct agtiapi_softc *pCard (IN) Pointer to HBA data structure ******************************************************************************/ STATIC void agtiapi_clrRmScan( struct agtiapi_softc *pCard ) { ag_tgt_map_t *pWWNList; ag_portal_info_t *pPortalInfo; ag_portal_data_t *pPortalData; int lIdx; bit32 lReadRm; bit16 lReadCt; pWWNList = pCard->pWWNList; AGTIAPI_PRINTK( "agtiapi_clrRmScan: start\n" ); AG_LIST_LOCK( &pCard->devListLock ); for ( lIdx = 0; lIdx < pCard->devDiscover; lIdx++ ) { lReadCt = atomic_load_acq_16( &pCard->rmChkCt ); if ( 0 == lReadCt ) { break; // trim to who cares } lReadRm = atomic_readandclear_32( &pWWNList[lIdx].devRemoved ); if ( lReadRm > 0 ) { pCard->pDevList[lIdx].flags &= ~ACTIVE; pCard->pDevList[lIdx].pDevHandle = NULL; pPortalData = &pCard->pPortalData[pWWNList[lIdx].portId]; pPortalInfo = &pPortalData->portalInfo; pPortalInfo->pDevList[lIdx] = NULL; AGTIAPI_PRINTK( "agtiapi_clrRmScan: cleared dev %d at port %d\n", lIdx, pWWNList[lIdx].portId ); atomic_subtract_16( &pCard->rmChkCt, 1 ); } } AG_LIST_UNLOCK( &pCard->devListLock ); agtiapi_scan( pCard ); } /****************************************************************************** agtiapi_devRmCheck() Purpose: Timer tick to check for timeout on missing targets Removes device list entry when timeout is reached Parameters: void *data (IN) Pointer to the HBA data structure ******************************************************************************/ STATIC void agtiapi_devRmCheck( void *data ) { struct agtiapi_softc *pCard; ag_tgt_map_t *pWWNList; int lIdx, cmpsetRtn, lRunScanFlag = FALSE; bit16 lReadCt; bit32 lReadRm; pCard = ( struct agtiapi_softc * )data; // routine overhead if ( callout_pending( &pCard->devRmTimer ) ) // callout was reset { return; } if ( !callout_active( &pCard->devRmTimer ) ) // callout was stopped { return; } callout_deactivate( &pCard->devRmTimer ); if( pCard->flags & AGTIAPI_SHUT_DOWN ) { return; // implicit timer clear } pWWNList = pCard->pWWNList; AG_LIST_LOCK( &pCard->devListLock ); lReadCt = atomic_load_acq_16( &pCard->rmChkCt ); if ( lReadCt ) { if ( callout_pending(&pCard->devRmTimer) == FALSE ) { callout_reset( &pCard->devRmTimer, 1 * hz, agtiapi_devRmCheck, pCard ); } else { AG_LIST_UNLOCK( &pCard->devListLock ); return; } for ( lIdx = 0; lIdx < pCard->devDiscover; lIdx++ ) { lReadCt = atomic_load_acq_16( &pCard->rmChkCt ); if ( 0 == lReadCt ) { break; // if handled somewhere else, get out } lReadRm = atomic_load_acq_32( &pWWNList[lIdx].devRemoved ); if ( lReadRm > 0 ) { if ( 1 == lReadRm ) // timed out { // no decrement of devRemoved as way to leave a clrRmScan marker lRunScanFlag = TRUE; // other devRemoved values are about to get wiped break; // ... so bail out } else { AGTIAPI_PRINTK( "agtiapi_devRmCheck: counting down dev %d @ %d; %d\n", lIdx, lReadRm, lReadCt ); cmpsetRtn = atomic_cmpset_32( &pWWNList[lIdx].devRemoved, lReadRm, lReadRm-1 ); if ( 0 == cmpsetRtn ) { printf( "agtiapi_devRmCheck: %d decrement already handled\n", lIdx ); } } } } AG_LIST_UNLOCK( &pCard->devListLock ); if ( TRUE == lRunScanFlag ) agtiapi_clrRmScan( pCard ); } else { AG_LIST_UNLOCK( &pCard->devListLock ); } return; } static void agtiapi_cam_poll( struct cam_sim *asim ) { return; } /***************************************************************************** agtiapi_ResetCard() Purpose: Hard or soft reset on the controller and resend any outstanding requests if needed. Parameters: struct agtiapi_softc *pCard (IN) Pointer to HBA data structure unsigned lomg flags (IN/OUT) Flags used in locking done from calling layers Return: AGTIAPI_SUCCESS - reset successful AGTIAPI_FAIL - reset failed Note: *****************************************************************************/ U32 agtiapi_ResetCard( struct agtiapi_softc *pCard, unsigned long *flags ) { ag_device_t *pDevice; U32 lIdx = 0; U32 lFlagVal; agBOOLEAN ret; ag_portal_info_t *pPortalInfo; ag_portal_data_t *pPortalData; U32 count, loop; int szdv; if( pCard->flags & AGTIAPI_RESET ) { AGTIAPI_PRINTK( "agtiapi_ResetCard: reset card already in progress!\n" ); return AGTIAPI_FAIL; } AGTIAPI_PRINTK( "agtiapi_ResetCard: Enter cnt %d\n", pCard->resetCount ); #ifdef LOGEVENT agtiapi_LogEvent( pCard, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "Reset initiator time = %d!", pCard->resetCount + 1 ); #endif pCard->flags |= AGTIAPI_RESET; pCard->flags &= ~(AGTIAPI_CB_DONE | AGTIAPI_RESET_SUCCESS); tiCOMSystemInterruptsActive( &pCard->tiRoot, FALSE ); pCard->flags &= ~AGTIAPI_SYS_INTR_ON; agtiapi_FlushCCBs( pCard, AGTIAPI_CALLBACK ); for ( lIdx = 1; 3 >= lIdx; lIdx++ ) // we try reset up to 3 times { if( pCard->flags & AGTIAPI_SOFT_RESET ) { AGTIAPI_PRINTK( "agtiapi_ResetCard: soft variant\n" ); tiCOMReset( &pCard->tiRoot, tiSoftReset ); } else { AGTIAPI_PRINTK( "agtiapi_ResetCard: no flag, no reset!\n" ); } lFlagVal = AGTIAPI_RESET_SUCCESS; AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, *flags ); ret = agtiapi_CheckCB( pCard, 50000, lFlagVal, &pCard->flags ); AG_SPIN_LOCK_IRQ( agtiapi_host_lock, *flags ); if( ret == AGTIAPI_FAIL ) { AGTIAPI_PRINTK( "agtiapi_ResetCard: CheckCB indicates failed reset call, " "try again?\n" ); } else { break; } } if ( 1 < lIdx ) { if ( AGTIAPI_FAIL == ret ) { AGTIAPI_PRINTK( "agtiapi_ResetCard: soft reset failed after try %d\n", lIdx ); } else { AGTIAPI_PRINTK( "agtiapi_ResetCard: soft reset success at try %d\n", lIdx ); } } if( AGTIAPI_FAIL == ret ) { printf( "agtiapi_ResetCard: reset ERROR\n" ); pCard->flags &= ~AGTIAPI_INSTALLED; return AGTIAPI_FAIL; } pCard->flags &= ~AGTIAPI_SOFT_RESET; // disable all devices pDevice = pCard->pDevList; for( lIdx = 0; lIdx < maxTargets; lIdx++, pDevice++ ) { /* if ( pDevice->flags & ACTIVE ) { printf( "agtiapi_ResetCard: before ... active device %d\n", lIdx ); } */ pDevice->flags &= ~ACTIVE; } AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, *flags ); if( tiCOMPortInit( &pCard->tiRoot, agFALSE ) != tiSuccess ) printf( "agtiapi_ResetCard: tiCOMPortInit FAILED \n" ); else AGTIAPI_PRINTK( "agtiapi_ResetCard: tiCOMPortInit success\n" ); if( !pCard->pDevList ) { // try to get a little sanity here AGTIAPI_PRINTK( "agtiapi_ResetCard: no pDevList ERROR %p\n", pCard->pDevList ); return AGTIAPI_FAIL; } AGTIAPI_PRINTK( "agtiapi_ResetCard: pre target-count %d port-count %d\n", pCard->tgtCount, pCard->portCount ); pCard->tgtCount = 0; DELAY( 500000 ); pCard->flags &= ~AGTIAPI_CB_DONE; pPortalData = pCard->pPortalData; for( count = 0; count < pCard->portCount; count++ ) { AG_SPIN_LOCK_IRQ( agtiapi_host_lock, flags ); pPortalInfo = &pPortalData->portalInfo; pPortalInfo->portStatus = 0; pPortalInfo->portStatus &= ~( AGTIAPI_PORT_START | AGTIAPI_PORT_DISC_READY | AGTIAPI_DISC_DONE | AGTIAPI_DISC_COMPLETE ); szdv = sizeof( pPortalInfo->pDevList ) / sizeof( pPortalInfo->pDevList[0] ); if (szdv > pCard->devDiscover) { szdv = pCard->devDiscover; } for( lIdx = 0, loop = 0; lIdx < szdv && loop < pPortalInfo->devTotal; lIdx++ ) { pDevice = (ag_device_t*)pPortalInfo->pDevList[lIdx]; if( pDevice ) { loop++; pDevice->pDevHandle = 0; // mark for availability in pCard->pDevList[] // don't erase more as the device is scheduled for removal on DPC } AGTIAPI_PRINTK( "agtiapi_ResetCard: reset pDev %p pDevList %p idx %d\n", pDevice, pPortalInfo->pDevList, lIdx ); pPortalInfo->devTotal = pPortalInfo->devPrev = 0; } for( lIdx = 0; lIdx < maxTargets; lIdx++ ) { // we reconstruct dev list later in get dev handle pPortalInfo->pDevList[lIdx] = NULL; } for( loop = 0; loop < AGTIAPI_LOOP_MAX; loop++ ) { AGTIAPI_PRINTK( "agtiapi_ResetCard: tiCOMPortStart entry data " "%p / %d / %p\n", &pCard->tiRoot, pPortalInfo->portID, &pPortalInfo->tiPortalContext ); if( tiCOMPortStart( &pCard->tiRoot, pPortalInfo->portID, &pPortalInfo->tiPortalContext, 0 ) != tiSuccess ) { printf( "agtiapi_ResetCard: tiCOMPortStart %d FAILED\n", pPortalInfo->portID ); } else { AGTIAPI_PRINTK( "agtiapi_ResetCard: tiCOMPortStart %d success\n", pPortalInfo->portID ); break; } } AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); tiCOMGetPortInfo( &pCard->tiRoot, &pPortalInfo->tiPortalContext, &pPortalInfo->tiPortInfo ); pPortalData++; } // ## fail case: pCard->flags &= ~AGTIAPI_INSTALLED; AG_SPIN_LOCK_IRQ(agtiapi_host_lock, *flags); if( !(pCard->flags & AGTIAPI_INSTALLED) ) // driver not installed ! { printf( "agtiapi_ResetCard: error, driver not intstalled? " "!AGTIAPI_INSTALLED \n" ); return AGTIAPI_FAIL; } AGTIAPI_PRINTK( "agtiapi_ResetCard: total device %d\n", pCard->tgtCount ); #ifdef LOGEVENT agtiapi_LogEvent( pCard, IOCTL_EVT_SEV_INFORMATIONAL, 0, agNULL, 0, "Reset initiator total device = %d!", pCard->tgtCount ); #endif pCard->resetCount++; AGTIAPI_PRINTK( "agtiapi_ResetCard: clear send and done queues\n" ); // clear send & done queue AG_LOCAL_LOCK( &pCard->sendLock ); pCard->ccbSendHead = NULL; pCard->ccbSendTail = NULL; AG_LOCAL_UNLOCK( &pCard->sendLock ); AG_LOCAL_LOCK( &pCard->doneLock ); pCard->ccbDoneHead = NULL; pCard->ccbDoneTail = NULL; AG_LOCAL_UNLOCK( &pCard->doneLock ); // clear smp queues also AG_LOCAL_LOCK( &pCard->sendSMPLock ); pCard->smpSendHead = NULL; pCard->smpSendTail = NULL; AG_LOCAL_UNLOCK( &pCard->sendSMPLock ); AG_LOCAL_LOCK( &pCard->doneSMPLock ); pCard->smpDoneHead = NULL; pCard->smpDoneTail = NULL; AG_LOCAL_UNLOCK( &pCard->doneSMPLock ); // finished with all reset stuff, now start things back up tiCOMSystemInterruptsActive( &pCard->tiRoot, TRUE ); pCard->flags |= AGTIAPI_SYS_INTR_ON; pCard->flags |= AGTIAPI_HAD_RESET; pCard->flags &= ~AGTIAPI_RESET; // ## agtiapi_StartIO( pCard ); AGTIAPI_PRINTK( "agtiapi_ResetCard: local return success\n" ); return AGTIAPI_SUCCESS; } // agtiapi_ResetCard /****************************************************************************** agtiapi_ReleaseHBA() Purpose: Releases all resources previously acquired to support a specific Host Adapter, including the I/O Address range, and unregisters the agtiapi Host Adapter. Parameters: device_t dev (IN) - device pointer Return: always return 0 - success Note: ******************************************************************************/ int agtiapi_ReleaseHBA( device_t dev ) { int thisCard = device_get_unit( dev ); // keeping get_unit call to once int i; ag_card_info_t *thisCardInst = &agCardInfoList[ thisCard ]; struct ccb_setasync csa; struct agtiapi_softc *pCard; pCard = device_get_softc( dev ); ag_card_info_t *pCardInfo = pCard->pCardInfo; ag_resource_info_t *pRscInfo = &thisCardInst->tiRscInfo; AG_GLOBAL_ARG(flags); AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: start\n" ); if (thisCardInst != pCardInfo) { AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: Wrong ag_card_info_t thisCardInst %p " "pCardInfo %p\n", thisCardInst, pCardInfo ); panic( "agtiapi_ReleaseHBA: Wrong ag_card_info_t thisCardInst %p pCardInfo " "%p\n", thisCardInst, pCardInfo ); return( EIO ); } AGTIAPI_PRINTK( "agtiapi_ReleaseHBA card %p\n", pCard ); pCard->flags |= AGTIAPI_SHUT_DOWN; // remove timer if (pCard->flags & AGTIAPI_TIMER_ON) { AG_SPIN_LOCK_IRQ( agtiapi_host_lock, flags ); callout_drain( &pCard->OS_timer ); callout_drain( &pCard->devRmTimer ); callout_drain(&pCard->IO_timer); AG_SPIN_UNLOCK_IRQ( agtiapi_host_lock, flags ); AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: timer released\n" ); } #ifdef HIALEAH_ENCRYPTION //Release encryption table memory - Fix it //if(pCard->encrypt && (pCard->flags & AGTIAPI_INSTALLED)) //agtiapi_CleanupEncryption(pCard); #endif /* * Shutdown the channel so that chip gets frozen * and it does not do any more pci-bus accesses. */ if (pCard->flags & AGTIAPI_SYS_INTR_ON) { tiCOMSystemInterruptsActive( &pCard->tiRoot, FALSE ); pCard->flags &= ~AGTIAPI_SYS_INTR_ON; AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: card interrupt off\n" ); } if (pCard->flags & AGTIAPI_INSTALLED) { tiCOMShutDown( &pCard->tiRoot ); AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: low layers shutdown\n" ); } /* * first release IRQ, so that we do not get any more interrupts * from this host */ if (pCard->flags & AGTIAPI_IRQ_REQUESTED) { if (!agtiapi_intx_mode) { int i; for (i = 0; i< MAX_MSIX_NUM_VECTOR; i++) { if (pCard->irq[i] != agNULL && pCard->rscID[i] != 0) { bus_teardown_intr(dev, pCard->irq[i], pCard->intrcookie[i]); bus_release_resource( dev, SYS_RES_IRQ, pCard->rscID[i], pCard->irq[i] ); } } pci_release_msi(dev); } pCard->flags &= ~AGTIAPI_IRQ_REQUESTED; #ifdef AGTIAPI_DPC for (i = 0; i < MAX_MSIX_NUM_DPC; i++) tasklet_kill(&pCard->tasklet_dpc[i]); #endif AGTIAPI_PRINTK("agtiapi_ReleaseHBA: IRQ released\n"); } // release memory vs. alloc in agtiapi_alloc_ostimem; used in ostiAllocMemory if( pCard->osti_busaddr != 0 ) { bus_dmamap_unload( pCard->osti_dmat, pCard->osti_mapp ); } if( pCard->osti_mem != NULL ) { bus_dmamem_free( pCard->osti_dmat, pCard->osti_mem, pCard->osti_mapp ); } if( pCard->osti_dmat != NULL ) { bus_dma_tag_destroy( pCard->osti_dmat ); } /* unmap the mapped PCI memory */ /* calls bus_release_resource( ,SYS_RES_MEMORY, ..) */ agtiapi_ReleasePCIMem(thisCardInst); /* release all ccbs */ if (pCard->ccbTotal) { //calls bus_dmamap_destroy() for all pccbs agtiapi_ReleaseCCBs(pCard); AGTIAPI_PRINTK("agtiapi_ReleaseHBA: CCB released\n"); } #ifdef HIALEAH_ENCRYPTION /*release encryption resources - Fix it*/ if(pCard->encrypt) { /*Check that all IO's are completed */ if(atomic_read (&outstanding_encrypted_io_count) > 0) { printf("%s: WARNING: %d outstanding encrypted IOs !\n", __FUNCTION__, atomic_read(&outstanding_encrypted_io_count)); } //agtiapi_CleanupEncryptionPools(pCard); } #endif /* release device list */ if( pCard->pDevList ) { free((caddr_t)pCard->pDevList, M_PMC_MDVT); pCard->pDevList = NULL; AGTIAPI_PRINTK("agtiapi_ReleaseHBA: device list released\n"); } #ifdef LINUX_PERBI_SUPPORT // ## review use of PERBI AGTIAPI_PRINTK( "agtiapi_ReleaseHBA: WWN list %p \n", pCard->pWWNList ); if( pCard->pWWNList ) { free( (caddr_t)pCard->pWWNList, M_PMC_MTGT ); pCard->pWWNList = NULL; AGTIAPI_PRINTK("agtiapi_ReleaseHBA: WWN list released\n"); } if( pCard->pSLRList ) { free( (caddr_t)pCard->pSLRList, M_PMC_MSLR ); pCard->pSLRList = NULL; AGTIAPI_PRINTK("agtiapi_ReleaseHBA: SAS Local Remote list released\n"); } #endif if (pCard->pPortalData) { free((caddr_t)pCard->pPortalData, M_PMC_MPRT); pCard->pPortalData = NULL; AGTIAPI_PRINTK("agtiapi_ReleaseHBA: PortalData released\n"); } //calls contigfree() or free() agtiapi_MemFree(pCardInfo); AGTIAPI_PRINTK("agtiapi_ReleaseHBA: low level resource released\n"); #ifdef HOTPLUG_SUPPORT if (pCard->flags & AGTIAPI_PORT_INITIALIZED) { // agtiapi_FreeDevWorkList(pCard); AGTIAPI_PRINTK("agtiapi_ReleaseHBA: (HP dev) work resources released\n"); } #endif /* * TBD, scsi_unregister may release wrong host data structure * which cause NULL pointer shows up. */ if (pCard->flags & AGTIAPI_SCSI_REGISTERED) { pCard->flags &= ~AGTIAPI_SCSI_REGISTERED; #ifdef AGTIAPI_LOCAL_LOCK if (pCard->STLock) { //destroy mtx int maxLocks; maxLocks = pRscInfo->tiLoLevelResource.loLevelOption.numOfQueuesPerPort; for( i = 0; i < maxLocks; i++ ) { mtx_destroy(&pCard->STLock[i]); } free(pCard->STLock, M_PMC_MSTL); pCard->STLock = NULL; } #endif } ag_card_good--; /* reset agtiapi_1st_time if this is the only card */ if (!ag_card_good && !agtiapi_1st_time) { agtiapi_1st_time = 1; } /* for tiSgl_t memeory */ if (pCard->tisgl_busaddr != 0) { bus_dmamap_unload(pCard->tisgl_dmat, pCard->tisgl_map); } if (pCard->tisgl_mem != NULL) { bus_dmamem_free(pCard->tisgl_dmat, pCard->tisgl_mem, pCard->tisgl_map); } if (pCard->tisgl_dmat != NULL) { bus_dma_tag_destroy(pCard->tisgl_dmat); } if (pCard->buffer_dmat != agNULL) { bus_dma_tag_destroy(pCard->buffer_dmat); } if (pCard->sim != NULL) { mtx_lock(&thisCardInst->pmIOLock); + memset(&csa, 0, sizeof(csa)); xpt_setup_ccb(&csa.ccb_h, pCard->path, 5); csa.ccb_h.func_code = XPT_SASYNC_CB; csa.event_enable = 0; csa.callback = agtiapi_async; csa.callback_arg = pCard; xpt_action((union ccb *)&csa); xpt_free_path(pCard->path); // if (pCard->ccbTotal == 0) if (pCard->ccbTotal <= thisCard) { /* no link up so that simq has not been released. In order to remove cam, we call this. */ xpt_release_simq(pCard->sim, 1); } xpt_bus_deregister(cam_sim_path(pCard->sim)); cam_sim_free(pCard->sim, FALSE); mtx_unlock(&thisCardInst->pmIOLock); } if (pCard->devq != NULL) { cam_simq_free(pCard->devq); } //destroy mtx mtx_destroy( &thisCardInst->pmIOLock ); mtx_destroy( &pCard->sendLock ); mtx_destroy( &pCard->doneLock ); mtx_destroy( &pCard->sendSMPLock ); mtx_destroy( &pCard->doneSMPLock ); mtx_destroy( &pCard->ccbLock ); mtx_destroy( &pCard->devListLock ); mtx_destroy( &pCard->OS_timer_lock ); mtx_destroy( &pCard->devRmTimerLock ); mtx_destroy( &pCard->memLock ); mtx_destroy( &pCard->freezeLock ); destroy_dev( pCard->my_cdev ); memset((void *)pCardInfo, 0, sizeof(ag_card_info_t)); return 0; } // Called during system shutdown after sync static int agtiapi_shutdown( device_t dev ) { AGTIAPI_PRINTK( "agtiapi_shutdown\n" ); return( 0 ); } static int agtiapi_suspend( device_t dev ) // Device suspend routine. { AGTIAPI_PRINTK( "agtiapi_suspend\n" ); return( 0 ); } static int agtiapi_resume( device_t dev ) // Device resume routine. { AGTIAPI_PRINTK( "agtiapi_resume\n" ); return( 0 ); } static device_method_t agtiapi_methods[] = { // Device interface DEVMETHOD( device_probe, agtiapi_probe ), DEVMETHOD( device_attach, agtiapi_attach ), DEVMETHOD( device_detach, agtiapi_ReleaseHBA ), DEVMETHOD( device_shutdown, agtiapi_shutdown ), DEVMETHOD( device_suspend, agtiapi_suspend ), DEVMETHOD( device_resume, agtiapi_resume ), { 0, 0 } }; static devclass_t pmspcv_devclass; static driver_t pmspcv_driver = { "pmspcv", agtiapi_methods, sizeof( struct agtiapi_softc ) }; DRIVER_MODULE( pmspcv, pci, pmspcv_driver, pmspcv_devclass, 0, 0 ); MODULE_DEPEND( pmspcv, cam, 1, 1, 1 ); MODULE_DEPEND( pmspcv, pci, 1, 1, 1 ); #include #include #include #include