static int ValidatePagesContiguous(unsigned virtAddress, unsigned size, unsigned* physBase) { /* Iterate over the pages ensuring they are physically contiguous */ int result = 0; unsigned virtBase = (virtAddress / PAGE_SIZE) * PAGE_SIZE; unsigned offset = virtAddress - virtBase; unsigned range = offset + size; unsigned pageCount = range/PAGE_SIZE + ((range%PAGE_SIZE)?1:0); unsigned lastPhys = 0xffffffff; unsigned thisPage; for (thisPage=0; thisPage<pageCount; thisPage++, virtBase += PAGE_SIZE) { int res; unsigned long phys; /* Perform a Virtual to physical translation of the user address */ res = VirtToPhys((void *)virtBase, &phys); if (res == VTOP_INVALID_ARG) { printk("Page lookup failed for address 0x%08x\n", virtBase); result = -EFAULT; break; } if (lastPhys == 0xffffffff) { lastPhys = phys; *physBase = offset + lastPhys; #ifdef NO_PAGE_CHECK return 0; #endif } else if (phys == (lastPhys + PAGE_SIZE)) { lastPhys += PAGE_SIZE; } else { printk("Page discontinuous virtual 0x%08x, last phys 0x%08x, phys 0x%08x, pageCount %d\n", virtBase, lastPhys, phys, pageCount); result = -EFAULT; break; } } return result; }
/* * ======== WMD_DEH_Notify ======== * DEH error notification function. Informs user about the error. */ void WMD_DEH_Notify(struct DEH_MGR *hDehMgr, u32 ulEventMask, u32 dwErrInfo) { struct DEH_MGR *pDehMgr = (struct DEH_MGR *)hDehMgr; struct WMD_DEV_CONTEXT *pDevContext; u32 memPhysical = 0; u32 HW_MMU_MAX_TLB_COUNT = 31; extern u32 faultAddr; u32 cnt = 0; if (MEM_IsValidHandle(pDehMgr, SIGNATURE)) { printk(KERN_INFO "WMD_DEH_Notify: ********** DEVICE EXCEPTION " "**********\n"); pDevContext = (struct WMD_DEV_CONTEXT *)pDehMgr->hWmdContext; switch (ulEventMask) { case DSP_SYSERROR: /* reset errInfo structure before use */ pDehMgr->errInfo.dwErrMask = DSP_SYSERROR; pDehMgr->errInfo.dwVal1 = 0L; pDehMgr->errInfo.dwVal2 = 0L; pDehMgr->errInfo.dwVal3 = 0L; pDehMgr->errInfo.dwVal1 = dwErrInfo; printk(KERN_ERR "WMD_DEH_Notify: DSP_SYSERROR, errInfo " "= 0x%x\n", dwErrInfo); dump_dl_modules(pDevContext); dump_dsp_stack(pDevContext); break; case DSP_MMUFAULT: /* MMU fault routine should have set err info * structure */ pDehMgr->errInfo.dwErrMask = DSP_MMUFAULT; printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT," "errInfo = 0x%x\n", dwErrInfo); printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, High " "Address = 0x%x\n", (unsigned int)pDehMgr->errInfo.dwVal1); printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, Low " "Address = 0x%x\n", (unsigned int)pDehMgr->errInfo.dwVal2); printk(KERN_INFO "WMD_DEH_Notify: DSP_MMUFAULT, fault " "address = 0x%x\n", (unsigned int)faultAddr); PrintDspTraceBuffer(pDevContext); dump_dl_modules(pDevContext); dummyVaAddr = (u32)MEM_Calloc(sizeof(char) * 0x1000, MEM_PAGED); memPhysical = VirtToPhys(PG_ALIGN_LOW((u32)dummyVaAddr, PG_SIZE_4K)); pDevContext = (struct WMD_DEV_CONTEXT *) pDehMgr->hWmdContext; /* Reset the dynamic mmu index to fixed count if it * exceeds 31. So that the dynmmuindex is always * between the range of standard/fixed entries * and 31. */ if (pDevContext->numTLBEntries > HW_MMU_MAX_TLB_COUNT) { pDevContext->numTLBEntries = pDevContext-> fixedTLBEntries; } HW_MMU_TLBAdd(pDevContext->dwDSPMmuBase, memPhysical, faultAddr, HW_PAGE_SIZE_4KB, 1, &mapAttrs, HW_SET, HW_SET); /* * Send a GP Timer interrupt to DSP * The DSP expects a GP timer interrupt after an * MMU-Fault Request GPTimer */ if (timer) { omap_dm_timer_enable(timer); /* Enable overflow interrupt */ omap_dm_timer_set_int_enable(timer, GPTIMER_IRQ_OVERFLOW); /* * Set counter value to overflow counter after * one tick and start timer */ omap_dm_timer_set_load_start(timer, 0, 0xfffffffe); /* Wait 80us for timer to overflow */ udelay(80); /* Check interrupt status and */ /* wait for interrupt */ cnt = 0; while (!(omap_dm_timer_read_status(timer) & GPTIMER_IRQ_OVERFLOW)) { if (cnt++ >= GPTIMER_IRQ_WAIT_MAX_CNT) { pr_err("%s: GPTimer interrupt" " failed\n", __func__); break; } } } /* Clear MMU interrupt */ HW_MMU_EventAck(pDevContext->dwDSPMmuBase, HW_MMU_TRANSLATION_FAULT); dump_dsp_stack(hDehMgr->hWmdContext); if (timer) omap_dm_timer_disable(timer); break; #ifdef CONFIG_BRIDGE_NTFY_PWRERR case DSP_PWRERROR: /* reset errInfo structure before use */ pDehMgr->errInfo.dwErrMask = DSP_PWRERROR; pDehMgr->errInfo.dwVal1 = 0L; pDehMgr->errInfo.dwVal2 = 0L; pDehMgr->errInfo.dwVal3 = 0L; pDehMgr->errInfo.dwVal1 = dwErrInfo; printk(KERN_ERR "WMD_DEH_Notify: DSP_PWRERROR, errInfo " "= 0x%x\n", dwErrInfo); break; #endif /* CONFIG_BRIDGE_NTFY_PWRERR */ #ifdef CONFIG_BRIDGE_WDT3 case DSP_WDTOVERFLOW: pDehMgr->errInfo.dwErrMask = DSP_WDTOVERFLOW; pDehMgr->errInfo.dwVal1 = 0L; pDehMgr->errInfo.dwVal2 = 0L; pDehMgr->errInfo.dwVal3 = 0L; pr_err("WMD_DEH_Notify: DSP_WDTOVERFLOW \n "); break; #endif default: DBG_Trace(DBG_LEVEL6, "WMD_DEH_Notify: Unknown Error, errInfo = " "0x%x\n", dwErrInfo); break; } /* Filter subsequent notifications when an error occurs */ if (pDevContext->dwBrdState != BRD_ERROR) { NTFY_Notify(pDehMgr->hNtfy, ulEventMask); #ifdef CONFIG_BRIDGE_RECOVERY bridge_recover_schedule(); #endif } /* Set the Board state as ERROR */ pDevContext->dwBrdState = BRD_ERROR; /* Disable all the clocks that were enabled by DSP */ (void)DSP_PeripheralClocks_Disable(pDevContext, NULL); #ifdef CONFIG_BRIDGE_WDT3 /* * Avoid the subsequent WDT if it happens once, * also If MMU fault occurs */ dsp_wdt_enable(false); #endif } }
static long sim_execute_scsi_io(BusLogic *bl, CCB_HEADER *ccbh) { CCB_SCSIIO *ccb; int cdb_len; BL_CCB32 *bl_ccb; BL_PRIV *priv; uint32 priv_phys; uint32 bl_ccb_phys; physical_entry entries[2]; physical_entry *scratch; uint32 tmp; int i,t,req; ccb = (CCB_SCSIIO *) ccbh; #ifdef DEBUG_BUSLOGIC req = atomic_add(&(bl->reqid),1); #endif /* valid cdb len? */ cdb_len = ccb->cam_cdb_len; if (cdb_len != 6 && cdb_len != 10 && cdb_len != 12) { ccb->cam_ch.cam_status = CAM_REQ_INVALID; return B_ERROR; } /* acquire a CCB32 block */ acquire_sem(bl->ccb_count); /* protect the freelist and unchain the CCB32 from it */ acquire_sem(bl->ccb_lock); bl_ccb = bl->first_ccb; bl->first_ccb = bl_ccb->next; release_sem(bl->ccb_lock); bl_ccb_phys = VirtToPhys(bl_ccb); /* get contiguous area for bl_ccb in the private data area */ get_memory_map((void *)ccb->cam_sim_priv, 4096, entries, 2); priv_phys = (uint32) entries[0].address; priv = (BL_PRIV *) ccb->cam_sim_priv; /* copy over the CDB */ if(ccb->cam_ch.cam_flags & CAM_CDB_POINTER) { memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_ptr, cdb_len); } else { memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_bytes, cdb_len); } /* fill out the ccb header */ bl_ccb->direction = BL_CCB_DIR_DEFAULT; bl_ccb->length_cdb = cdb_len; bl_ccb->length_sense = ccb->cam_sense_len; bl_ccb->_reserved1 = bl_ccb->_reserved2 = 0; bl_ccb->target_id = ccb->cam_ch.cam_target_id; bl_ccb->lun_tag = ccb->cam_ch.cam_target_lun & 0x07; bl_ccb->ccb_control = 0; bl_ccb->link_id = 0; bl_ccb->link = 0; bl_ccb->sense = toLE(priv_phys); /* okay, this is really disgusting and could potentially break if physical_entry{} changes format... we use the sg list as a scratchpad. Disgusting, but a start */ scratch = (physical_entry *) priv->sg; if(ccb->cam_ch.cam_flags & CAM_SCATTER_VALID) { /* we're using scatter gather -- things just got trickier */ iovec *iov = (iovec *) ccb->cam_data_ptr; int j,sgcount = 0; /* dprintf("buslogic: sg count = %d\n",ccb->cam_sglist_cnt);*/ /* multiple entries, use SG */ bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG; bl_ccb->data = toLE(priv_phys + 256); /* for each entry in the sglist we were given ... */ for(t=0,i=0; i<ccb->cam_sglist_cnt; i++) { /* map it ... */ get_memory_map(iov[i].iov_base, iov[i].iov_len, &(scratch[sgcount]), MAX_SCATTER - sgcount); /* and make a bl sgentry for each chunk ... */ for(j=sgcount; scratch[j].size && j<MAX_SCATTER; j++) { t += scratch[j].size; sgcount++; dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req, j, (uint32) scratch[j].address, scratch[j].size); tmp = priv->sg[j].length; priv->sg[j].length = toLE(priv->sg[j].phys); priv->sg[j].phys = toLE(tmp); } if(scratch[j].size) panic("egads! sgseg overrun in BusLogic SIM"); } if(t != ccb->cam_dxfer_len) { dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len); ccb->cam_ch.cam_status = CAM_REQ_INVALID; /* put the CCB32 back on the freelist and release our lock */ acquire_sem(bl->ccb_lock); bl_ccb->next = bl->first_ccb; bl->first_ccb = bl_ccb; release_sem(bl->ccb_lock); release_sem(bl->ccb_count); return B_ERROR; } /* total bytes in DataSegList */ bl_ccb->length_data = toLE(sgcount * 8); } else { get_memory_map((void *)ccb->cam_data_ptr, ccb->cam_dxfer_len, scratch, MAX_SCATTER); if(scratch[1].size) { /* multiple entries, use SG */ bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG; bl_ccb->data = toLE(priv_phys + 256); for(t=0,i=0; scratch[i].size && i<MAX_SCATTER; i++) { t += scratch[i].size; dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req, i, (uint32) scratch[i].address, scratch[i].size); tmp = priv->sg[i].length; priv->sg[i].length = toLE(priv->sg[i].phys); priv->sg[i].phys = toLE(tmp); } if(t != ccb->cam_dxfer_len) { dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len); ccb->cam_ch.cam_status = CAM_REQ_INVALID; /* put the CCB32 back on the freelist and release our lock */ acquire_sem(bl->ccb_lock); bl_ccb->next = bl->first_ccb; bl->first_ccb = bl_ccb; release_sem(bl->ccb_lock); release_sem(bl->ccb_count); return B_ERROR; } /* total bytes in DataSegList */ bl_ccb->length_data = toLE(i * 8); } else { bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN; /* single entry, use direct */ t = bl_ccb->length_data = toLE(ccb->cam_dxfer_len); bl_ccb->data = toLE((uint32) scratch[0].address); } } dt_printf("buslogic/%d: targ %d, dxfr %d, scsi op = 0x%02x\n",req, bl_ccb->target_id, t, bl_ccb->cdb[0]); acquire_sem(bl->hw_lock); /* check for box in use state XXX */ bl->out_boxes[bl->out_nextbox].ccb_phys = toLE(bl_ccb_phys); bl->out_boxes[bl->out_nextbox].action_code = BL_ActionCode_Start; bl->out_nextbox++; if(bl->out_nextbox == bl->box_count) bl->out_nextbox = 0; outb(BL_COMMAND_REG, 0x02); #ifndef SERIALIZE_REQS release_sem(bl->hw_lock); #endif /* d_printf("buslogic/%d: CCB %08x (%08xv) waiting on done\n", req, bl_ccb_phys, (uint32) bl_ccb);*/ acquire_sem(bl_ccb->done); /* d_printf("buslogic/%d: CCB %08x (%08xv) done\n", req, bl_ccb_phys, (uint32) bl_ccb);*/ #ifdef SERIALIZE_REQS release_sem(bl->hw_lock); #endif if(bl_ccb->btstat) { /* XXX - error state xlat goes here */ switch(bl_ccb->btstat) { case 0x11: ccb->cam_ch.cam_status = CAM_SEL_TIMEOUT; break; case 0x12: ccb->cam_ch.cam_status = CAM_DATA_RUN_ERR; break; case 0x13: ccb->cam_ch.cam_status = CAM_UNEXP_BUSFREE; break; case 0x22: case 0x23: ccb->cam_ch.cam_status = CAM_SCSI_BUS_RESET; break; case 0x34: ccb->cam_ch.cam_status = CAM_UNCOR_PARITY; break; default: ccb->cam_ch.cam_status = CAM_REQ_INVALID; } dt_printf("buslogic/%d: error stat %02x\n",req,bl_ccb->btstat); } else { dt_printf("buslogic/%d: data %d/%d, sense %d/%d\n", req, bl_ccb->length_data, ccb->cam_dxfer_len, bl_ccb->length_sense, ccb->cam_sense_len); ccb->cam_resid = bl_ccb->length_data; /* under what condition should we do this? */ memcpy(ccb->cam_sense_ptr, priv->sensedata, ccb->cam_sense_len); ccb->cam_scsi_status = bl_ccb->sdstat; if(bl_ccb->sdstat == 02) { ccb->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID; ccb->cam_sense_resid = 0; dt_printf("buslogic/%d: error scsi\n",req); } else { ccb->cam_ch.cam_status = CAM_REQ_CMP; ccb->cam_sense_resid = bl_ccb->length_sense; dt_printf("buslogic/%d: success scsi\n",req); /* put the CCB32 back on the freelist and release our lock */ acquire_sem(bl->ccb_lock); bl_ccb->next = bl->first_ccb; bl->first_ccb = bl_ccb; release_sem(bl->ccb_lock); release_sem(bl->ccb_count); return 0; } } /* put the CCB32 back on the freelist and release our lock */ acquire_sem(bl->ccb_lock); bl_ccb->next = bl->first_ccb; bl->first_ccb = bl_ccb; release_sem(bl->ccb_lock); release_sem(bl->ccb_count); return B_ERROR; }
/* Initialization function for the driver. Only called once. */ void E2Init (PRPINITOUT Req) { int UnitCount; char FAR *pCmdLine; /* Initialize some of the important global variables. */ DevHelp= ((PRPINITIN) Req)->DevHlpEP; /* Get pointer to DevHelp */ pDataSeg= (PVOID) &pDataSeg; /* Get pointer to data seg */ OFFSETOF(pDataSeg)= 0; VirtToPhys (pDataSeg,&ppDataSeg); /* Get the physical address */ /* of the data segment */ for (MountCount= 0; MountCount<MAX_LINUX_PARTITIONS; MountCount++) MountTable[MountCount]= MountCount; /* MountCount= max num of */ /* partitions to mount. */ pCmdLine= ((PRPINITIN) Req)->InitArgs; /* Get command line args */ OFFSETOF(pCmdLine)=(USHORT) ((PDDD_PARM_LIST) pCmdLine)->cmd_line_args; ProcessCmdline (pCmdLine); InitPrint ("Linux partition filter. (C) Deon van der Westhuysen. v1.2\n\r" "Development version (Alpha).\n\r"); InitScanDrivers(); /* Scan for partitions... */ InitGetUnitFS(); /* Determine FS for each unit */ InitSortUnits(); /* Sort the units */ if (MountCount>NumVirtUnits) MountCount =NumVirtUnits; /* Get correct number of */ /* units to be mounted. */ /* Check that each entry points to a valid unit. If not valid, point to */ /* first unit. (Which can only be allocated once, thus one drive letter.) */ for (UnitCount=0;UnitCount<MountCount;UnitCount++) if (MountTable[UnitCount]>=NumVirtUnits) MountTable[UnitCount]= 0; if (!NumVirtUnits) { InitPrint ("No Linux partitions were found: filter not installed."); Req->Unit= 0; Req->CodeEnd= 0; /* No code to keep */ Req->DataEnd= 0; /* No data to keep */ Req->rph.Status= STDON+STERR+ERROR_I24_QUIET_INIT_FAIL; /* Indicate failure */ return; } ADDHandle= RegisterADD (E2FilterIORBWrapper,FILTER_ADD_NAME); /* Register filter */ if (!ADDHandle) /* Check registration */ { InitPrint ("Could't register filter. Installation aborted."); while (NumBaseUnits) InitRemoveBaseUnit(); /* Free all base units */ Req->Unit= 0; Req->CodeEnd= 0; /* No code to keep */ Req->DataEnd= 0; /* No data to keep */ Req->rph.Status= STDON+STERR+ERROR_I24_QUIET_INIT_FAIL; /* Indicate failure */ return; } for (UnitCount= 0; UnitCount<NumBaseUnits; UnitCount++) InitFilterBaseUnit (UnitCount); /* Filter all base units... */ InitPrintVerbose ("Filter installed."); Req->Unit= 0; Req->CodeEnd= ((USHORT)E2Init); /* Pointer to end of code */ Req->DataEnd= ((USHORT)&StartInitData); /* Pointer to end of data */ Req->rph.Status= STDON; /* Everything is OK */ }