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 + -
显示快捷键?