isp_freebsd.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,209 行 · 第 1/3 页

C
1,209
字号
/* $Id: isp_freebsd.c,v 1.10.2.3 1999/05/12 23:26:41 mjacob Exp $ *//* release_5_11_99 *//* * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. * *--------------------------------------- * Copyright (c) 1997, 1998 by Matthew Jacob * NASA/Ames Research Center * 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 immediately at the beginning of the file, without modification, *    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. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * 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 <dev/isp/isp_freebsd.h>#if	__FreeBSD_version >= 300004static void isp_cam_async __P((void *, u_int32_t, struct cam_path *, void *));static void isp_poll __P((struct cam_sim *));static void isp_action __P((struct cam_sim *, union ccb *));voidisp_attach(struct ispsoftc *isp){	int primary, secondary;	struct ccb_setasync csa;	struct cam_devq *devq;	struct cam_sim *sim;	struct cam_path *path;	/*	 * Establish (in case of 12X0) which bus is the primary.	 */	primary = 0;	secondary = 1;	/*	 * Create the device queue for our SIM(s).	 */	devq = cam_simq_alloc(MAXISPREQUEST);	if (devq == NULL) {		return;	}	/*	 * Construct our SIM entry.	 */	sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,	    isp->isp_unit, 1, MAXISPREQUEST, devq);	if (sim == NULL) {		cam_simq_free(devq);		return;	}	if (xpt_bus_register(sim, primary) != CAM_SUCCESS) {		cam_sim_free(sim, TRUE);		return;	}	if (xpt_create_path(&path, NULL, cam_sim_path(sim),	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {		xpt_bus_deregister(cam_sim_path(sim));		cam_sim_free(sim, TRUE);		return;	}	xpt_setup_ccb(&csa.ccb_h, path, 5);	csa.ccb_h.func_code = XPT_SASYNC_CB;	csa.event_enable = AC_LOST_DEVICE;	csa.callback = isp_cam_async;	csa.callback_arg = sim;	xpt_action((union ccb *)&csa);	isp->isp_sim = sim;	isp->isp_path = path;	/*	 * If we have a second channel, construct SIM entry for that.	 */	if (IS_12X0(isp)) {		sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp,		    isp->isp_unit, 1, MAXISPREQUEST, devq);		if (sim == NULL) {			xpt_bus_deregister(cam_sim_path(isp->isp_sim));			xpt_free_path(isp->isp_path);			cam_simq_free(devq);			return;		}		if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) {			xpt_bus_deregister(cam_sim_path(isp->isp_sim));			xpt_free_path(isp->isp_path);			cam_sim_free(sim, TRUE);			return;		}		if (xpt_create_path(&path, NULL, cam_sim_path(sim),		    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {			xpt_bus_deregister(cam_sim_path(isp->isp_sim));			xpt_free_path(isp->isp_path);			xpt_bus_deregister(cam_sim_path(sim));			cam_sim_free(sim, TRUE);			return;		}		xpt_setup_ccb(&csa.ccb_h, path, 5);		csa.ccb_h.func_code = XPT_SASYNC_CB;		csa.event_enable = AC_LOST_DEVICE;		csa.callback = isp_cam_async;		csa.callback_arg = sim;		xpt_action((union ccb *)&csa);		isp->isp_sim2 = sim;		isp->isp_path2 = path;	}	if (isp->isp_state == ISP_INITSTATE)		isp->isp_state = ISP_RUNSTATE;}static voidisp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg){	struct cam_sim *sim;	struct ispsoftc *isp;	sim = (struct cam_sim *)cbarg;	isp = (struct ispsoftc *) cam_sim_softc(sim);	switch (code) {	case AC_LOST_DEVICE:		if (isp->isp_type & ISP_HA_SCSI) {			u_int16_t oflags, nflags;			sdparam *sdp = isp->isp_param;			int s, tgt = xpt_path_target_id(path);			s = splcam();			sdp += cam_sim_bus(sim);			isp->isp_update |= (1 << cam_sim_bus(sim));			nflags = DPARM_SAFE_DFLT;			if (ISP_FW_REVX(isp->isp_fwrev) >=			    ISP_FW_REV(7, 55, 0)) {				nflags |= DPARM_NARROW | DPARM_ASYNC;			}			oflags = sdp->isp_devparam[tgt].dev_flags;			sdp->isp_devparam[tgt].dev_flags = nflags;			sdp->isp_devparam[tgt].dev_update = 1;			(void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL);			sdp->isp_devparam[tgt].dev_flags = oflags;			(void) splx(s);		}		break;	default:		break;	}}static voidisp_poll(struct cam_sim *sim){	isp_intr((struct ispsoftc *) cam_sim_softc(sim));}static voidisp_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.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?