Example #1
0
/*
 * Catch an interrupt from the adaptor
 */
static void
ahbintr(void *arg)
{
	struct	  ahb_softc *ahb;
	u_int	  intstat;
	u_int32_t mbox;

	ahb = (struct ahb_softc *)arg;

	while (ahb_inb(ahb, HOSTSTAT) & HOSTSTAT_INTPEND) {
		/*
		 * Fetch information about this interrupt.
		 */
		intstat = ahb_inb(ahb, INTSTAT);
		mbox = ahb_inl(ahb, MBOXIN0);

		/*
		 * Reset interrupt latch.
		 */
		ahb_outb(ahb, CONTROL, CNTRL_CLRINT);

		/*
		 * Process the completed operation
		 */
		switch (intstat & INTSTAT_MASK) {
		case INTSTAT_ECB_OK:
		case INTSTAT_ECB_CMPWRETRY:
		case INTSTAT_ECB_CMPWERR:
			ahbdone(ahb, mbox, intstat);
			break;
		case INTSTAT_AEN_OCCURED:
			if ((intstat & INTSTAT_TARGET_MASK) == ahb->scsi_id) {
				/* Bus Reset */
				xpt_print_path(ahb->path);
				switch (mbox) {
				case HS_SCSI_RESET_ADAPTER:
					printf("Host Adapter Initiated "
					       "Bus Reset occurred\n");
					break;
				case HS_SCSI_RESET_INCOMING:
					printf("Bus Reset Initiated "
					       "by another device occurred\n");
					break;
				}
				/* Notify the XPT */
				xpt_async(AC_BUS_RESET, ahb->path, NULL);
				break;
			}
			printf("Unsupported initiator selection AEN occured\n");
			break;
		case INTSTAT_IMMED_OK:
		case INTSTAT_IMMED_ERR:
			ahbhandleimmed(ahb, mbox, intstat);
			break;
		case INTSTAT_HW_ERR:
			panic("Unrecoverable hardware Error Occurred\n");
		}
	}
}
Example #2
0
/*
 * Update the XPT's idea of the negotiated transfer
 * parameters for a particular target.
 */
static void
ahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts)
{
	setup_data_t	setup_info;
	u_int		target;
	u_int		targ_offset;
	u_int		sync_period;
	int		error;
	uint8_t	param;
	targ_syncinfo_t	sync_info;
	struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;

	target = cts->ccb_h.target_id;
	targ_offset = (target & 0x7);

	/*
	 * Inquire Setup Information.  This command retreives
	 * the sync info for older models.
	 */
	param = sizeof(setup_info);
	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,
	    (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT);

	if (error != 0) {
		device_printf(aha->dev,
		    "ahafetchtransinfo - Inquire Setup Info Failed %d\n",
		    error);
		return;
	}

	sync_info = setup_info.syncinfo[targ_offset];

	if (sync_info.sync == 0)
		spi->sync_offset = 0;
	else
		spi->sync_offset = sync_info.offset;

	spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;

	if (aha->boardid >= BOARD_1542CF)
		sync_period = 1000;
	else
		sync_period = 2000;
	sync_period += 500 * sync_info.period;

	/* Convert ns value to standard SCSI sync rate */
	if (spi->sync_offset != 0)
		spi->sync_period = scsi_calc_syncparam(sync_period);
	else
		spi->sync_period = 0;

	spi->valid = CTS_SPI_VALID_SYNC_RATE
		   | CTS_SPI_VALID_SYNC_OFFSET
		   | CTS_SPI_VALID_BUS_WIDTH;
        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);
}
Example #3
0
int
aha_detach(struct aha_softc *aha)
{
	mtx_lock(&aha->lock);
	xpt_async(AC_LOST_DEVICE, aha->path, NULL);
	xpt_free_path(aha->path);
	xpt_bus_deregister(cam_sim_path(aha->sim));
	cam_sim_free(aha->sim, /*free_devq*/TRUE);
	mtx_unlock(&aha->lock);
	/* XXX: Drain all timers? */
	return (0);
}
Example #4
0
void
ic_destroy(isc_session_t *sp )
{
     debug_called(8);

     if(sp->cam_path != NULL) {
	  sdebug(2, "name=%s unit=%d",
		 cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim));
	  CAM_LOCK(sp);
#if 0
	  xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL);
#else
	  xpt_async(XPT_RESET_BUS, sp->cam_path, NULL);
#endif
	  xpt_free_path(sp->cam_path);
	  xpt_bus_deregister(cam_sim_path(sp->cam_sim));
	  cam_sim_free(sp->cam_sim, TRUE /*free_devq*/);

	  CAM_UNLOCK(sp);
	  sdebug(2, "done");
     }
}
Example #5
0
static void
nvme_sim_controller_fail(void *ctrlr_arg)
{
	struct nvme_sim_softc *sc = ctrlr_arg;
	struct nvme_controller *ctrlr = sc->s_ctrlr;

	mtx_lock(&ctrlr->lock);
	xpt_async(AC_LOST_DEVICE, sc->s_path, NULL);
	xpt_free_path(sc->s_path);
	xpt_bus_deregister(cam_sim_path(sc->s_sim));
	cam_sim_free(sc->s_sim, /*free_devq*/TRUE);
	mtx_unlock(&ctrlr->lock);
	free(sc, M_NVME);
}
Example #6
0
void
ic_lost_target(isc_session_t *sp, int target)
{
     debug_called(8);
     sdebug(2, "lost target=%d", target);

     if(sp->cam_path != NULL) {
	  mtx_lock(&sp->cam_mtx);
	  xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL);
	  xpt_free_path(sp->cam_path);
	  mtx_unlock(&sp->cam_mtx);
	  sp->cam_path = 0; // XXX
     }
}
Example #7
0
/*
 * The state of the port has changed.
 *
 * If atx is NULL the physical port has changed state.
 * If atx is non-NULL a particular target behind a PM has changed state.
 *
 * If found is -1 the target state must be queued to a non-interrupt context.
 * (only works with at == NULL).
 *
 * If found is 0 the target was removed.
 * If found is 1 the target was inserted.
 */
void
ahci_cam_changed(struct ahci_port *ap, struct ata_port *atx, int found)
{
	struct cam_path *tmppath;
	int status;
	int target;

	target = atx ? atx->at_target : CAM_TARGET_WILDCARD;

	if (ap->ap_sim == NULL)
		return;
	if (found == CAM_TARGET_WILDCARD) {
		status = xpt_create_path(&tmppath, NULL,
					 cam_sim_path(ap->ap_sim),
					 target, CAM_LUN_WILDCARD);
		if (status != CAM_REQ_CMP)
			return;
		ahci_cam_rescan(ap);
	} else {
		status = xpt_create_path(&tmppath, NULL,
					 cam_sim_path(ap->ap_sim),
					 target,
					 CAM_LUN_WILDCARD);
		if (status != CAM_REQ_CMP)
			return;
#if 0
		/*
		 * This confuses CAM
		 */
		if (found)
			xpt_async(AC_FOUND_DEVICE, tmppath, NULL);
		else
			xpt_async(AC_LOST_DEVICE, tmppath, NULL);
#endif
	}
	xpt_free_path(tmppath);
}
Example #8
0
static int
aac_cam_detach(device_t dev)
{
    struct aac_softc *sc;
    struct aac_cam *camsc;
    fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");

    camsc = (struct aac_cam *)device_get_softc(dev);
    sc = camsc->inf->aac_sc;

    mtx_lock(&sc->aac_io_lock);

    xpt_async(AC_LOST_DEVICE, camsc->path, NULL);
    xpt_free_path(camsc->path);
    xpt_bus_deregister(cam_sim_path(camsc->sim));
    cam_sim_free(camsc->sim, /*free_devq*/TRUE);

    mtx_unlock(&sc->aac_io_lock);

    return (0);
}
Example #9
0
static void
pmponinvalidate(struct cam_periph *periph)
{
	struct cam_path *dpath;
	int i;

	/*
	 * De-register any async callbacks.
	 */
	xpt_register_async(0, pmpasync, periph, periph->path);

	for (i = 0; i < 15; i++) {
		if (xpt_create_path(&dpath, periph,
		    xpt_path_path_id(periph->path),
		    i, 0) == CAM_REQ_CMP) {
			xpt_async(AC_LOST_DEVICE, dpath, NULL);
			xpt_free_path(dpath);
		}
	}
	pmprelease(periph, -1);
}
Example #10
0
int
ata_detach(device_t dev)
{
    struct ata_channel *ch = device_get_softc(dev);

    /* check that we have a valid channel to detach */
    if (!ch->r_irq)
	return ENXIO;

    /* grap the channel lock so no new requests gets launched */
    mtx_lock(&ch->state_mtx);
    ch->state |= ATA_STALL_QUEUE;
    mtx_unlock(&ch->state_mtx);
    if (ch->flags & ATA_PERIODIC_POLL)
	callout_drain(&ch->poll_callout);

    taskqueue_drain(taskqueue_thread, &ch->conntask);

	mtx_lock(&ch->state_mtx);
	xpt_async(AC_LOST_DEVICE, ch->path, NULL);
	xpt_free_path(ch->path);
	xpt_bus_deregister(cam_sim_path(ch->sim));
	cam_sim_free(ch->sim, /*free_devq*/TRUE);
	ch->sim = NULL;
	mtx_unlock(&ch->state_mtx);

    /* release resources */
    bus_teardown_intr(dev, ch->r_irq, ch->ih);
    bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
    ch->r_irq = NULL;

    /* free DMA resources if DMA HW present*/
    if (ch->dma.free)
	ch->dma.free(dev);

    mtx_destroy(&ch->state_mtx);
    return 0;
}
Example #11
0
int
ata_reinit(device_t dev)
{
    struct ata_channel *ch = device_get_softc(dev);
    struct ata_request *request;

	xpt_freeze_simq(ch->sim, 1);
	if ((request = ch->running)) {
		ch->running = NULL;
		if (ch->state == ATA_ACTIVE)
		    ch->state = ATA_IDLE;
		callout_stop(&request->callout);
		if (ch->dma.unload)
		    ch->dma.unload(request);
		request->result = ERESTART;
		ata_cam_end_transaction(dev, request);
	}
	/* reset the controller HW, the channel and device(s) */
	ATA_RESET(dev);
	/* Tell the XPT about the event */
	xpt_async(AC_BUS_RESET, ch->path, NULL);
	xpt_release_simq(ch->sim, TRUE);
	return(0);
}
Example #12
0
static int
ahci_em_detach(device_t dev)
{
	struct ahci_enclosure *enc = device_get_softc(dev);
	int i;

	for (i = 0; i < enc->channels * AHCI_NUM_LEDS; i++) {
		if (enc->leds[i].led)
			led_destroy(enc->leds[i].led);
	}
	mtx_lock(&enc->mtx);
	xpt_async(AC_LOST_DEVICE, enc->path, NULL);
	xpt_free_path(enc->path);
	xpt_bus_deregister(cam_sim_path(enc->sim));
	cam_sim_free(enc->sim, /*free_devq*/TRUE);
	mtx_unlock(&enc->mtx);

	bus_release_resource(dev, SYS_RES_MEMORY, 0, enc->r_memc);
	bus_release_resource(dev, SYS_RES_MEMORY, 1, enc->r_memt);
	if (enc->r_memr)
		bus_release_resource(dev, SYS_RES_MEMORY, 2, enc->r_memr);
	mtx_destroy(&enc->mtx);
	return (0);
}
Example #13
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;
	}
}
Example #14
0
static int
ahareset(struct aha_softc* aha, int hard_reset)
{
	struct	 ccb_hdr *ccb_h;
	u_int	 status;
	u_int	 timeout;
	uint8_t reset_type;

	if (hard_reset != 0)
		reset_type = HARD_RESET;
	else
		reset_type = SOFT_RESET;
	aha_outb(aha, CONTROL_REG, reset_type);

	/* Wait 5sec. for Diagnostic start */
	timeout = 5 * 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & DIAG_ACTIVE) != 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		PRVERB((aha->dev, "ahareset - Diagnostic Active failed to "
		    "assert. status = %#x\n", status));
		return (ETIMEDOUT);
	}

	/* Wait 10sec. for Diagnostic end */
	timeout = 10 * 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & DIAG_ACTIVE) == 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		panic("%s: ahareset - Diagnostic Active failed to drop. "
		    "status = 0x%x\n", aha_name(aha), status);
		return (ETIMEDOUT);
	}

	/* Wait for the host adapter to become ready or report a failure */
	timeout = 10000;
	while (--timeout) {
		status = aha_inb(aha, STATUS_REG);
		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
			break;
		DELAY(100);
	}
	if (timeout == 0) {
		device_printf(aha->dev, "ahareset - Host adapter failed to "
		    "come ready. status = 0x%x\n", status);
		return (ETIMEDOUT);
	}

	/* If the diagnostics failed, tell the user */
	if ((status & DIAG_FAIL) != 0
	 || (status & HA_READY) == 0) {
		device_printf(aha->dev, "ahareset - Adapter failed diag\n");

		if ((status & DATAIN_REG_READY) != 0)
			device_printf(aha->dev, "ahareset - Host Adapter "
			    "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG));
		return (ENXIO);
	}

	/* If we've attached to the XPT, tell it about the event */
	if (aha->path != NULL)
		xpt_async(AC_BUS_RESET, aha->path, NULL);

	/*
	 * Perform completion processing for all outstanding CCBs.
	 */
	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
		struct aha_ccb *pending_accb;

		pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
		pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
		ahadone(aha, pending_accb, AMBI_ERROR);
	}

	/* If we've allocated mailboxes, initialize them */
	/* Must be done after we've aborted our queue, or aha_cmd fails */
	if (aha->init_level > 4)
		ahainitmboxes(aha);

	return (0);
}
Example #15
0
static void
ahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code)
{
	union  ccb	  *ccb;
	struct ccb_scsiio *csio;

	ccb = accb->ccb;
	csio = &accb->ccb->csio;

	if ((accb->flags & ACCB_ACTIVE) == 0) {
		device_printf(aha->dev, 
		    "ahadone - Attempt to free non-active ACCB %p\n",
		    (void *)accb);
		return;
	}

	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		bus_dmasync_op_t op;

		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
			op = BUS_DMASYNC_POSTREAD;
		else
			op = BUS_DMASYNC_POSTWRITE;
		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
		bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
	}

	if (accb == aha->recovery_accb) {
		/*
		 * The recovery ACCB does not have a CCB associated
		 * with it, so short circuit the normal error handling.
		 * We now traverse our list of pending CCBs and process
		 * any that were terminated by the recovery CCBs action.
		 * We also reinstate timeouts for all remaining, pending,
		 * CCBs.
		 */
		struct cam_path *path;
		struct ccb_hdr *ccb_h;
		cam_status error;

		/* Notify all clients that a BDR occurred */
		error = xpt_create_path(&path, /*periph*/NULL,
		    cam_sim_path(aha->sim), accb->hccb.target,
		    CAM_LUN_WILDCARD);

		if (error == CAM_REQ_CMP) {
			xpt_async(AC_SENT_BDR, path, NULL);
			xpt_free_path(path);
		}

		ccb_h = LIST_FIRST(&aha->pending_ccbs);
		while (ccb_h != NULL) {
			struct aha_ccb *pending_accb;

			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
			if (pending_accb->hccb.target == accb->hccb.target) {
				pending_accb->hccb.ahastat = AHASTAT_HA_BDR;
				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
				ahadone(aha, pending_accb, AMBI_ERROR);
			} else {
				callout_reset_sbt(&pending_accb->timer,
				    SBT_1MS * ccb_h->timeout, 0, ahatimeout,
				    pending_accb, 0);
				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
			}
		}
		device_printf(aha->dev, "No longer in timeout\n");
		return;
	}

	callout_stop(&accb->timer);

	switch (comp_code) {
	case AMBI_FREE:
		device_printf(aha->dev,
		    "ahadone - CCB completed with free status!\n");
		break;
	case AMBI_NOT_FOUND:
		device_printf(aha->dev,
		    "ahadone - CCB Abort failed to find CCB\n");
		break;
	case AMBI_ABORT:
	case AMBI_ERROR:
		/* An error occurred */
		if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
			csio->resid = 0;
		else
			csio->resid = aha_a24tou(accb->hccb.data_len);
		switch(accb->hccb.ahastat) {
		case AHASTAT_DATARUN_ERROR:
		{
			if (csio->resid <= 0) {
				csio->ccb_h.status = CAM_DATA_RUN_ERR;
				break;
			}
			/* FALLTHROUGH */
		}
		case AHASTAT_NOERROR:
			csio->scsi_status = accb->hccb.sdstat;
			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
			switch(csio->scsi_status) {
			case SCSI_STATUS_CHECK_COND:
			case SCSI_STATUS_CMD_TERMINATED:
				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
				/*
				 * The aha writes the sense data at different
				 * offsets based on the scsi cmd len
				 */
				bcopy((caddr_t) &accb->hccb.scsi_cdb +
				    accb->hccb.cmd_len,
				    (caddr_t) &csio->sense_data,
				    accb->hccb.sense_len);
				break;
			default:
				break;
			case SCSI_STATUS_OK:
				csio->ccb_h.status = CAM_REQ_CMP;
				break;
			}
			break;
		case AHASTAT_SELTIMEOUT:
			csio->ccb_h.status = CAM_SEL_TIMEOUT;
			break;
		case AHASTAT_UNEXPECTED_BUSFREE:
			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
			break;
		case AHASTAT_INVALID_PHASE:
			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
			break;
		case AHASTAT_INVALID_ACTION_CODE:
			panic("%s: Inavlid Action code", aha_name(aha));
			break;
		case AHASTAT_INVALID_OPCODE:
			if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
				panic("%s: Invalid CCB Opcode %x hccb = %p",
				    aha_name(aha), accb->hccb.opcode,
				    &accb->hccb);
			device_printf(aha->dev,
			    "AHA-1540A compensation failed\n");
			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
			csio->ccb_h.status = CAM_REQUEUE_REQ;
			break;
		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
			/* We don't even support linked commands... */
			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
			break;
		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
			panic("%s: Invalid CCB or SG list", aha_name(aha));
			break;
		case AHASTAT_HA_SCSI_BUS_RESET:
			if ((csio->ccb_h.status & CAM_STATUS_MASK)
			    != CAM_CMD_TIMEOUT)
				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
			break;
		case AHASTAT_HA_BDR:
			if ((accb->flags & ACCB_DEVICE_RESET) == 0)
				csio->ccb_h.status = CAM_BDR_SENT;
			else
				csio->ccb_h.status = CAM_CMD_TIMEOUT;
			break;
		}
		if (csio->ccb_h.status != CAM_REQ_CMP) {
			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
			csio->ccb_h.status |= CAM_DEV_QFRZN;
		}
		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		break;
	case AMBI_OK:
		/* All completed without incident */
		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
		/* I don't think so since it works???? */
		ccb->ccb_h.status |= CAM_REQ_CMP;
		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		break;
	}
}
Example #16
0
static void
ahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
{
	struct hardware_ecb *hecb;
	struct ecb_status *status;

	hecb = &ecb->hecb;
	status = &ecb->status;
	switch (status->ha_status) {
	case HS_OK:
		ccb->csio.scsi_status = status->scsi_status;
		if (status->scsi_status != 0) {
			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
			if (status->sense_stored) {
				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
				ccb->csio.sense_resid =
				    ccb->csio.sense_len - status->sense_len;
				bcopy(&ecb->sense, &ccb->csio.sense_data,
				      status->sense_len);
			}
		}
		break;
	case HS_TARGET_NOT_ASSIGNED:
		ccb->ccb_h.status = CAM_PATH_INVALID;
		break;
	case HS_SEL_TIMEOUT:
		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
		break;
	case HS_DATA_RUN_ERR:
		ahbcalcresid(ahb, ecb, ccb);
		break;
	case HS_UNEXPECTED_BUSFREE:
		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
		break;
	case HS_INVALID_PHASE:
		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
		break;
	case HS_REQUEST_SENSE_FAILED:
		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
		break;
	case HS_TAG_MSG_REJECTED:
	{
		struct ccb_trans_settings neg; 
		struct ccb_trans_settings_scsi *scsi = &neg.proto_specific.scsi;

		xpt_print_path(ccb->ccb_h.path);
		printf("refuses tagged commands.  Performing "
		       "non-tagged I/O\n");
		memset(&neg, 0, sizeof (neg));
		neg.protocol = PROTO_SCSI;
		neg.protocol_version = SCSI_REV_2;
		neg.transport = XPORT_SPI;
		neg.transport_version = 2;
		scsi->flags = CTS_SCSI_VALID_TQ;
		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 
		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
		break;
	}
	case HS_FIRMWARE_LOAD_REQ:
	case HS_HARDWARE_ERR:
		/*
		 * Tell the system that the Adapter
		 * is no longer functional.
		 */
		ccb->ccb_h.status = CAM_NO_HBA;
		break;
	case HS_CMD_ABORTED_HOST:
	case HS_CMD_ABORTED_ADAPTER:
	case HS_ATN_TARGET_FAILED:
	case HS_SCSI_RESET_ADAPTER:
	case HS_SCSI_RESET_INCOMING:
		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
		break;
	case HS_INVALID_ECB_PARAM:
		printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
			ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2);	
		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
		break;
	case HS_DUP_TCB_RECEIVED:
	case HS_INVALID_OPCODE:
	case HS_INVALID_CMD_LINK:
	case HS_PROGRAM_CKSUM_ERROR:
		panic("ahb%ld: Can't happen host status %x occurred",
		      ahb->unit, status->ha_status);
		break;
	}
	if (ccb->ccb_h.status != CAM_REQ_CMP) {
		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
}