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

	}
}
Beispiel #3
0
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;
}
Beispiel #4
0
/* 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 */
}