183ae4407SMatt Jacob /* $Id: isp_freebsd.c,v 1.18 1999/05/11 05:10:06 mjacob Exp $ */ 2ea6f23cdSMatt Jacob /* release_5_11_99 */ 36054c3f6SMatt Jacob /* 46054c3f6SMatt Jacob * Platform (FreeBSD) dependent common attachment code for Qlogic adapters. 56054c3f6SMatt Jacob * 66054c3f6SMatt Jacob *--------------------------------------- 76054c3f6SMatt Jacob * Copyright (c) 1997, 1998 by Matthew Jacob 86054c3f6SMatt Jacob * NASA/Ames Research Center 96054c3f6SMatt Jacob * All rights reserved. 106054c3f6SMatt Jacob *--------------------------------------- 116054c3f6SMatt Jacob * 126054c3f6SMatt Jacob * Redistribution and use in source and binary forms, with or without 136054c3f6SMatt Jacob * modification, are permitted provided that the following conditions 146054c3f6SMatt Jacob * are met: 156054c3f6SMatt Jacob * 1. Redistributions of source code must retain the above copyright 166054c3f6SMatt Jacob * notice immediately at the beginning of the file, without modification, 176054c3f6SMatt Jacob * this list of conditions, and the following disclaimer. 186054c3f6SMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 196054c3f6SMatt Jacob * notice, this list of conditions and the following disclaimer in the 206054c3f6SMatt Jacob * documentation and/or other materials provided with the distribution. 216054c3f6SMatt Jacob * 3. The name of the author may not be used to endorse or promote products 226054c3f6SMatt Jacob * derived from this software without specific prior written permission. 236054c3f6SMatt Jacob * 246054c3f6SMatt Jacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 256054c3f6SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 266054c3f6SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 276054c3f6SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 286054c3f6SMatt Jacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 296054c3f6SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 306054c3f6SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 316054c3f6SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 326054c3f6SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 336054c3f6SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 346054c3f6SMatt Jacob * SUCH DAMAGE. 356054c3f6SMatt Jacob */ 366054c3f6SMatt Jacob #include <dev/isp/isp_freebsd.h> 376054c3f6SMatt Jacob 383dd37e43SMatt Jacob #if __FreeBSD_version >= 300004 393dd37e43SMatt Jacob 40cbf57b47SMatt Jacob static void isp_cam_async __P((void *, u_int32_t, struct cam_path *, void *)); 41478f8a96SJustin T. Gibbs static void isp_poll __P((struct cam_sim *)); 42478f8a96SJustin T. Gibbs static void isp_action __P((struct cam_sim *, union ccb *)); 43478f8a96SJustin T. Gibbs 44478f8a96SJustin T. Gibbs void 45c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 46478f8a96SJustin T. Gibbs { 47ea6f23cdSMatt Jacob int primary, secondary; 48478f8a96SJustin T. Gibbs struct ccb_setasync csa; 49478f8a96SJustin T. Gibbs struct cam_devq *devq; 50ea6f23cdSMatt Jacob struct cam_sim *sim; 51ea6f23cdSMatt Jacob struct cam_path *path; 52478f8a96SJustin T. Gibbs 53478f8a96SJustin T. Gibbs /* 54ea6f23cdSMatt Jacob * Establish (in case of 12X0) which bus is the primary. 55ea6f23cdSMatt Jacob */ 56ea6f23cdSMatt Jacob 57ea6f23cdSMatt Jacob primary = 0; 58ea6f23cdSMatt Jacob secondary = 1; 59ea6f23cdSMatt Jacob 60ea6f23cdSMatt Jacob /* 61ea6f23cdSMatt Jacob * Create the device queue for our SIM(s). 62478f8a96SJustin T. Gibbs */ 63478f8a96SJustin T. Gibbs devq = cam_simq_alloc(MAXISPREQUEST); 64478f8a96SJustin T. Gibbs if (devq == NULL) { 65478f8a96SJustin T. Gibbs return; 66478f8a96SJustin T. Gibbs } 67478f8a96SJustin T. Gibbs 68478f8a96SJustin T. Gibbs /* 69ea6f23cdSMatt Jacob * Construct our SIM entry. 70478f8a96SJustin T. Gibbs */ 71ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 72478f8a96SJustin T. Gibbs isp->isp_unit, 1, MAXISPREQUEST, devq); 73ea6f23cdSMatt Jacob if (sim == NULL) { 74478f8a96SJustin T. Gibbs cam_simq_free(devq); 75478f8a96SJustin T. Gibbs return; 76478f8a96SJustin T. Gibbs } 77ea6f23cdSMatt Jacob if (xpt_bus_register(sim, primary) != CAM_SUCCESS) { 78ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 79478f8a96SJustin T. Gibbs return; 80478f8a96SJustin T. Gibbs } 81478f8a96SJustin T. Gibbs 82ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 83478f8a96SJustin T. Gibbs CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 84ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 85ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 86478f8a96SJustin T. Gibbs return; 87478f8a96SJustin T. Gibbs } 88478f8a96SJustin T. Gibbs 89ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 90478f8a96SJustin T. Gibbs csa.ccb_h.func_code = XPT_SASYNC_CB; 91478f8a96SJustin T. Gibbs csa.event_enable = AC_LOST_DEVICE; 92cbf57b47SMatt Jacob csa.callback = isp_cam_async; 93ea6f23cdSMatt Jacob csa.callback_arg = sim; 94478f8a96SJustin T. Gibbs xpt_action((union ccb *)&csa); 95ea6f23cdSMatt Jacob isp->isp_sim = sim; 96ea6f23cdSMatt Jacob isp->isp_path = path; 97478f8a96SJustin T. Gibbs 98ea6f23cdSMatt Jacob /* 99ea6f23cdSMatt Jacob * If we have a second channel, construct SIM entry for that. 100ea6f23cdSMatt Jacob */ 101ea6f23cdSMatt Jacob if (IS_12X0(isp)) { 102ea6f23cdSMatt Jacob sim = cam_sim_alloc(isp_action, isp_poll, "isp", isp, 103ea6f23cdSMatt Jacob isp->isp_unit, 1, MAXISPREQUEST, devq); 104ea6f23cdSMatt Jacob if (sim == NULL) { 105ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 106ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 107ea6f23cdSMatt Jacob cam_simq_free(devq); 108ea6f23cdSMatt Jacob return; 109ea6f23cdSMatt Jacob } 110ea6f23cdSMatt Jacob if (xpt_bus_register(sim, secondary) != CAM_SUCCESS) { 111ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 112ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 113ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 114ea6f23cdSMatt Jacob return; 115ea6f23cdSMatt Jacob } 116ea6f23cdSMatt Jacob 117ea6f23cdSMatt Jacob if (xpt_create_path(&path, NULL, cam_sim_path(sim), 118ea6f23cdSMatt Jacob CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 119ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(isp->isp_sim)); 120ea6f23cdSMatt Jacob xpt_free_path(isp->isp_path); 121ea6f23cdSMatt Jacob xpt_bus_deregister(cam_sim_path(sim)); 122ea6f23cdSMatt Jacob cam_sim_free(sim, TRUE); 123ea6f23cdSMatt Jacob return; 124ea6f23cdSMatt Jacob } 125ea6f23cdSMatt Jacob 126ea6f23cdSMatt Jacob xpt_setup_ccb(&csa.ccb_h, path, 5); 127ea6f23cdSMatt Jacob csa.ccb_h.func_code = XPT_SASYNC_CB; 128ea6f23cdSMatt Jacob csa.event_enable = AC_LOST_DEVICE; 129ea6f23cdSMatt Jacob csa.callback = isp_cam_async; 130ea6f23cdSMatt Jacob csa.callback_arg = sim; 131ea6f23cdSMatt Jacob xpt_action((union ccb *)&csa); 132ea6f23cdSMatt Jacob isp->isp_sim2 = sim; 133ea6f23cdSMatt Jacob isp->isp_path2 = path; 134ea6f23cdSMatt Jacob } 13557c801f5SMatt Jacob if (isp->isp_state == ISP_INITSTATE) 136478f8a96SJustin T. Gibbs isp->isp_state = ISP_RUNSTATE; 137478f8a96SJustin T. Gibbs } 138478f8a96SJustin T. Gibbs 139478f8a96SJustin T. Gibbs static void 140cbf57b47SMatt Jacob isp_cam_async(void *cbarg, u_int32_t code, struct cam_path *path, void *arg) 141478f8a96SJustin T. Gibbs { 142478f8a96SJustin T. Gibbs struct cam_sim *sim; 143478f8a96SJustin T. Gibbs struct ispsoftc *isp; 144478f8a96SJustin T. Gibbs 145478f8a96SJustin T. Gibbs sim = (struct cam_sim *)cbarg; 146478f8a96SJustin T. Gibbs isp = (struct ispsoftc *) cam_sim_softc(sim); 147478f8a96SJustin T. Gibbs switch (code) { 148478f8a96SJustin T. Gibbs case AC_LOST_DEVICE: 149478f8a96SJustin T. Gibbs if (isp->isp_type & ISP_HA_SCSI) { 150478f8a96SJustin T. Gibbs u_int16_t oflags, nflags; 151478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 152478f8a96SJustin T. Gibbs int s, tgt = xpt_path_target_id(path); 153478f8a96SJustin T. Gibbs 154ea6f23cdSMatt Jacob s = splcam(); 155ea6f23cdSMatt Jacob sdp += cam_sim_bus(sim); 156ea6f23cdSMatt Jacob isp->isp_update |= (1 << cam_sim_bus(sim)); 157ea6f23cdSMatt Jacob 158478f8a96SJustin T. Gibbs nflags = DPARM_SAFE_DFLT; 15992718a7fSMatt Jacob if (ISP_FW_REVX(isp->isp_fwrev) >= 16092718a7fSMatt Jacob ISP_FW_REV(7, 55, 0)) { 161478f8a96SJustin T. Gibbs nflags |= DPARM_NARROW | DPARM_ASYNC; 162478f8a96SJustin T. Gibbs } 163478f8a96SJustin T. Gibbs oflags = sdp->isp_devparam[tgt].dev_flags; 164478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = nflags; 165478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 166478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 167478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_flags = oflags; 168ea6f23cdSMatt Jacob (void) splx(s); 169478f8a96SJustin T. Gibbs } 170478f8a96SJustin T. Gibbs break; 171478f8a96SJustin T. Gibbs default: 172478f8a96SJustin T. Gibbs break; 173478f8a96SJustin T. Gibbs } 174478f8a96SJustin T. Gibbs } 175478f8a96SJustin T. Gibbs 176478f8a96SJustin T. Gibbs static void 177c3055363SMatt Jacob isp_poll(struct cam_sim *sim) 178478f8a96SJustin T. Gibbs { 179478f8a96SJustin T. Gibbs isp_intr((struct ispsoftc *) cam_sim_softc(sim)); 180478f8a96SJustin T. Gibbs } 181478f8a96SJustin T. Gibbs 182478f8a96SJustin T. Gibbs 183478f8a96SJustin T. Gibbs static void 184c3055363SMatt Jacob isp_action(struct cam_sim *sim, union ccb *ccb) 185478f8a96SJustin T. Gibbs { 186478f8a96SJustin T. Gibbs int s, tgt, error; 187478f8a96SJustin T. Gibbs struct ispsoftc *isp; 1884663e367SJustin T. Gibbs struct ccb_trans_settings *cts; 189478f8a96SJustin T. Gibbs 190478f8a96SJustin T. Gibbs CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("isp_action\n")); 191478f8a96SJustin T. Gibbs 192478f8a96SJustin T. Gibbs isp = (struct ispsoftc *)cam_sim_softc(sim); 193478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[0].field = 0; 194478f8a96SJustin T. Gibbs ccb->ccb_h.sim_priv.entries[1].ptr = isp; 19557c801f5SMatt Jacob /* 19657c801f5SMatt Jacob * This should only happen for Fibre Channel adapters. 19757c801f5SMatt Jacob * We want to pass through all but XPT_SCSI_IO (e.g., 19857c801f5SMatt Jacob * path inquiry) but fail if we can't get good Fibre 19957c801f5SMatt Jacob * Channel link status. 20057c801f5SMatt Jacob */ 20157c801f5SMatt Jacob if (ccb->ccb_h.func_code == XPT_SCSI_IO && 20257c801f5SMatt Jacob isp->isp_state != ISP_RUNSTATE) { 20357c801f5SMatt Jacob s = splcam(); 20457c801f5SMatt Jacob DISABLE_INTS(isp); 20557c801f5SMatt Jacob isp_init(isp); 20657c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 20757c801f5SMatt Jacob (void) splx(s); 20857c801f5SMatt Jacob /* 20957c801f5SMatt Jacob * Lie. Say it was a selection timeout. 21057c801f5SMatt Jacob */ 21157c801f5SMatt Jacob ccb->ccb_h.status = CAM_SEL_TIMEOUT; 21257c801f5SMatt Jacob xpt_done(ccb); 21357c801f5SMatt Jacob return; 21457c801f5SMatt Jacob } 21557c801f5SMatt Jacob isp->isp_state = ISP_RUNSTATE; 21657c801f5SMatt Jacob ENABLE_INTS(isp); 21757c801f5SMatt Jacob (void) splx(s); 21857c801f5SMatt Jacob } 219478f8a96SJustin T. Gibbs 220478f8a96SJustin T. Gibbs IDPRINTF(4, ("%s: isp_action code %x\n", isp->isp_name, 221478f8a96SJustin T. Gibbs ccb->ccb_h.func_code)); 222478f8a96SJustin T. Gibbs 223478f8a96SJustin T. Gibbs switch (ccb->ccb_h.func_code) { 224478f8a96SJustin T. Gibbs case XPT_SCSI_IO: /* Execute the requested I/O operation */ 225478f8a96SJustin T. Gibbs /* 226478f8a96SJustin T. Gibbs * Do a couple of preliminary checks... 227478f8a96SJustin T. Gibbs */ 228478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { 229478f8a96SJustin T. Gibbs if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { 230478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 231478f8a96SJustin T. Gibbs xpt_done(ccb); 232478f8a96SJustin T. Gibbs break; 233478f8a96SJustin T. Gibbs } 234478f8a96SJustin T. Gibbs } 235478f8a96SJustin T. Gibbs 236478f8a96SJustin T. Gibbs 237478f8a96SJustin T. Gibbs if (isp->isp_type & ISP_HA_SCSI) { 238478f8a96SJustin T. Gibbs if (ccb->ccb_h.target_id > (MAX_TARGETS-1)) { 239478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 24092718a7fSMatt Jacob } else if (ISP_FW_REVX(isp->isp_fwrev) >= 24192718a7fSMatt Jacob ISP_FW_REV(7, 55, 0)) { 242478f8a96SJustin T. Gibbs /* 243478f8a96SJustin T. Gibbs * Too much breakage. 244478f8a96SJustin T. Gibbs */ 245478f8a96SJustin T. Gibbs #if 0 246478f8a96SJustin T. Gibbs if (ccb->ccb_h.target_lun > 31) { 247478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 248478f8a96SJustin T. Gibbs } 249478f8a96SJustin T. Gibbs #else 250478f8a96SJustin T. Gibbs if (ccb->ccb_h.target_lun > 7) { 251478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 252478f8a96SJustin T. Gibbs } 253478f8a96SJustin T. Gibbs #endif 254478f8a96SJustin T. Gibbs } else if (ccb->ccb_h.target_lun > 7) { 255478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 256478f8a96SJustin T. Gibbs } 257478f8a96SJustin T. Gibbs } else { 258478f8a96SJustin T. Gibbs if (ccb->ccb_h.target_id > (MAX_FC_TARG-1)) { 259478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 260d3a9eb2eSMatt Jacob #ifdef SCCLUN 261478f8a96SJustin T. Gibbs } else if (ccb->ccb_h.target_lun > 15) { 262478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_PATH_INVALID; 263d3a9eb2eSMatt Jacob #else 264d3a9eb2eSMatt Jacob } else if (ccb->ccb_h.target_lun > 65535) { 265d3a9eb2eSMatt Jacob ccb->ccb_h.status = CAM_PATH_INVALID; 266d3a9eb2eSMatt Jacob #endif 267478f8a96SJustin T. Gibbs } 268478f8a96SJustin T. Gibbs } 269478f8a96SJustin T. Gibbs if (ccb->ccb_h.status == CAM_PATH_INVALID) { 270478f8a96SJustin T. Gibbs printf("%s: invalid tgt/lun (%d.%d) in XPT_SCSI_IO\n", 271478f8a96SJustin T. Gibbs isp->isp_name, ccb->ccb_h.target_id, 272478f8a96SJustin T. Gibbs ccb->ccb_h.target_lun); 273478f8a96SJustin T. Gibbs xpt_done(ccb); 274478f8a96SJustin T. Gibbs break; 275478f8a96SJustin T. Gibbs } 276478f8a96SJustin T. Gibbs s = splcam(); 277c3055363SMatt Jacob DISABLE_INTS(isp); 278478f8a96SJustin T. Gibbs switch (ispscsicmd((ISP_SCSI_XFER_T *) ccb)) { 279478f8a96SJustin T. Gibbs case CMD_QUEUED: 280478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_SIM_QUEUED; 281478f8a96SJustin T. Gibbs break; 282478f8a96SJustin T. Gibbs case CMD_EAGAIN: 28357c801f5SMatt Jacob if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE)) { 284478f8a96SJustin T. Gibbs xpt_freeze_simq(sim, 1); 28557c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_RESOURCE; 28600f50ce8SMatt Jacob } 287478f8a96SJustin T. Gibbs ccb->ccb_h.status &= ~CAM_STATUS_MASK; 288478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_REQUEUE_REQ; 289478f8a96SJustin T. Gibbs xpt_done(ccb); 290478f8a96SJustin T. Gibbs break; 291478f8a96SJustin T. Gibbs case CMD_COMPLETE: 292c6904df9SMatt Jacob /* 293c6904df9SMatt Jacob * Just make sure that we didn't get it returned 294c6904df9SMatt Jacob * as completed, but with the request still in 295c6904df9SMatt Jacob * progress. In theory, 'cannot happen'. 296c6904df9SMatt Jacob */ 297c6904df9SMatt Jacob if ((ccb->ccb_h.status & CAM_STATUS_MASK) == 298478f8a96SJustin T. Gibbs CAM_REQ_INPROG) { 299478f8a96SJustin T. Gibbs ccb->ccb_h.status &= ~CAM_STATUS_MASK; 300478f8a96SJustin T. Gibbs ccb->ccb_h.status |= CAM_REQ_CMP_ERR; 301478f8a96SJustin T. Gibbs } 302478f8a96SJustin T. Gibbs xpt_done(ccb); 303478f8a96SJustin T. Gibbs break; 304478f8a96SJustin T. Gibbs } 305c3055363SMatt Jacob ENABLE_INTS(isp); 306478f8a96SJustin T. Gibbs splx(s); 307478f8a96SJustin T. Gibbs break; 308478f8a96SJustin T. Gibbs 309478f8a96SJustin T. Gibbs case XPT_EN_LUN: /* Enable LUN as a target */ 310478f8a96SJustin T. Gibbs case XPT_TARGET_IO: /* Execute target I/O request */ 311478f8a96SJustin T. Gibbs case XPT_ACCEPT_TARGET_IO: /* Accept Host Target Mode CDB */ 312478f8a96SJustin T. Gibbs case XPT_CONT_TARGET_IO: /* Continue Host Target I/O Connection*/ 313478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 314478f8a96SJustin T. Gibbs xpt_done(ccb); 315478f8a96SJustin T. Gibbs break; 316478f8a96SJustin T. Gibbs 317478f8a96SJustin T. Gibbs case XPT_RESET_DEV: /* BDR the specified SCSI device */ 318ea6f23cdSMatt Jacob tgt = ccb->ccb_h.target_id; /* XXX: Which Bus? */ 319478f8a96SJustin T. Gibbs s = splcam(); 320ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_DEV, &tgt); 321478f8a96SJustin T. Gibbs (void) splx(s); 322478f8a96SJustin T. Gibbs if (error) { 323478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 324478f8a96SJustin T. Gibbs } else { 325478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 326478f8a96SJustin T. Gibbs } 327478f8a96SJustin T. Gibbs xpt_done(ccb); 328478f8a96SJustin T. Gibbs break; 329478f8a96SJustin T. Gibbs case XPT_ABORT: /* Abort the specified CCB */ 330478f8a96SJustin T. Gibbs s = splcam(); 331478f8a96SJustin T. Gibbs error = isp_control(isp, ISPCTL_ABORT_CMD, ccb); 332478f8a96SJustin T. Gibbs (void) splx(s); 333478f8a96SJustin T. Gibbs if (error) { 334478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 335478f8a96SJustin T. Gibbs } else { 336478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 337478f8a96SJustin T. Gibbs } 338478f8a96SJustin T. Gibbs xpt_done(ccb); 339478f8a96SJustin T. Gibbs break; 340478f8a96SJustin T. Gibbs 341478f8a96SJustin T. Gibbs case XPT_SET_TRAN_SETTINGS: /* Nexus Settings */ 342478f8a96SJustin T. Gibbs 343478f8a96SJustin T. Gibbs cts = &ccb->cts; 344478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 345478f8a96SJustin T. Gibbs s = splcam(); 346478f8a96SJustin T. Gibbs if (isp->isp_type & ISP_HA_FC) { 347478f8a96SJustin T. Gibbs ; /* nothing to change */ 348478f8a96SJustin T. Gibbs } else { 349478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 350478f8a96SJustin T. Gibbs u_int16_t *dptr; 351ea6f23cdSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 352478f8a96SJustin T. Gibbs 353ea6f23cdSMatt Jacob sdp += bus; 354478f8a96SJustin T. Gibbs #if 0 355478f8a96SJustin T. Gibbs if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) 356478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].cur_dflags; 357478f8a96SJustin T. Gibbs else 358478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 359478f8a96SJustin T. Gibbs #else 360478f8a96SJustin T. Gibbs /* 361478f8a96SJustin T. Gibbs * We always update (internally) from dev_flags 362478f8a96SJustin T. Gibbs * so any request to change settings just gets 363478f8a96SJustin T. Gibbs * vectored to that location. 364478f8a96SJustin T. Gibbs */ 365478f8a96SJustin T. Gibbs dptr = &sdp->isp_devparam[tgt].dev_flags; 366478f8a96SJustin T. Gibbs #endif 367478f8a96SJustin T. Gibbs 368478f8a96SJustin T. Gibbs /* 369478f8a96SJustin T. Gibbs * Note that these operations affect the 3704394c92fSMatt Jacob * the goal flags (dev_flags)- not 371478f8a96SJustin T. Gibbs * the current state flags. Then we mark 372478f8a96SJustin T. Gibbs * things so that the next operation to 373478f8a96SJustin T. Gibbs * this HBA will cause the update to occur. 374478f8a96SJustin T. Gibbs */ 375478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_DISC_VALID) { 376478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_DISC_ENB) != 0) { 377478f8a96SJustin T. Gibbs *dptr |= DPARM_DISC; 378478f8a96SJustin T. Gibbs } else { 379478f8a96SJustin T. Gibbs *dptr &= ~DPARM_DISC; 380478f8a96SJustin T. Gibbs } 381478f8a96SJustin T. Gibbs } 382478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_TQ_VALID) { 383478f8a96SJustin T. Gibbs if ((cts->flags & CCB_TRANS_TAG_ENB) != 0) { 384478f8a96SJustin T. Gibbs *dptr |= DPARM_TQING; 385478f8a96SJustin T. Gibbs } else { 386478f8a96SJustin T. Gibbs *dptr &= ~DPARM_TQING; 387478f8a96SJustin T. Gibbs } 388478f8a96SJustin T. Gibbs } 389478f8a96SJustin T. Gibbs if (cts->valid & CCB_TRANS_BUS_WIDTH_VALID) { 390478f8a96SJustin T. Gibbs switch (cts->bus_width) { 391478f8a96SJustin T. Gibbs case MSG_EXT_WDTR_BUS_16_BIT: 392478f8a96SJustin T. Gibbs *dptr |= DPARM_WIDE; 393478f8a96SJustin T. Gibbs break; 394478f8a96SJustin T. Gibbs default: 395478f8a96SJustin T. Gibbs *dptr &= ~DPARM_WIDE; 396478f8a96SJustin T. Gibbs } 397478f8a96SJustin T. Gibbs } 398478f8a96SJustin T. Gibbs /* 399478f8a96SJustin T. Gibbs * Any SYNC RATE of nonzero and SYNC_OFFSET 400478f8a96SJustin T. Gibbs * of nonzero will cause us to go to the 401478f8a96SJustin T. Gibbs * selected (from NVRAM) maximum value for 402478f8a96SJustin T. Gibbs * this device. At a later point, we'll 403478f8a96SJustin T. Gibbs * allow finer control. 404478f8a96SJustin T. Gibbs */ 405478f8a96SJustin T. Gibbs if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) && 406478f8a96SJustin T. Gibbs (cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) && 407478f8a96SJustin T. Gibbs (cts->sync_offset > 0)) { 408478f8a96SJustin T. Gibbs *dptr |= DPARM_SYNC; 409478f8a96SJustin T. Gibbs } else { 410478f8a96SJustin T. Gibbs *dptr &= ~DPARM_SYNC; 411478f8a96SJustin T. Gibbs } 41283ae4407SMatt Jacob if (bootverbose || isp->isp_dblev >= 3) 41383ae4407SMatt Jacob printf("%s: %d.%d set %s period 0x%x offset " 41483ae4407SMatt Jacob "0x%x flags 0x%x\n", isp->isp_name, bus, 41583ae4407SMatt Jacob tgt, 4164394c92fSMatt Jacob (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 4174394c92fSMatt Jacob "current" : "user", 4182b052931SMatt Jacob sdp->isp_devparam[tgt].sync_period, 4192b052931SMatt Jacob sdp->isp_devparam[tgt].sync_offset, 42083ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_flags); 421478f8a96SJustin T. Gibbs s = splcam(); 422478f8a96SJustin T. Gibbs sdp->isp_devparam[tgt].dev_update = 1; 423ea6f23cdSMatt Jacob isp->isp_update |= (1 << bus); 424478f8a96SJustin T. Gibbs (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, NULL); 425478f8a96SJustin T. Gibbs (void) splx(s); 426478f8a96SJustin T. Gibbs } 427478f8a96SJustin T. Gibbs (void) splx(s); 428478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 429478f8a96SJustin T. Gibbs xpt_done(ccb); 430478f8a96SJustin T. Gibbs break; 431478f8a96SJustin T. Gibbs 432478f8a96SJustin T. Gibbs case XPT_GET_TRAN_SETTINGS: 433478f8a96SJustin T. Gibbs 434478f8a96SJustin T. Gibbs cts = &ccb->cts; 435478f8a96SJustin T. Gibbs tgt = cts->ccb_h.target_id; 436478f8a96SJustin T. Gibbs if (isp->isp_type & ISP_HA_FC) { 437478f8a96SJustin T. Gibbs /* 438478f8a96SJustin T. Gibbs * a lot of normal SCSI things don't make sense. 439478f8a96SJustin T. Gibbs */ 440478f8a96SJustin T. Gibbs cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB; 441478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 442478f8a96SJustin T. Gibbs /* 443478f8a96SJustin T. Gibbs * How do you measure the width of a high 444478f8a96SJustin T. Gibbs * speed serial bus? Well, in bytes. 445478f8a96SJustin T. Gibbs * 446478f8a96SJustin T. Gibbs * Offset and period make no sense, though, so we set 447478f8a96SJustin T. Gibbs * (above) a 'base' transfer speed to be gigabit. 448478f8a96SJustin T. Gibbs */ 449478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 450478f8a96SJustin T. Gibbs } else { 451478f8a96SJustin T. Gibbs sdparam *sdp = isp->isp_param; 4524394c92fSMatt Jacob u_int16_t dval, pval, oval; 453ea6f23cdSMatt Jacob int bus = cam_sim_bus(xpt_path_sim(cts->ccb_h.path)); 454478f8a96SJustin T. Gibbs 455ea6f23cdSMatt Jacob sdp += bus; 4564394c92fSMatt Jacob if (cts->flags & CCB_TRANS_CURRENT_SETTINGS) { 45783ae4407SMatt Jacob s = splcam(); 45883ae4407SMatt Jacob /* 45983ae4407SMatt Jacob * First do a refresh to see if things 46083ae4407SMatt Jacob * have changed recently! 46183ae4407SMatt Jacob */ 46283ae4407SMatt Jacob sdp->isp_devparam[tgt].dev_refresh = 1; 46383ae4407SMatt Jacob isp->isp_update |= (1 << bus); 46483ae4407SMatt Jacob (void) isp_control(isp, ISPCTL_UPDATE_PARAMS, 46583ae4407SMatt Jacob NULL); 46683ae4407SMatt Jacob (void) splx(s); 467478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].cur_dflags; 4684394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].cur_offset; 4694394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].cur_period; 4704394c92fSMatt Jacob } else { 471478f8a96SJustin T. Gibbs dval = sdp->isp_devparam[tgt].dev_flags; 4724394c92fSMatt Jacob oval = sdp->isp_devparam[tgt].sync_offset; 4734394c92fSMatt Jacob pval = sdp->isp_devparam[tgt].sync_period; 4744394c92fSMatt Jacob } 475478f8a96SJustin T. Gibbs 476478f8a96SJustin T. Gibbs s = splcam(); 477478f8a96SJustin T. Gibbs cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB); 478478f8a96SJustin T. Gibbs 479478f8a96SJustin T. Gibbs if (dval & DPARM_DISC) { 480478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_DISC_ENB; 481478f8a96SJustin T. Gibbs } 482478f8a96SJustin T. Gibbs if (dval & DPARM_TQING) { 483478f8a96SJustin T. Gibbs cts->flags |= CCB_TRANS_TAG_ENB; 484478f8a96SJustin T. Gibbs } 485478f8a96SJustin T. Gibbs if (dval & DPARM_WIDE) { 486478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_16_BIT; 487478f8a96SJustin T. Gibbs } else { 488478f8a96SJustin T. Gibbs cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT; 489478f8a96SJustin T. Gibbs } 490478f8a96SJustin T. Gibbs cts->valid = CCB_TRANS_BUS_WIDTH_VALID | 491478f8a96SJustin T. Gibbs CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 492478f8a96SJustin T. Gibbs 4934394c92fSMatt Jacob if ((dval & DPARM_SYNC) && oval != 0) { 4944394c92fSMatt Jacob cts->sync_period = pval; 4954394c92fSMatt Jacob cts->sync_offset = oval; 496478f8a96SJustin T. Gibbs cts->valid |= 497478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_RATE_VALID | 498478f8a96SJustin T. Gibbs CCB_TRANS_SYNC_OFFSET_VALID; 499478f8a96SJustin T. Gibbs } 500478f8a96SJustin T. Gibbs splx(s); 50183ae4407SMatt Jacob if (bootverbose || isp->isp_dblev >= 3) 50283ae4407SMatt Jacob printf("%s: %d.%d get %s period 0x%x offset " 50383ae4407SMatt Jacob "0x%x flags 0x%x\n", isp->isp_name, bus, 50483ae4407SMatt Jacob tgt, 5054394c92fSMatt Jacob (cts->flags & CCB_TRANS_CURRENT_SETTINGS)? 50683ae4407SMatt Jacob "current" : "user", pval, oval, dval); 507478f8a96SJustin T. Gibbs } 508478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 509478f8a96SJustin T. Gibbs xpt_done(ccb); 510478f8a96SJustin T. Gibbs break; 511478f8a96SJustin T. Gibbs 512478f8a96SJustin T. Gibbs case XPT_CALC_GEOMETRY: 513478f8a96SJustin T. Gibbs { 514478f8a96SJustin T. Gibbs struct ccb_calc_geometry *ccg; 515478f8a96SJustin T. Gibbs u_int32_t secs_per_cylinder; 516478f8a96SJustin T. Gibbs u_int32_t size_mb; 517478f8a96SJustin T. Gibbs 518478f8a96SJustin T. Gibbs ccg = &ccb->ccg; 519478f8a96SJustin T. Gibbs if (ccg->block_size == 0) { 520478f8a96SJustin T. Gibbs printf("%s: %d.%d XPT_CALC_GEOMETRY block size 0?\n", 521478f8a96SJustin T. Gibbs isp->isp_name, ccg->ccb_h.target_id, 522478f8a96SJustin T. Gibbs ccg->ccb_h.target_lun); 523478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 524478f8a96SJustin T. Gibbs xpt_done(ccb); 525478f8a96SJustin T. Gibbs break; 526478f8a96SJustin T. Gibbs } 527478f8a96SJustin T. Gibbs size_mb = ccg->volume_size /((1024L * 1024L) / ccg->block_size); 528478f8a96SJustin T. Gibbs if (size_mb > 1024) { 529478f8a96SJustin T. Gibbs ccg->heads = 255; 530478f8a96SJustin T. Gibbs ccg->secs_per_track = 63; 531478f8a96SJustin T. Gibbs } else { 532478f8a96SJustin T. Gibbs ccg->heads = 64; 533478f8a96SJustin T. Gibbs ccg->secs_per_track = 32; 534478f8a96SJustin T. Gibbs } 535478f8a96SJustin T. Gibbs secs_per_cylinder = ccg->heads * ccg->secs_per_track; 536478f8a96SJustin T. Gibbs ccg->cylinders = ccg->volume_size / secs_per_cylinder; 537478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 538478f8a96SJustin T. Gibbs xpt_done(ccb); 539478f8a96SJustin T. Gibbs break; 540478f8a96SJustin T. Gibbs } 541478f8a96SJustin T. Gibbs case XPT_RESET_BUS: /* Reset the specified bus */ 542ea6f23cdSMatt Jacob tgt = cam_sim_bus(sim); 543478f8a96SJustin T. Gibbs s = splcam(); 544ea6f23cdSMatt Jacob error = isp_control(isp, ISPCTL_RESET_BUS, &tgt); 545478f8a96SJustin T. Gibbs (void) splx(s); 546478f8a96SJustin T. Gibbs if (error) 547478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP_ERR; 5482b052931SMatt Jacob else { 549ea6f23cdSMatt Jacob if (cam_sim_bus(sim) && isp->isp_path2 != NULL) 550ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 551ea6f23cdSMatt Jacob else if (isp->isp_path != NULL) 5522b052931SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 553478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_CMP; 5542b052931SMatt Jacob } 555478f8a96SJustin T. Gibbs xpt_done(ccb); 556478f8a96SJustin T. Gibbs break; 557478f8a96SJustin T. Gibbs 558478f8a96SJustin T. Gibbs case XPT_TERM_IO: /* Terminate the I/O process */ 559478f8a96SJustin T. Gibbs /* Does this need to be implemented? */ 560478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 561478f8a96SJustin T. Gibbs xpt_done(ccb); 562478f8a96SJustin T. Gibbs break; 563478f8a96SJustin T. Gibbs 564478f8a96SJustin T. Gibbs case XPT_PATH_INQ: /* Path routing inquiry */ 565478f8a96SJustin T. Gibbs { 566478f8a96SJustin T. Gibbs struct ccb_pathinq *cpi = &ccb->cpi; 567478f8a96SJustin T. Gibbs 568478f8a96SJustin T. Gibbs cpi->version_num = 1; 569478f8a96SJustin T. Gibbs cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 570478f8a96SJustin T. Gibbs cpi->target_sprt = 0; 571478f8a96SJustin T. Gibbs cpi->hba_eng_cnt = 0; 5724394c92fSMatt Jacob if (IS_FC(isp)) { 5734394c92fSMatt Jacob cpi->hba_misc = PIM_NOBUSRESET; 574478f8a96SJustin T. Gibbs cpi->max_target = MAX_FC_TARG-1; 575478f8a96SJustin T. Gibbs cpi->initiator_id = 576478f8a96SJustin T. Gibbs ((fcparam *)isp->isp_param)->isp_loopid; 577d3a9eb2eSMatt Jacob #ifdef SCCLUN 578c3055363SMatt Jacob cpi->max_lun = (1 << 16) - 1; 579d3a9eb2eSMatt Jacob #else 580c3055363SMatt Jacob cpi->max_lun = (1 << 4) - 1; 581d3a9eb2eSMatt Jacob #endif 5829deea857SKenneth D. Merry /* 5839deea857SKenneth D. Merry * Set base transfer capabilities for Fibre Channel. 5849deea857SKenneth D. Merry * Technically not correct because we don't know 5859deea857SKenneth D. Merry * what media we're running on top of- but we'll 5869deea857SKenneth D. Merry * look good if we always say 100MB/s. 5879deea857SKenneth D. Merry */ 5889deea857SKenneth D. Merry cpi->base_transfer_speed = 100000; 589478f8a96SJustin T. Gibbs } else { 590ea6f23cdSMatt Jacob sdparam *sdp = isp->isp_param; 591ea6f23cdSMatt Jacob sdp += cam_sim_bus(xpt_path_sim(cpi->ccb_h.path)); 5924394c92fSMatt Jacob cpi->hba_misc = 0; 593ea6f23cdSMatt Jacob cpi->initiator_id = sdp->isp_initiator_id; 594478f8a96SJustin T. Gibbs cpi->max_target = MAX_TARGETS-1; 59592718a7fSMatt Jacob if (ISP_FW_REVX(isp->isp_fwrev) >= 59692718a7fSMatt Jacob ISP_FW_REV(7, 55, 0)) { 597d3a9eb2eSMatt Jacob #if 0 598478f8a96SJustin T. Gibbs /* 599478f8a96SJustin T. Gibbs * Too much breakage. 600478f8a96SJustin T. Gibbs */ 601c3055363SMatt Jacob cpi->max_lun = (1 << 5) - 1; 602478f8a96SJustin T. Gibbs #else 603c3055363SMatt Jacob cpi->max_lun = (1 << 3) - 1; 604478f8a96SJustin T. Gibbs #endif 605478f8a96SJustin T. Gibbs } else { 606c3055363SMatt Jacob cpi->max_lun = (1 << 3) - 1; 607478f8a96SJustin T. Gibbs } 6089deea857SKenneth D. Merry cpi->base_transfer_speed = 3300; 609478f8a96SJustin T. Gibbs } 610478f8a96SJustin T. Gibbs 611478f8a96SJustin T. Gibbs cpi->bus_id = cam_sim_bus(sim); 612478f8a96SJustin T. Gibbs strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 613478f8a96SJustin T. Gibbs strncpy(cpi->hba_vid, "Qlogic", HBA_IDLEN); 614478f8a96SJustin T. Gibbs strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 615478f8a96SJustin T. Gibbs cpi->unit_number = cam_sim_unit(sim); 616478f8a96SJustin T. Gibbs cpi->ccb_h.status = CAM_REQ_CMP; 617478f8a96SJustin T. Gibbs xpt_done(ccb); 618478f8a96SJustin T. Gibbs break; 619478f8a96SJustin T. Gibbs } 620478f8a96SJustin T. Gibbs default: 621478f8a96SJustin T. Gibbs ccb->ccb_h.status = CAM_REQ_INVALID; 622478f8a96SJustin T. Gibbs xpt_done(ccb); 623478f8a96SJustin T. Gibbs break; 624478f8a96SJustin T. Gibbs } 625478f8a96SJustin T. Gibbs } 626d3a9eb2eSMatt Jacob 627d3a9eb2eSMatt Jacob #define ISPDDB (CAM_DEBUG_INFO|CAM_DEBUG_TRACE|CAM_DEBUG_CDB) 628d3a9eb2eSMatt Jacob void 629c3055363SMatt Jacob isp_done(struct ccb_scsiio *sccb) 630d3a9eb2eSMatt Jacob { 631d3a9eb2eSMatt Jacob struct ispsoftc *isp = XS_ISP(sccb); 632d3a9eb2eSMatt Jacob 633d3a9eb2eSMatt Jacob if (XS_NOERR(sccb)) 634d3a9eb2eSMatt Jacob XS_SETERR(sccb, CAM_REQ_CMP); 635d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 636d3a9eb2eSMatt Jacob sccb->ccb_h.status |= sccb->ccb_h.spriv_field0; 637d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP && 638d3a9eb2eSMatt Jacob (sccb->scsi_status != SCSI_STATUS_OK)) { 639d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_STATUS_MASK; 640d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; 641d3a9eb2eSMatt Jacob } 642d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 643d3a9eb2eSMatt Jacob if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { 644d3a9eb2eSMatt Jacob IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n", 645d3a9eb2eSMatt Jacob isp->isp_name, sccb->ccb_h.target_id, 646d3a9eb2eSMatt Jacob sccb->ccb_h.target_lun, sccb->ccb_h.status)); 647d3a9eb2eSMatt Jacob xpt_freeze_devq(sccb->ccb_h.path, 1); 648d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_DEV_QFRZN; 649d3a9eb2eSMatt Jacob } 650d3a9eb2eSMatt Jacob } 65157c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) { 65257c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE; 653d3a9eb2eSMatt Jacob sccb->ccb_h.status |= CAM_RELEASE_SIMQ; 65457c801f5SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 655d3a9eb2eSMatt Jacob } 656d3a9eb2eSMatt Jacob sccb->ccb_h.status &= ~CAM_SIM_QUEUED; 657d3a9eb2eSMatt Jacob if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) && 658d3a9eb2eSMatt Jacob (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 659d3a9eb2eSMatt Jacob xpt_print_path(sccb->ccb_h.path); 660d3a9eb2eSMatt Jacob printf("cam completion status 0x%x\n", sccb->ccb_h.status); 661d3a9eb2eSMatt Jacob } 662d3a9eb2eSMatt Jacob xpt_done((union ccb *) sccb); 663d3a9eb2eSMatt Jacob } 664d3a9eb2eSMatt Jacob 665cbf57b47SMatt Jacob int 666cbf57b47SMatt Jacob isp_async(isp, cmd, arg) 667cbf57b47SMatt Jacob struct ispsoftc *isp; 668cbf57b47SMatt Jacob ispasync_t cmd; 669cbf57b47SMatt Jacob void *arg; 670cbf57b47SMatt Jacob { 671ea6f23cdSMatt Jacob int bus, rv = 0; 672cbf57b47SMatt Jacob switch (cmd) { 673cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 674cbf57b47SMatt Jacob if (isp->isp_type & ISP_HA_SCSI) { 675cbf57b47SMatt Jacob int flags, tgt; 676cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 677cbf57b47SMatt Jacob struct ccb_trans_settings neg; 678cbf57b47SMatt Jacob struct cam_path *tmppath; 679cbf57b47SMatt Jacob 680cbf57b47SMatt Jacob tgt = *((int *)arg); 681ea6f23cdSMatt Jacob bus = (tgt >> 16) & 0xffff; 682ea6f23cdSMatt Jacob tgt &= 0xffff; 683ea6f23cdSMatt Jacob sdp += bus; 684cbf57b47SMatt Jacob if (xpt_create_path(&tmppath, NULL, 685ea6f23cdSMatt Jacob cam_sim_path(bus? isp->isp_sim2 : isp->isp_sim), 686ea6f23cdSMatt Jacob tgt, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 687cbf57b47SMatt Jacob xpt_print_path(isp->isp_path); 688cbf57b47SMatt Jacob printf("isp_async cannot make temp path for " 689ea6f23cdSMatt Jacob "target %d bus %d\n", tgt, bus); 690cbf57b47SMatt Jacob rv = -1; 691cbf57b47SMatt Jacob break; 692cbf57b47SMatt Jacob } 6934394c92fSMatt Jacob flags = sdp->isp_devparam[tgt].cur_dflags; 694cbf57b47SMatt Jacob neg.valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID; 695cbf57b47SMatt Jacob if (flags & DPARM_DISC) { 696cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_DISC_ENB; 697cbf57b47SMatt Jacob } 698cbf57b47SMatt Jacob if (flags & DPARM_TQING) { 699cbf57b47SMatt Jacob neg.flags |= CCB_TRANS_TAG_ENB; 700cbf57b47SMatt Jacob } 701cbf57b47SMatt Jacob neg.valid |= CCB_TRANS_BUS_WIDTH_VALID; 702cbf57b47SMatt Jacob neg.bus_width = (flags & DPARM_WIDE)? 703cbf57b47SMatt Jacob MSG_EXT_WDTR_BUS_8_BIT : MSG_EXT_WDTR_BUS_16_BIT; 7044394c92fSMatt Jacob neg.sync_period = sdp->isp_devparam[tgt].cur_period; 7054394c92fSMatt Jacob neg.sync_offset = sdp->isp_devparam[tgt].cur_offset; 706cbf57b47SMatt Jacob if (flags & DPARM_SYNC) { 7074394c92fSMatt Jacob neg.valid |= 7084394c92fSMatt Jacob CCB_TRANS_SYNC_RATE_VALID | 709cbf57b47SMatt Jacob CCB_TRANS_SYNC_OFFSET_VALID; 710cbf57b47SMatt Jacob } 711ea6f23cdSMatt Jacob IDPRINTF(3, ("%s: NEW_TGT_PARAMS bus %d tgt %d period " 712ea6f23cdSMatt Jacob "0x%x offset 0x%x flags 0x%x\n", isp->isp_name, 713ea6f23cdSMatt Jacob bus, tgt, neg.sync_period, neg.sync_offset, flags)); 714cbf57b47SMatt Jacob xpt_setup_ccb(&neg.ccb_h, tmppath, 1); 715cbf57b47SMatt Jacob xpt_async(AC_TRANSFER_NEG, tmppath, &neg); 716cbf57b47SMatt Jacob xpt_free_path(tmppath); 717cbf57b47SMatt Jacob } 718cbf57b47SMatt Jacob break; 71957c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 720ea6f23cdSMatt Jacob bus = *((int *)arg); 721ea6f23cdSMatt Jacob printf("%s: SCSI bus reset on bus %d detected\n", 722ea6f23cdSMatt Jacob isp->isp_name, bus); 723ea6f23cdSMatt Jacob if (bus > 0 && isp->isp_path2) { 724ea6f23cdSMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path2, NULL); 725ea6f23cdSMatt Jacob } else if (isp->isp_path) { 72657c801f5SMatt Jacob xpt_async(AC_BUS_RESET, isp->isp_path, NULL); 72757c801f5SMatt Jacob } 72857c801f5SMatt Jacob break; 72957c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 73057c801f5SMatt Jacob if (isp->isp_path) { 73157c801f5SMatt Jacob /* 73257c801f5SMatt Jacob * We can get multiple LOOP downs, so only count one. 73357c801f5SMatt Jacob */ 73457c801f5SMatt Jacob if (!(isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN)) { 73557c801f5SMatt Jacob xpt_freeze_simq(isp->isp_sim, 1); 73657c801f5SMatt Jacob isp->isp_osinfo.simqfrozen |= SIMQFRZ_LOOPDOWN; 73757c801f5SMatt Jacob printf("%s: Loop DOWN- freezing SIMQ until Loop" 73857c801f5SMatt Jacob " comes up\n", isp->isp_name); 73957c801f5SMatt Jacob } 74057c801f5SMatt Jacob } else { 74157c801f5SMatt Jacob printf("%s: Loop DOWN\n", isp->isp_name); 74257c801f5SMatt Jacob } 74357c801f5SMatt Jacob break; 74457c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 74557c801f5SMatt Jacob if (isp->isp_path) { 74657c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen & SIMQFRZ_LOOPDOWN) { 74757c801f5SMatt Jacob xpt_release_simq(isp->isp_sim, 1); 74857c801f5SMatt Jacob isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_LOOPDOWN; 74957c801f5SMatt Jacob if (isp->isp_osinfo.simqfrozen) { 75057c801f5SMatt Jacob printf("%s: Loop UP- SIMQ still " 75157c801f5SMatt Jacob "frozen\n", isp->isp_name); 75257c801f5SMatt Jacob } else { 75357c801f5SMatt Jacob printf("%s: Loop UP-releasing frozen " 75457c801f5SMatt Jacob "SIMQ\n", isp->isp_name); 75557c801f5SMatt Jacob } 75657c801f5SMatt Jacob } 75757c801f5SMatt Jacob } else { 75857c801f5SMatt Jacob printf("%s: Loop UP\n", isp->isp_name); 75957c801f5SMatt Jacob } 76057c801f5SMatt Jacob break; 76157c801f5SMatt Jacob case ISPASYNC_PDB_CHANGE_COMPLETE: 7624394c92fSMatt Jacob if (IS_FC(isp)) { 7634394c92fSMatt Jacob long i = (long) arg; 76457c801f5SMatt Jacob static char *roles[4] = { 76557c801f5SMatt Jacob "No", "Target", "Initiator", "Target/Initiator" 76657c801f5SMatt Jacob }; 7674394c92fSMatt Jacob isp_pdb_t *pdbp = &((fcparam *)isp->isp_param)->isp_pdb[i]; 7684394c92fSMatt Jacob if (pdbp->pdb_options == INVALID_PDB_OPTIONS) { 7694394c92fSMatt Jacob break; 7704394c92fSMatt Jacob } 7714394c92fSMatt Jacob printf("%s: Loop ID %d, %s role\n", isp->isp_name, 7724394c92fSMatt Jacob pdbp->pdb_loopid, roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]); 77357c801f5SMatt Jacob printf(" Node Address 0x%x WWN 0x" 77457c801f5SMatt Jacob "%02x%02x%02x%02x%02x%02x%02x%02x\n", 77557c801f5SMatt Jacob BITS2WORD(pdbp->pdb_portid_bits), 77657c801f5SMatt Jacob pdbp->pdb_portname[0], pdbp->pdb_portname[1], 77757c801f5SMatt Jacob pdbp->pdb_portname[2], pdbp->pdb_portname[3], 77857c801f5SMatt Jacob pdbp->pdb_portname[4], pdbp->pdb_portname[5], 77957c801f5SMatt Jacob pdbp->pdb_portname[6], pdbp->pdb_portname[7]); 78057c801f5SMatt Jacob if (pdbp->pdb_options & PDB_OPTIONS_ADISC) 78157c801f5SMatt Jacob printf(" Hard Address 0x%x WWN 0x" 78257c801f5SMatt Jacob "%02x%02x%02x%02x%02x%02x%02x%02x\n", 78357c801f5SMatt Jacob BITS2WORD(pdbp->pdb_hardaddr_bits), 7844394c92fSMatt Jacob pdbp->pdb_nodename[0], pdbp->pdb_nodename[1], 7854394c92fSMatt Jacob pdbp->pdb_nodename[2], pdbp->pdb_nodename[3], 7864394c92fSMatt Jacob pdbp->pdb_nodename[4], pdbp->pdb_nodename[5], 7874394c92fSMatt Jacob pdbp->pdb_nodename[6], pdbp->pdb_nodename[7]); 78857c801f5SMatt Jacob switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) { 78957c801f5SMatt Jacob case SVC3_TGT_ROLE|SVC3_INI_ROLE: 79057c801f5SMatt Jacob printf(" Master State=%s, Slave State=%s\n", 79157c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_mstate), 79257c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_sstate)); 79357c801f5SMatt Jacob break; 79457c801f5SMatt Jacob case SVC3_TGT_ROLE: 79557c801f5SMatt Jacob printf(" Master State=%s\n", 79657c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_mstate)); 79757c801f5SMatt Jacob break; 79857c801f5SMatt Jacob case SVC3_INI_ROLE: 79957c801f5SMatt Jacob printf(" Slave State=%s\n", 80057c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_sstate)); 80157c801f5SMatt Jacob break; 80257c801f5SMatt Jacob default: 80357c801f5SMatt Jacob break; 80457c801f5SMatt Jacob } 80557c801f5SMatt Jacob break; 80657c801f5SMatt Jacob } 80757c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 80857c801f5SMatt Jacob printf("%s: Name Server Database Changed\n", isp->isp_name); 80957c801f5SMatt Jacob break; 810cbf57b47SMatt Jacob default: 811cbf57b47SMatt Jacob break; 812cbf57b47SMatt Jacob } 813cbf57b47SMatt Jacob return (rv); 814cbf57b47SMatt Jacob } 815cbf57b47SMatt Jacob 81692718a7fSMatt Jacob 81792718a7fSMatt Jacob /* 81892718a7fSMatt Jacob * Locks are held before coming here. 81992718a7fSMatt Jacob */ 82092718a7fSMatt Jacob void 82192718a7fSMatt Jacob isp_uninit(struct ispsoftc *isp) 82292718a7fSMatt Jacob { 823ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 82492718a7fSMatt Jacob DISABLE_INTS(isp); 82592718a7fSMatt Jacob } 826478f8a96SJustin T. Gibbs #else 827478f8a96SJustin T. Gibbs 82892718a7fSMatt Jacob #define WATCH_INTERVAL 30 82992718a7fSMatt Jacob 8306054c3f6SMatt Jacob static void ispminphys __P((struct buf *)); 8316054c3f6SMatt Jacob static u_int32_t isp_adapter_info __P((int)); 832478f8a96SJustin T. Gibbs static int ispcmd __P((ISP_SCSI_XFER_T *)); 833c3055363SMatt Jacob static void isp_watch __P((void *arg)); 8346054c3f6SMatt Jacob 8356054c3f6SMatt Jacob static struct scsi_adapter isp_switch = { 836478f8a96SJustin T. Gibbs ispcmd, ispminphys, 0, 0, isp_adapter_info, "isp", { 0, 0 } 8376054c3f6SMatt Jacob }; 8386054c3f6SMatt Jacob static struct scsi_device isp_dev = { 8396054c3f6SMatt Jacob NULL, NULL, NULL, NULL, "isp", 0, { 0, 0 } 8406054c3f6SMatt Jacob }; 841478f8a96SJustin T. Gibbs static int isp_poll __P((struct ispsoftc *, ISP_SCSI_XFER_T *, int)); 842478f8a96SJustin T. Gibbs 8436054c3f6SMatt Jacob 8446054c3f6SMatt Jacob /* 8456054c3f6SMatt Jacob * Complete attachment of hardware, include subdevices. 8466054c3f6SMatt Jacob */ 8476054c3f6SMatt Jacob void 848c3055363SMatt Jacob isp_attach(struct ispsoftc *isp) 8496054c3f6SMatt Jacob { 8506054c3f6SMatt Jacob struct scsibus_data *scbus; 8516054c3f6SMatt Jacob 8526054c3f6SMatt Jacob scbus = scsi_alloc_bus(); 8536054c3f6SMatt Jacob if(!scbus) { 8546054c3f6SMatt Jacob return; 8556054c3f6SMatt Jacob } 85657c801f5SMatt Jacob if (isp->isp_state == ISP_INITSTATE) 8576054c3f6SMatt Jacob isp->isp_state = ISP_RUNSTATE; 85857c801f5SMatt Jacob 85992718a7fSMatt Jacob timeout(isp_watch, isp, WATCH_INTERVAL * hz); 86092718a7fSMatt Jacob isp->isp_dogactive = 1; 8616054c3f6SMatt Jacob 8626054c3f6SMatt Jacob isp->isp_osinfo._link.adapter_unit = isp->isp_osinfo.unit; 8636054c3f6SMatt Jacob isp->isp_osinfo._link.adapter_softc = isp; 8646054c3f6SMatt Jacob isp->isp_osinfo._link.adapter = &isp_switch; 8656054c3f6SMatt Jacob isp->isp_osinfo._link.device = &isp_dev; 8666054c3f6SMatt Jacob isp->isp_osinfo._link.flags = 0; 8676054c3f6SMatt Jacob if (isp->isp_type & ISP_HA_FC) { 868478f8a96SJustin T. Gibbs isp->isp_osinfo._link.adapter_targ = 869478f8a96SJustin T. Gibbs ((fcparam *)isp->isp_param)->isp_loopid; 8706054c3f6SMatt Jacob scbus->maxtarg = MAX_FC_TARG-1; 8716054c3f6SMatt Jacob } else { 872ea6f23cdSMatt Jacob int tmp = 0; /* XXXX: Which Bus? */ 87392718a7fSMatt Jacob isp->isp_osinfo.delay_throttle_count = 1; 8746054c3f6SMatt Jacob isp->isp_osinfo._link.adapter_targ = 8756054c3f6SMatt Jacob ((sdparam *)isp->isp_param)->isp_initiator_id; 8766054c3f6SMatt Jacob scbus->maxtarg = MAX_TARGETS-1; 877ea6f23cdSMatt Jacob (void) isp_control(isp, ISPCTL_RESET_BUS, &tmp); 8788ea807adSMatt Jacob } 8792b052931SMatt Jacob 8806054c3f6SMatt Jacob /* 8816054c3f6SMatt Jacob * Prepare the scsibus_data area for the upperlevel scsi code. 8826054c3f6SMatt Jacob */ 8836054c3f6SMatt Jacob scbus->adapter_link = &isp->isp_osinfo._link; 8846054c3f6SMatt Jacob 8856054c3f6SMatt Jacob /* 8866054c3f6SMatt Jacob * ask the adapter what subunits are present 8876054c3f6SMatt Jacob */ 8886054c3f6SMatt Jacob scsi_attachdevs(scbus); 8896054c3f6SMatt Jacob } 8906054c3f6SMatt Jacob 8916054c3f6SMatt Jacob 8926054c3f6SMatt Jacob /* 8936054c3f6SMatt Jacob * minphys our xfers 8946054c3f6SMatt Jacob * 8956054c3f6SMatt Jacob * Unfortunately, the buffer pointer describes the target device- not the 8966054c3f6SMatt Jacob * adapter device, so we can't use the pointer to find out what kind of 8976054c3f6SMatt Jacob * adapter we are and adjust accordingly. 8986054c3f6SMatt Jacob */ 8996054c3f6SMatt Jacob 9006054c3f6SMatt Jacob static void 901c3055363SMatt Jacob ispminphys(struct buf *bp) 9026054c3f6SMatt Jacob { 9036054c3f6SMatt Jacob /* 904478f8a96SJustin T. Gibbs * Only the 10X0 has a 24 bit limit. 9056054c3f6SMatt Jacob */ 9066054c3f6SMatt Jacob if (bp->b_bcount >= (1 << 24)) { 9076054c3f6SMatt Jacob bp->b_bcount = (1 << 24); 9086054c3f6SMatt Jacob } 9096054c3f6SMatt Jacob } 9106054c3f6SMatt Jacob 9116054c3f6SMatt Jacob static u_int32_t 912c3055363SMatt Jacob isp_adapter_info(int unit) 9136054c3f6SMatt Jacob { 9146054c3f6SMatt Jacob /* 9156054c3f6SMatt Jacob * XXX: FIND ISP BASED UPON UNIT AND GET REAL QUEUE LIMIT FROM THAT 9166054c3f6SMatt Jacob */ 9176054c3f6SMatt Jacob return (2); 9186054c3f6SMatt Jacob } 919478f8a96SJustin T. Gibbs 920478f8a96SJustin T. Gibbs static int 921c3055363SMatt Jacob ispcmd(ISP_SCSI_XFER_T *xs) 922478f8a96SJustin T. Gibbs { 923478f8a96SJustin T. Gibbs struct ispsoftc *isp; 92457c801f5SMatt Jacob int r, s; 925478f8a96SJustin T. Gibbs 926478f8a96SJustin T. Gibbs isp = XS_ISP(xs); 92757c801f5SMatt Jacob s = splbio(); 92857c801f5SMatt Jacob DISABLE_INTS(isp); 92957c801f5SMatt Jacob if (isp->isp_state != ISP_RUNSTATE) { 93057c801f5SMatt Jacob isp_init(isp); 93157c801f5SMatt Jacob if (isp->isp_state != ISP_INITSTATE) { 93257c801f5SMatt Jacob ENABLE_INTS(isp); 93357c801f5SMatt Jacob (void) splx(s); 93457c801f5SMatt Jacob XS_SETERR(xs, HBA_BOTCH); 93557c801f5SMatt Jacob return (CMD_COMPLETE); 93657c801f5SMatt Jacob } 93792718a7fSMatt Jacob isp->isp_state = ISP_RUNSTATE; 93857c801f5SMatt Jacob } 939478f8a96SJustin T. Gibbs r = ispscsicmd(xs); 94057c801f5SMatt Jacob ENABLE_INTS(isp); 941478f8a96SJustin T. Gibbs if (r != CMD_QUEUED || (xs->flags & SCSI_NOMASK) == 0) { 94257c801f5SMatt Jacob (void) splx(s); 943478f8a96SJustin T. Gibbs return (r); 944478f8a96SJustin T. Gibbs } 945478f8a96SJustin T. Gibbs 946478f8a96SJustin T. Gibbs /* 947478f8a96SJustin T. Gibbs * If we can't use interrupts, poll on completion. 948478f8a96SJustin T. Gibbs */ 949478f8a96SJustin T. Gibbs if (isp_poll(isp, xs, XS_TIME(xs))) { 950478f8a96SJustin T. Gibbs /* 951478f8a96SJustin T. Gibbs * If no other error occurred but we didn't finish, 952478f8a96SJustin T. Gibbs * something bad happened. 953478f8a96SJustin T. Gibbs */ 954478f8a96SJustin T. Gibbs if (XS_IS_CMD_DONE(xs) == 0) { 955478f8a96SJustin T. Gibbs isp->isp_nactive--; 956478f8a96SJustin T. Gibbs if (isp->isp_nactive < 0) 957478f8a96SJustin T. Gibbs isp->isp_nactive = 0; 958478f8a96SJustin T. Gibbs if (XS_NOERR(xs)) { 959478f8a96SJustin T. Gibbs isp_lostcmd(isp, xs); 960478f8a96SJustin T. Gibbs XS_SETERR(xs, HBA_BOTCH); 961478f8a96SJustin T. Gibbs } 962478f8a96SJustin T. Gibbs } 963478f8a96SJustin T. Gibbs } 96457c801f5SMatt Jacob (void) splx(s); 965478f8a96SJustin T. Gibbs return (CMD_COMPLETE); 966478f8a96SJustin T. Gibbs } 967478f8a96SJustin T. Gibbs 968478f8a96SJustin T. Gibbs static int 969c3055363SMatt Jacob isp_poll(struct ispsoftc *isp, ISP_SCSI_XFER_T *xs, int mswait) 970478f8a96SJustin T. Gibbs { 971478f8a96SJustin T. Gibbs 972478f8a96SJustin T. Gibbs while (mswait) { 973478f8a96SJustin T. Gibbs /* Try the interrupt handling routine */ 974478f8a96SJustin T. Gibbs (void)isp_intr((void *)isp); 975478f8a96SJustin T. Gibbs 976478f8a96SJustin T. Gibbs /* See if the xs is now done */ 977478f8a96SJustin T. Gibbs if (XS_IS_CMD_DONE(xs)) 978478f8a96SJustin T. Gibbs return (0); 979478f8a96SJustin T. Gibbs SYS_DELAY(1000); /* wait one millisecond */ 980478f8a96SJustin T. Gibbs mswait--; 981478f8a96SJustin T. Gibbs } 982478f8a96SJustin T. Gibbs return (1); 983478f8a96SJustin T. Gibbs } 984c3055363SMatt Jacob 985c3055363SMatt Jacob static void 986c3055363SMatt Jacob isp_watch(void *arg) 987c3055363SMatt Jacob { 988c3055363SMatt Jacob int i; 989c3055363SMatt Jacob struct ispsoftc *isp = arg; 990c3055363SMatt Jacob ISP_SCSI_XFER_T *xs; 99192718a7fSMatt Jacob int s; 992c3055363SMatt Jacob 993c3055363SMatt Jacob /* 994c3055363SMatt Jacob * Look for completely dead commands (but not polled ones). 995c3055363SMatt Jacob */ 99692718a7fSMatt Jacob s = splbio(); 997c3055363SMatt Jacob for (i = 0; i < RQUEST_QUEUE_LEN; i++) { 998c3055363SMatt Jacob if ((xs = (ISP_SCSI_XFER_T *) isp->isp_xflist[i]) == NULL) { 999c3055363SMatt Jacob continue; 1000c3055363SMatt Jacob } 1001c3055363SMatt Jacob if (XS_TIME(xs) == 0) { 1002c3055363SMatt Jacob continue; 1003c3055363SMatt Jacob } 1004c3055363SMatt Jacob XS_TIME(xs) -= (WATCH_INTERVAL * 1000); 100592718a7fSMatt Jacob 1006c3055363SMatt Jacob /* 1007c3055363SMatt Jacob * Avoid later thinking that this 1008c3055363SMatt Jacob * transaction is not being timed. 1009c3055363SMatt Jacob * Then give ourselves to watchdog 1010c3055363SMatt Jacob * periods of grace. 1011c3055363SMatt Jacob */ 1012c3055363SMatt Jacob if (XS_TIME(xs) == 0) 1013c3055363SMatt Jacob XS_TIME(xs) = 1; 1014c3055363SMatt Jacob else if (XS_TIME(xs) > -(2 * WATCH_INTERVAL * 1000)) { 1015c3055363SMatt Jacob continue; 1016c3055363SMatt Jacob } 101792718a7fSMatt Jacob if (IS_SCSI(isp)) { 101892718a7fSMatt Jacob isp->isp_osinfo.delay_throttle_count = 1; 101992718a7fSMatt Jacob } 1020c3055363SMatt Jacob if (isp_control(isp, ISPCTL_ABORT_CMD, xs)) { 1021c3055363SMatt Jacob printf("%s: isp_watch failed to abort command\n", 1022c3055363SMatt Jacob isp->isp_name); 1023c3055363SMatt Jacob isp_restart(isp); 1024c3055363SMatt Jacob break; 1025c3055363SMatt Jacob } 1026c3055363SMatt Jacob } 102792718a7fSMatt Jacob if (isp->isp_osinfo.delay_throttle_count) { 102892718a7fSMatt Jacob if (--isp->isp_osinfo.delay_throttle_count == 0) { 102992718a7fSMatt Jacob sdparam *sdp = isp->isp_param; 103092718a7fSMatt Jacob for (i = 0; i < MAX_TARGETS; i++) { 103192718a7fSMatt Jacob sdp->isp_devparam[i].dev_flags |= 103292718a7fSMatt Jacob DPARM_WIDE|DPARM_SYNC|DPARM_TQING; 103392718a7fSMatt Jacob sdp->isp_devparam[i].dev_update = 1; 103492718a7fSMatt Jacob } 103592718a7fSMatt Jacob isp->isp_update = 1; 103692718a7fSMatt Jacob } 103792718a7fSMatt Jacob } 103892718a7fSMatt Jacob timeout(isp_watch, isp, WATCH_INTERVAL * hz); 103992718a7fSMatt Jacob isp->isp_dogactive = 1; 104092718a7fSMatt Jacob splx(s); 1041c3055363SMatt Jacob } 1042cbf57b47SMatt Jacob 1043cbf57b47SMatt Jacob int 1044cbf57b47SMatt Jacob isp_async(isp, cmd, arg) 1045cbf57b47SMatt Jacob struct ispsoftc *isp; 1046cbf57b47SMatt Jacob ispasync_t cmd; 1047cbf57b47SMatt Jacob void *arg; 1048cbf57b47SMatt Jacob { 1049cbf57b47SMatt Jacob switch (cmd) { 1050cbf57b47SMatt Jacob case ISPASYNC_NEW_TGT_PARAMS: 1051cbf57b47SMatt Jacob if (isp->isp_type & ISP_HA_SCSI) { 1052cbf57b47SMatt Jacob sdparam *sdp = isp->isp_param; 1053cbf57b47SMatt Jacob char *wt; 10544394c92fSMatt Jacob int mhz, flags, tgt, period; 1055cbf57b47SMatt Jacob 1056cbf57b47SMatt Jacob tgt = *((int *) arg); 1057cbf57b47SMatt Jacob 10584394c92fSMatt Jacob flags = sdp->isp_devparam[tgt].cur_dflags; 10594394c92fSMatt Jacob period = sdp->isp_devparam[tgt].cur_period; 10604394c92fSMatt Jacob if ((flags & DPARM_SYNC) && period && 10614394c92fSMatt Jacob (sdp->isp_devparam[tgt].cur_offset) != 0) { 10624394c92fSMatt Jacob if (sdp->isp_lvdmode) { 10634394c92fSMatt Jacob switch (period) { 10644394c92fSMatt Jacob case 0xa: 10654394c92fSMatt Jacob mhz = 40; 10664394c92fSMatt Jacob break; 10674394c92fSMatt Jacob case 0xb: 10684394c92fSMatt Jacob mhz = 33; 10694394c92fSMatt Jacob break; 10704394c92fSMatt Jacob case 0xc: 10714394c92fSMatt Jacob mhz = 25; 10724394c92fSMatt Jacob break; 10734394c92fSMatt Jacob default: 10744394c92fSMatt Jacob mhz = 1000 / (period * 4); 10754394c92fSMatt Jacob break; 10764394c92fSMatt Jacob } 1077cbf57b47SMatt Jacob } else { 10784394c92fSMatt Jacob mhz = 1000 / (period * 4); 10794394c92fSMatt Jacob } 10804394c92fSMatt Jacob } else { 10814394c92fSMatt Jacob mhz = 0; 1082cbf57b47SMatt Jacob } 1083cbf57b47SMatt Jacob switch (flags & (DPARM_WIDE|DPARM_TQING)) { 1084cbf57b47SMatt Jacob case DPARM_WIDE: 1085cbf57b47SMatt Jacob wt = ", 16 bit wide\n"; 1086cbf57b47SMatt Jacob break; 1087cbf57b47SMatt Jacob case DPARM_TQING: 1088cbf57b47SMatt Jacob wt = ", Tagged Queueing Enabled\n"; 1089cbf57b47SMatt Jacob break; 1090cbf57b47SMatt Jacob case DPARM_WIDE|DPARM_TQING: 1091cbf57b47SMatt Jacob wt = ", 16 bit wide, Tagged Queueing Enabled\n"; 1092cbf57b47SMatt Jacob break; 1093cbf57b47SMatt Jacob default: 1094cbf57b47SMatt Jacob wt = "\n"; 1095cbf57b47SMatt Jacob break; 1096cbf57b47SMatt Jacob } 10974394c92fSMatt Jacob if (mhz) { 1098cbf57b47SMatt Jacob printf("%s: Target %d at %dMHz Max Offset %d%s", 10994394c92fSMatt Jacob isp->isp_name, tgt, mhz, 11004394c92fSMatt Jacob sdp->isp_devparam[tgt].cur_offset, wt); 1101cbf57b47SMatt Jacob } else { 1102cbf57b47SMatt Jacob printf("%s: Target %d Async Mode%s", 1103cbf57b47SMatt Jacob isp->isp_name, tgt, wt); 1104cbf57b47SMatt Jacob } 1105cbf57b47SMatt Jacob } 1106cbf57b47SMatt Jacob break; 110757c801f5SMatt Jacob case ISPASYNC_BUS_RESET: 110857c801f5SMatt Jacob printf("%s: SCSI bus reset detected\n", isp->isp_name); 110957c801f5SMatt Jacob break; 111057c801f5SMatt Jacob case ISPASYNC_LOOP_DOWN: 111157c801f5SMatt Jacob printf("%s: Loop DOWN\n", isp->isp_name); 111257c801f5SMatt Jacob break; 111357c801f5SMatt Jacob case ISPASYNC_LOOP_UP: 111457c801f5SMatt Jacob printf("%s: Loop UP\n", isp->isp_name); 111557c801f5SMatt Jacob break; 111657c801f5SMatt Jacob case ISPASYNC_PDB_CHANGE_COMPLETE: 111757c801f5SMatt Jacob if (isp->isp_type & ISP_HA_FC) { 111857c801f5SMatt Jacob int i; 111957c801f5SMatt Jacob static char *roles[4] = { 112057c801f5SMatt Jacob "No", "Target", "Initiator", "Target/Initiator" 112157c801f5SMatt Jacob }; 112292718a7fSMatt Jacob for (i = 0; i < MAX_FC_TARG; i++) { 112357c801f5SMatt Jacob isp_pdb_t *pdbp = 112457c801f5SMatt Jacob &((fcparam *)isp->isp_param)->isp_pdb[i]; 112557c801f5SMatt Jacob if (pdbp->pdb_options == INVALID_PDB_OPTIONS) 112657c801f5SMatt Jacob continue; 112757c801f5SMatt Jacob printf("%s: Loop ID %d, %s role\n", 112857c801f5SMatt Jacob isp->isp_name, pdbp->pdb_loopid, 112957c801f5SMatt Jacob roles[(pdbp->pdb_prli_svc3 >> 4) & 0x3]); 113057c801f5SMatt Jacob printf(" Node Address 0x%x WWN 0x" 113157c801f5SMatt Jacob "%02x%02x%02x%02x%02x%02x%02x%02x\n", 113257c801f5SMatt Jacob BITS2WORD(pdbp->pdb_portid_bits), 113357c801f5SMatt Jacob pdbp->pdb_portname[0], pdbp->pdb_portname[1], 113457c801f5SMatt Jacob pdbp->pdb_portname[2], pdbp->pdb_portname[3], 113557c801f5SMatt Jacob pdbp->pdb_portname[4], pdbp->pdb_portname[5], 113657c801f5SMatt Jacob pdbp->pdb_portname[6], pdbp->pdb_portname[7]); 113757c801f5SMatt Jacob if (pdbp->pdb_options & PDB_OPTIONS_ADISC) 113857c801f5SMatt Jacob printf(" Hard Address 0x%x WWN 0x" 113957c801f5SMatt Jacob "%02x%02x%02x%02x%02x%02x%02x%02x\n", 114057c801f5SMatt Jacob BITS2WORD(pdbp->pdb_hardaddr_bits), 114157c801f5SMatt Jacob pdbp->pdb_nodename[0], 114257c801f5SMatt Jacob pdbp->pdb_nodename[1], 114357c801f5SMatt Jacob pdbp->pdb_nodename[2], 114457c801f5SMatt Jacob pdbp->pdb_nodename[3], 114557c801f5SMatt Jacob pdbp->pdb_nodename[4], 114657c801f5SMatt Jacob pdbp->pdb_nodename[5], 114757c801f5SMatt Jacob pdbp->pdb_nodename[6], 114857c801f5SMatt Jacob pdbp->pdb_nodename[7]); 114957c801f5SMatt Jacob switch (pdbp->pdb_prli_svc3 & SVC3_ROLE_MASK) { 115057c801f5SMatt Jacob case SVC3_TGT_ROLE|SVC3_INI_ROLE: 115157c801f5SMatt Jacob printf(" Master State=%s, Slave State=%s\n", 115257c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_mstate), 115357c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_sstate)); 115457c801f5SMatt Jacob break; 115557c801f5SMatt Jacob case SVC3_TGT_ROLE: 115657c801f5SMatt Jacob printf(" Master State=%s\n", 115757c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_mstate)); 115857c801f5SMatt Jacob break; 115957c801f5SMatt Jacob case SVC3_INI_ROLE: 116057c801f5SMatt Jacob printf(" Slave State=%s\n", 116157c801f5SMatt Jacob isp2100_pdb_statename(pdbp->pdb_sstate)); 116257c801f5SMatt Jacob break; 116357c801f5SMatt Jacob default: 116457c801f5SMatt Jacob break; 116557c801f5SMatt Jacob } 116657c801f5SMatt Jacob } 116757c801f5SMatt Jacob break; 116857c801f5SMatt Jacob } 116957c801f5SMatt Jacob case ISPASYNC_CHANGE_NOTIFY: 117057c801f5SMatt Jacob printf("%s: Name Server Database Changed\n", isp->isp_name); 117157c801f5SMatt Jacob break; 1172cbf57b47SMatt Jacob default: 1173cbf57b47SMatt Jacob break; 1174cbf57b47SMatt Jacob } 1175cbf57b47SMatt Jacob return (0); 1176cbf57b47SMatt Jacob } 1177c3055363SMatt Jacob 1178c3055363SMatt Jacob /* 1179c3055363SMatt Jacob * Free any associated resources prior to decommissioning and 1180c3055363SMatt Jacob * set the card to a known state (so it doesn't wake up and kick 1181c3055363SMatt Jacob * us when we aren't expecting it to). 1182c3055363SMatt Jacob * 1183c3055363SMatt Jacob * Locks are held before coming here. 1184c3055363SMatt Jacob */ 1185c3055363SMatt Jacob void 118692718a7fSMatt Jacob isp_uninit(isp) 118792718a7fSMatt Jacob struct ispsoftc *isp; 1188c3055363SMatt Jacob { 118992718a7fSMatt Jacob int s = splbio(); 1190c3055363SMatt Jacob /* 1191c3055363SMatt Jacob * Leave with interrupts disabled. 1192c3055363SMatt Jacob */ 1193ea6f23cdSMatt Jacob ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); 1194c3055363SMatt Jacob DISABLE_INTS(isp); 1195c3055363SMatt Jacob 1196c3055363SMatt Jacob /* 1197c3055363SMatt Jacob * Turn off the watchdog (if active). 1198c3055363SMatt Jacob */ 119992718a7fSMatt Jacob if (isp->isp_dogactive) { 120092718a7fSMatt Jacob untimeout(isp_watch, isp); 120192718a7fSMatt Jacob isp->isp_dogactive = 0; 120292718a7fSMatt Jacob } 1203c3055363SMatt Jacob /* 1204c3055363SMatt Jacob * And out... 1205c3055363SMatt Jacob */ 120692718a7fSMatt Jacob splx(s); 1207c3055363SMatt Jacob } 120892718a7fSMatt Jacob #endif 1209