/*********************************************************** Function Name: Exec_writeEventFifo Function Description: This function is responsible for writing a single event to the event fifo and updating the appropriate pointers. Inputs: data - the byte to write to the Fifo Outputs: none ***********************************************************/ void Exec_writeEventFifo(unsigned char event) { unsigned char tmpHead; DISABLE_INTS(); Exec_eventFifo[Exec_eventFifoHead] = event; /* now move the head up */ tmpHead = (Exec_eventFifoHead + 1) & (EXEC_EVENT_FIFO_MASK); Exec_eventFifoHead = tmpHead; ENABLE_INTS(); }
/*********************************************************** Function Name: Exec_readEventFifo Function Description: This function is responsible for reading a single event out of the event fifo. Inputs: none Outputs: unsigned char-the data read ***********************************************************/ static unsigned char Exec_readEventFifo(void) { unsigned char dataByte, tmpTail; DISABLE_INTS(); /* just return the current tail from the tx fifo */ dataByte = Exec_eventFifo[Exec_eventFifoTail]; tmpTail = (Exec_eventFifoTail+1) & (EXEC_EVENT_FIFO_MASK); Exec_eventFifoTail = tmpTail; ENABLE_INTS(); return(dataByte); }
//---------------------------------------------------------- // Main entry point //---------------------------------------------------------- int main(void) { initSystem(); // ------------------------------------------ #ifdef USE_THREADS MESSAGE("Using threads"); // never returns startThreads(appMain, systemMain); // if we're here, something went wrong ASSERT(!"systemMain returned?!"); // ------------------------------------------ #else ENABLE_INTS(); #ifdef USE_PROTOTHREADS startProtoSched(); #else MESSAGE("Not using threads"); appMain(); #endif // // Do not allow to return from this function. The reason: // GCC 4.5+ disables interrupts after completion of main() function, // but MansOS applications may want to return from appMain() // and do all the "real work" in interrupt handlers. // Therefore, interrupts must be kept enabled. // for (;;) {} #endif // USE_THREADS return 0; }
static void isp_action(struct cam_sim *sim, union ccb *ccb) { int s, tgt, error; struct ispsoftc *isp; struct ccb_trans_settings *cts; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); isp = (struct ispsoftc *)cam_sim_softc(sim); ccb->ccb_h.sim_priv.entries[0].field = 0; ccb->ccb_h.sim_priv.entries[1].ptr = isp; /* * This should only happen for Fibre Channel adapters. * We want to pass through all but XPT_SCSI_IO (e.g., * path inquiry) but fail if we can't get good Fibre * Channel link status. */ if (ccb->ccb_h.func_code == XPT_SCSI_IO && isp->isp_state != ISP_RUNSTATE) { s = splcam(); DISABLE_INTS(isp); isp_init(isp); if (isp->isp_state != ISP_INITSTATE) { (void) splx(s); /* * Lie. Say it was a selection timeout. */ ccb->ccb_h.status = CAM_SEL_TIMEOUT; xpt_done(ccb); return; } isp->isp_state = ISP_RUNSTATE; ENABLE_INTS(isp); (void) splx(s); } IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name, ccb->ccb_h.func_code)); switch (ccb->ccb_h.func_code) { case XPT_SCSI_IO: /* Execute the requested I/O operation */ /* * Do a couple of preliminary checks... */ if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } } if (isp->isp_type & ISP_HA_SCSI) { if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) { ccb->ccb_h.status = CAM_PATH_INVALID; } else if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(7, 55, 0)) { /* * Too much breakage. */ #if 0 if (ccb->ccb_h.target_lun > 31) { ccb->ccb_h.status = CAM_PATH_INVALID; } #else if (ccb->ccb_h.target_lun > 7) { ccb->ccb_h.status = CAM_PATH_INVALID; } #endif } else if (ccb->ccb_h.target_lun > 7) { ccb->ccb_h.status = CAM_PATH_INVALID; } } else { if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) { ccb->ccb_h.status = CAM_PATH_INVALID; #ifdef SCCLUN } else if (ccb->ccb_h.target_lun > 15) { ccb->ccb_h.status = CAM_PATH_INVALID; #else } else if (ccb->ccb_h.target_lun > 65535) { ccb->ccb_h.status = CAM_PATH_INVALID; #endif } } if (ccb->ccb_h.status == CAM_PATH_INVALID) { printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n", isp->isp_name, ccb->ccb_h.target_id, ccb->ccb_h.target_lun); xpt_done(ccb); break; } s = splcam(); DISABLE_INTS(isp); switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) { case CMD_QUEUED: ccb->ccb_h.status |= CAM_SIM_QUEUED; break; case CMD_EAGAIN: if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE)) { xpt_freeze_simq(sim, 1); isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; } ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQUEUE_REQ; xpt_done(ccb); break; case CMD_COMPLETE: /* * Just make sure that we didn't get it returned * as completed, but with the request still in * progress. In theory, 'cannot happen'. */ if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_CMP_ERR; } xpt_done(ccb); break; } ENABLE_INTS(isp); splx(s); break; case XPT_EN_LUN: /* Enable LUN as a target */ case XPT_TARGET_IO: /* Execute target I/O request */ case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; case XPT_RESET_DEV: /* BDR the specified SCSI device */ tgt = ccb->ccb_h.target_id; /* XXX: Which Bus? */ s = splcam(); error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); (void) splx(s); if (error) { ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else { ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); break; case XPT_ABORT: /* Abort the specified CCB */ s = splcam(); error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); (void) splx(s); if (error) { ccb->ccb_h.status = CAM_REQ_CMP_ERR; } else { ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); break; case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ cts = &ccb->cts; tgt = cts->ccb_h.target_id; s = splcam(); if (isp->isp_type & ISP_HA_FC) { ; /* nothing to change */ } else { sdparam *sdp = isp->isp_param; u_int16_t *dptr; int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); sdp += bus; #if 0 if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) dptr = &sdp->isp_devparam[tgt].cur_dflags; else dptr = &sdp->isp_devparam[tgt].dev_flags; #else /* * We always update (internally) from dev_flags * so any request to change settings just gets * vectored to that location. */ dptr = &sdp->isp_devparam[tgt].dev_flags; #endif /* * Note that these operations affect the * the goal flags (dev_flags)- not * the current state flags. Then we mark * things so that the next operation to * this HBA will cause the update to occur. */ if (cts->valid & CCB_TRANS_DISC_VALID) { if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { *dptr |= DPARM_DISC; } else { *dptr &= ~DPARM_DISC; } } if (cts->valid & CCB_TRANS_TQ_VALID) { if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { *dptr |= DPARM_TQING; } else { *dptr &= ~DPARM_TQING; } } if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { switch (cts->bus_width) { case MSG_EXT_WDTR_BUS_16_BIT: *dptr |= DPARM_WIDE; break; default: *dptr &= ~DPARM_WIDE; } } /* * Any SYNC RATE of nonzero and SYNC_OFFSET * of nonzero will cause us to go to the * selected (from NVRAM) maximum value for * this device. At a later point, we'll * allow finer control. */ if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && (cts->sync_offset > 0)) { *dptr |= DPARM_SYNC; } else { *dptr &= ~DPARM_SYNC; } if (bootverbose || isp->isp_dblev >= 3) printf("%s: %d.%d set %s period 0x%x offset " "0x%x flags 0x%x\n", isp->isp_name, bus, tgt, (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? "current" : "user", sdp->isp_devparam[tgt].sync_period, sdp->isp_devparam[tgt].sync_offset, sdp->isp_devparam[tgt].dev_flags); s = splcam(); sdp->isp_devparam[tgt].dev_update = 1; isp->isp_update |= (1 << bus); (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); (void) splx(s); } (void) splx(s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; case XPT_GET_TRAN_SETTINGS: cts = &ccb->cts; tgt = cts->ccb_h.target_id; if (isp->isp_type & ISP_HA_FC) { /* * a lot of normal SCSI things don't make sense. */ cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; /* * How do you measure the width of a high * speed serial bus? Well, in bytes. * * Offset and period make no sense, though, so we set * (above) a 'base' transfer speed to be gigabit. */ cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; } else { sdparam *sdp = isp->isp_param; u_int16_t dval, pval, oval; int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); sdp += bus; if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) { s = splcam(); /* * First do a refresh to see if things * have changed recently! */ sdp->isp_devparam[tgt].dev_refresh = 1; isp->isp_update |= (1 << bus); (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); (void) splx(s); dval = sdp->isp_devparam[tgt].cur_dflags; oval = sdp->isp_devparam[tgt].cur_offset; pval = sdp->isp_devparam[tgt].cur_period; } else { dval = sdp->isp_devparam[tgt].dev_flags; oval = sdp->isp_devparam[tgt].sync_offset; pval = sdp->isp_devparam[tgt].sync_period; } s = splcam(); cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); if (dval & DPARM_DISC) { cts->flags |= CCB_TRANS_DISC_ENB; } if (dval & DPARM_TQING) { cts->flags |= CCB_TRANS_TAG_ENB; } if (dval & DPARM_WIDE) { cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; } else { cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; } cts->valid = CCB_TRANS_BUS_WIDTH_VALID | CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; if ((dval & DPARM_SYNC) && oval != 0) { cts->sync_period = pval; cts->sync_offset = oval; cts->valid |= CCB_TRANS_SYNC_RATE_VALID | CCB_TRANS_SYNC_OFFSET_VALID; } splx(s); if (bootverbose || isp->isp_dblev >= 3) printf("%s: %d.%d get %s period 0x%x offset " "0x%x flags 0x%x\n", isp->isp_name, bus, tgt, (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? "current" : "user", pval, oval, dval); } ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; case XPT_CALC_GEOMETRY: { struct ccb_calc_geometry *ccg; u_int32_t secs_per_cylinder; u_int32_t size_mb; ccg = &ccb->ccg; if (ccg->block_size == 0) { printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n", isp->isp_name, ccg->ccb_h.target_id, ccg->ccb_h.target_lun); ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); if (size_mb > 1024) { ccg->heads = 255; ccg->secs_per_track = 63; } else { ccg->heads = 64; ccg->secs_per_track = 32; } secs_per_cylinder = ccg->heads * ccg->secs_per_track; ccg->cylinders = ccg->volume_size / secs_per_cylinder; ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } case XPT_RESET_BUS: /* Reset the specified bus */ tgt = cam_sim_bus(sim); s = splcam(); error = isp_control(isp, ISPCTL_RESET_BUS, &tgt); (void) splx(s); if (error) ccb->ccb_h.status = CAM_REQ_CMP_ERR; else { if (cam_sim_bus(sim) && isp->isp_path2 != NULL) xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); else if (isp->isp_path != NULL) xpt_async(AC_BUS_RESET, isp->isp_path, NULL); ccb->ccb_h.status = CAM_REQ_CMP; } xpt_done(ccb); break; case XPT_TERM_IO: /* Terminate the I/O process */ /* Does this need to be implemented? */ ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; case XPT_PATH_INQ: /* Path routing inquiry */ { struct ccb_pathinq *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_eng_cnt = 0; if (IS_FC(isp)) { cpi->hba_misc = PIM_NOBUSRESET; cpi->max_target = MAX_FC_TARG-1; cpi->initiator_id = ((fcparam *)isp->isp_param)->isp_loopid; #ifdef SCCLUN cpi->max_lun = (1 << 16) - 1; #else cpi->max_lun = (1 << 4) - 1; #endif /* * Set base transfer capabilities for Fibre Channel. * Technically not correct because we don't know * what media we're running on top of- but we'll * look good if we always say 100MB/s. */ cpi->base_transfer_speed = 100000; } else { sdparam *sdp = isp->isp_param; sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); cpi->hba_misc = 0; cpi->initiator_id = sdp->isp_initiator_id; cpi->max_target = MAX_TARGETS-1; if (ISP_FW_REVX(isp->isp_fwrev) >= ISP_FW_REV(7, 55, 0)) { #if 0 /* * Too much breakage. */ cpi->max_lun = (1 << 5) - 1; #else cpi->max_lun = (1 << 3) - 1; #endif } else { cpi->max_lun = (1 << 3) - 1; } cpi->base_transfer_speed = 3300; } cpi->bus_id = cam_sim_bus(sim); strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; } default: ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); break; } }
/*********************************************************** Function Name: Exec_run Function Description: This function is responsible for running the main control loop. The control loop is based on checking both the fast-event bitmask (for high priority events) and the event FIFO to determine if an event needs to be handled. The event is then dispatched to the appropriate handler. Inputs: none Outputs: none ***********************************************************/ void Exec_run(void) { unsigned char eventGenerated; while(1) { if (fastEventBitmask) { /* an event needing fast processing has been received */ /* a received line needs to be processed...this needs to be processed as quickly as possible */ if (fastEventBitmask & FEV_ACQUIRE_LINE_COMPLETE) { DISABLE_INTS(); fastEventBitmask &= ~FEV_ACQUIRE_LINE_COMPLETE; ENABLE_INTS(); FrameMgr_processLine(); /* also check if serial data needs to be sent out through UIMgr */ UIMgr_transmitPendingData(); /* we can't just call acquire line again here, since we don't know if we need to acquire another line or not (it depends on the FrameMgr to figure this out) */ } if (fastEventBitmask & FEV_PROCESS_LINE_COMPLETE) { DISABLE_INTS(); fastEventBitmask &= ~FEV_PROCESS_LINE_COMPLETE; ENABLE_INTS(); FrameMgr_acquireLine(); } } if (IS_DATA_IN_EVENT_FIFO() == TRUE) { eventGenerated = Exec_readEventFifo(); switch(eventGenerated) { case (EV_DUMP_FRAME): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_ENABLE_TRACKING): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_DISABLE_TRACKING): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_ACQUIRE_LINE_COMPLETE): FrameMgr_dispatchEvent(eventGenerated); UIMgr_dispatchEvent(eventGenerated); break; case (EV_ACQUIRE_FRAME_COMPLETE): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_PROCESS_LINE_COMPLETE): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_PROCESS_FRAME_COMPLETE): FrameMgr_dispatchEvent(eventGenerated); break; case (EV_SERIAL_DATA_RECEIVED): UIMgr_dispatchEvent(eventGenerated); FrameMgr_dispatchEvent(eventGenerated); break; case (EV_SERIAL_DATA_PENDING_TX): UIMgr_dispatchEvent(eventGenerated); break; default: break; } } /* toggle the debug line */ } }