1*991554f2SKenneth D. Merry /*- 2*991554f2SKenneth D. Merry * Copyright (c) 2009 Yahoo! Inc. 3*991554f2SKenneth D. Merry * Copyright (c) 2011-2014 LSI Corp. 4*991554f2SKenneth D. Merry * All rights reserved. 5*991554f2SKenneth D. Merry * 6*991554f2SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 7*991554f2SKenneth D. Merry * modification, are permitted provided that the following conditions 8*991554f2SKenneth D. Merry * are met: 9*991554f2SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 10*991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer. 11*991554f2SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright 12*991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the 13*991554f2SKenneth D. Merry * documentation and/or other materials provided with the distribution. 14*991554f2SKenneth D. Merry * 15*991554f2SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*991554f2SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*991554f2SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*991554f2SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*991554f2SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*991554f2SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*991554f2SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*991554f2SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*991554f2SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*991554f2SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*991554f2SKenneth D. Merry * SUCH DAMAGE. 26*991554f2SKenneth D. Merry */ 27*991554f2SKenneth D. Merry 28*991554f2SKenneth D. Merry #include <sys/cdefs.h> 29*991554f2SKenneth D. Merry __FBSDID("$FreeBSD$"); 30*991554f2SKenneth D. Merry 31*991554f2SKenneth D. Merry /* Communications core for LSI MPT2 */ 32*991554f2SKenneth D. Merry 33*991554f2SKenneth D. Merry /* TODO Move headers to mprvar */ 34*991554f2SKenneth D. Merry #include <sys/types.h> 35*991554f2SKenneth D. Merry #include <sys/param.h> 36*991554f2SKenneth D. Merry #include <sys/systm.h> 37*991554f2SKenneth D. Merry #include <sys/kernel.h> 38*991554f2SKenneth D. Merry #include <sys/selinfo.h> 39*991554f2SKenneth D. Merry #include <sys/module.h> 40*991554f2SKenneth D. Merry #include <sys/bus.h> 41*991554f2SKenneth D. Merry #include <sys/conf.h> 42*991554f2SKenneth D. Merry #include <sys/bio.h> 43*991554f2SKenneth D. Merry #include <sys/malloc.h> 44*991554f2SKenneth D. Merry #include <sys/uio.h> 45*991554f2SKenneth D. Merry #include <sys/sysctl.h> 46*991554f2SKenneth D. Merry #include <sys/endian.h> 47*991554f2SKenneth D. Merry #include <sys/queue.h> 48*991554f2SKenneth D. Merry #include <sys/kthread.h> 49*991554f2SKenneth D. Merry #include <sys/taskqueue.h> 50*991554f2SKenneth D. Merry #include <sys/sbuf.h> 51*991554f2SKenneth D. Merry 52*991554f2SKenneth D. Merry #include <machine/bus.h> 53*991554f2SKenneth D. Merry #include <machine/resource.h> 54*991554f2SKenneth D. Merry #include <sys/rman.h> 55*991554f2SKenneth D. Merry 56*991554f2SKenneth D. Merry #include <machine/stdarg.h> 57*991554f2SKenneth D. Merry 58*991554f2SKenneth D. Merry #include <cam/cam.h> 59*991554f2SKenneth D. Merry #include <cam/cam_ccb.h> 60*991554f2SKenneth D. Merry #include <cam/cam_debug.h> 61*991554f2SKenneth D. Merry #include <cam/cam_sim.h> 62*991554f2SKenneth D. Merry #include <cam/cam_xpt_sim.h> 63*991554f2SKenneth D. Merry #include <cam/cam_xpt_periph.h> 64*991554f2SKenneth D. Merry #include <cam/cam_periph.h> 65*991554f2SKenneth D. Merry #include <cam/scsi/scsi_all.h> 66*991554f2SKenneth D. Merry #include <cam/scsi/scsi_message.h> 67*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 68*991554f2SKenneth D. Merry #include <cam/scsi/smp_all.h> 69*991554f2SKenneth D. Merry #endif 70*991554f2SKenneth D. Merry 71*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h> 72*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h> 73*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h> 74*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h> 75*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h> 76*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h> 77*991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h> 78*991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h> 79*991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h> 80*991554f2SKenneth D. Merry #include <dev/mpr/mpr_table.h> 81*991554f2SKenneth D. Merry #include <dev/mpr/mpr_sas.h> 82*991554f2SKenneth D. Merry 83*991554f2SKenneth D. Merry #define MPRSAS_DISCOVERY_TIMEOUT 20 84*991554f2SKenneth D. Merry #define MPRSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ 85*991554f2SKenneth D. Merry 86*991554f2SKenneth D. Merry /* 87*991554f2SKenneth D. Merry * static array to check SCSI OpCode for EEDP protection bits 88*991554f2SKenneth D. Merry */ 89*991554f2SKenneth D. Merry #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP 90*991554f2SKenneth D. Merry #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 91*991554f2SKenneth D. Merry #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 92*991554f2SKenneth D. Merry static uint8_t op_code_prot[256] = { 93*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 96*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97*991554f2SKenneth D. Merry 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 102*991554f2SKenneth D. Merry 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 104*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108*991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 109*991554f2SKenneth D. Merry }; 110*991554f2SKenneth D. Merry 111*991554f2SKenneth D. Merry MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory"); 112*991554f2SKenneth D. Merry 113*991554f2SKenneth D. Merry static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *); 114*991554f2SKenneth D. Merry static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *); 115*991554f2SKenneth D. Merry static void mprsas_action(struct cam_sim *sim, union ccb *ccb); 116*991554f2SKenneth D. Merry static void mprsas_poll(struct cam_sim *sim); 117*991554f2SKenneth D. Merry static void mprsas_scsiio_timeout(void *data); 118*991554f2SKenneth D. Merry static void mprsas_abort_complete(struct mpr_softc *sc, 119*991554f2SKenneth D. Merry struct mpr_command *cm); 120*991554f2SKenneth D. Merry static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *); 121*991554f2SKenneth D. Merry static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *); 122*991554f2SKenneth D. Merry static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *); 123*991554f2SKenneth D. Merry static void mprsas_resetdev_complete(struct mpr_softc *, 124*991554f2SKenneth D. Merry struct mpr_command *); 125*991554f2SKenneth D. Merry static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 126*991554f2SKenneth D. Merry struct mpr_command *cm); 127*991554f2SKenneth D. Merry static int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, 128*991554f2SKenneth D. Merry uint8_t type); 129*991554f2SKenneth D. Merry static void mprsas_async(void *callback_arg, uint32_t code, 130*991554f2SKenneth D. Merry struct cam_path *path, void *arg); 131*991554f2SKenneth D. Merry static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, 132*991554f2SKenneth D. Merry struct ccb_getdev *cgd); 133*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 134*991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 135*991554f2SKenneth D. Merry static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 136*991554f2SKenneth D. Merry struct ccb_getdev *cgd); 137*991554f2SKenneth D. Merry static void mprsas_read_cap_done(struct cam_periph *periph, 138*991554f2SKenneth D. Merry union ccb *done_ccb); 139*991554f2SKenneth D. Merry #endif 140*991554f2SKenneth D. Merry static int mprsas_send_portenable(struct mpr_softc *sc); 141*991554f2SKenneth D. Merry static void mprsas_portenable_complete(struct mpr_softc *sc, 142*991554f2SKenneth D. Merry struct mpr_command *cm); 143*991554f2SKenneth D. Merry 144*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 145*991554f2SKenneth D. Merry static void 146*991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm); 147*991554f2SKenneth D. Merry static void mprsas_send_smpcmd(struct mprsas_softc *sassc, 148*991554f2SKenneth D. Merry union ccb *ccb, uint64_t sasaddr); 149*991554f2SKenneth D. Merry static void 150*991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); 151*991554f2SKenneth D. Merry #endif 152*991554f2SKenneth D. Merry 153*991554f2SKenneth D. Merry struct mprsas_target * 154*991554f2SKenneth D. Merry mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start, 155*991554f2SKenneth D. Merry uint16_t handle) 156*991554f2SKenneth D. Merry { 157*991554f2SKenneth D. Merry struct mprsas_target *target; 158*991554f2SKenneth D. Merry int i; 159*991554f2SKenneth D. Merry 160*991554f2SKenneth D. Merry for (i = start; i < sassc->maxtargets; i++) { 161*991554f2SKenneth D. Merry target = &sassc->targets[i]; 162*991554f2SKenneth D. Merry if (target->handle == handle) 163*991554f2SKenneth D. Merry return (target); 164*991554f2SKenneth D. Merry } 165*991554f2SKenneth D. Merry 166*991554f2SKenneth D. Merry return (NULL); 167*991554f2SKenneth D. Merry } 168*991554f2SKenneth D. Merry 169*991554f2SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing 170*991554f2SKenneth D. Merry * commands before device handles have been found by discovery. Since 171*991554f2SKenneth D. Merry * discovery involves reading config pages and possibly sending commands, 172*991554f2SKenneth D. Merry * discovery actions may continue even after we receive the end of discovery 173*991554f2SKenneth D. Merry * event, so refcount discovery actions instead of assuming we can unfreeze 174*991554f2SKenneth D. Merry * the simq when we get the event. 175*991554f2SKenneth D. Merry */ 176*991554f2SKenneth D. Merry void 177*991554f2SKenneth D. Merry mprsas_startup_increment(struct mprsas_softc *sassc) 178*991554f2SKenneth D. Merry { 179*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 180*991554f2SKenneth D. Merry 181*991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 182*991554f2SKenneth D. Merry if (sassc->startup_refcount++ == 0) { 183*991554f2SKenneth D. Merry /* just starting, freeze the simq */ 184*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 185*991554f2SKenneth D. Merry "%s freezing simq\n", __func__); 186*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039 187*991554f2SKenneth D. Merry xpt_hold_boot(); 188*991554f2SKenneth D. Merry #endif 189*991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 190*991554f2SKenneth D. Merry } 191*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 192*991554f2SKenneth D. Merry sassc->startup_refcount); 193*991554f2SKenneth D. Merry } 194*991554f2SKenneth D. Merry } 195*991554f2SKenneth D. Merry 196*991554f2SKenneth D. Merry void 197*991554f2SKenneth D. Merry mprsas_release_simq_reinit(struct mprsas_softc *sassc) 198*991554f2SKenneth D. Merry { 199*991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 200*991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 201*991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 202*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n"); 203*991554f2SKenneth D. Merry } 204*991554f2SKenneth D. Merry } 205*991554f2SKenneth D. Merry 206*991554f2SKenneth D. Merry void 207*991554f2SKenneth D. Merry mprsas_startup_decrement(struct mprsas_softc *sassc) 208*991554f2SKenneth D. Merry { 209*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 210*991554f2SKenneth D. Merry 211*991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 212*991554f2SKenneth D. Merry if (--sassc->startup_refcount == 0) { 213*991554f2SKenneth D. Merry /* finished all discovery-related actions, release 214*991554f2SKenneth D. Merry * the simq and rescan for the latest topology. 215*991554f2SKenneth D. Merry */ 216*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 217*991554f2SKenneth D. Merry "%s releasing simq\n", __func__); 218*991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_IN_STARTUP; 219*991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 220*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039 221*991554f2SKenneth D. Merry xpt_release_boot(); 222*991554f2SKenneth D. Merry #else 223*991554f2SKenneth D. Merry mprsas_rescan_target(sassc->sc, NULL); 224*991554f2SKenneth D. Merry #endif 225*991554f2SKenneth D. Merry } 226*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 227*991554f2SKenneth D. Merry sassc->startup_refcount); 228*991554f2SKenneth D. Merry } 229*991554f2SKenneth D. Merry } 230*991554f2SKenneth D. Merry 231*991554f2SKenneth D. Merry /* LSI's firmware requires us to stop sending commands when we're doing task 232*991554f2SKenneth D. Merry * management, so refcount the TMs and keep the simq frozen when any are in 233*991554f2SKenneth D. Merry * use. 234*991554f2SKenneth D. Merry */ 235*991554f2SKenneth D. Merry struct mpr_command * 236*991554f2SKenneth D. Merry mprsas_alloc_tm(struct mpr_softc *sc) 237*991554f2SKenneth D. Merry { 238*991554f2SKenneth D. Merry struct mpr_command *tm; 239*991554f2SKenneth D. Merry 240*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 241*991554f2SKenneth D. Merry tm = mpr_alloc_high_priority_command(sc); 242*991554f2SKenneth D. Merry if (tm != NULL) { 243*991554f2SKenneth D. Merry if (sc->sassc->tm_count++ == 0) { 244*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, 245*991554f2SKenneth D. Merry "%s freezing simq\n", __func__); 246*991554f2SKenneth D. Merry xpt_freeze_simq(sc->sassc->sim, 1); 247*991554f2SKenneth D. Merry } 248*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, 249*991554f2SKenneth D. Merry sc->sassc->tm_count); 250*991554f2SKenneth D. Merry } 251*991554f2SKenneth D. Merry return tm; 252*991554f2SKenneth D. Merry } 253*991554f2SKenneth D. Merry 254*991554f2SKenneth D. Merry void 255*991554f2SKenneth D. Merry mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm) 256*991554f2SKenneth D. Merry { 257*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s", __func__); 258*991554f2SKenneth D. Merry if (tm == NULL) 259*991554f2SKenneth D. Merry return; 260*991554f2SKenneth D. Merry 261*991554f2SKenneth D. Merry /* if there are no TMs in use, we can release the simq. We use our 262*991554f2SKenneth D. Merry * own refcount so that it's easier for a diag reset to cleanup and 263*991554f2SKenneth D. Merry * release the simq. 264*991554f2SKenneth D. Merry */ 265*991554f2SKenneth D. Merry if (--sc->sassc->tm_count == 0) { 266*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__); 267*991554f2SKenneth D. Merry xpt_release_simq(sc->sassc->sim, 1); 268*991554f2SKenneth D. Merry } 269*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, 270*991554f2SKenneth D. Merry sc->sassc->tm_count); 271*991554f2SKenneth D. Merry 272*991554f2SKenneth D. Merry mpr_free_high_priority_command(sc, tm); 273*991554f2SKenneth D. Merry } 274*991554f2SKenneth D. Merry 275*991554f2SKenneth D. Merry void 276*991554f2SKenneth D. Merry mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ) 277*991554f2SKenneth D. Merry { 278*991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 279*991554f2SKenneth D. Merry path_id_t pathid; 280*991554f2SKenneth D. Merry target_id_t targetid; 281*991554f2SKenneth D. Merry union ccb *ccb; 282*991554f2SKenneth D. Merry 283*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 284*991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 285*991554f2SKenneth D. Merry if (targ == NULL) 286*991554f2SKenneth D. Merry targetid = CAM_TARGET_WILDCARD; 287*991554f2SKenneth D. Merry else 288*991554f2SKenneth D. Merry targetid = targ - sassc->targets; 289*991554f2SKenneth D. Merry 290*991554f2SKenneth D. Merry /* 291*991554f2SKenneth D. Merry * Allocate a CCB and schedule a rescan. 292*991554f2SKenneth D. Merry */ 293*991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 294*991554f2SKenneth D. Merry if (ccb == NULL) { 295*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n"); 296*991554f2SKenneth D. Merry return; 297*991554f2SKenneth D. Merry } 298*991554f2SKenneth D. Merry 299*991554f2SKenneth D. Merry if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, 300*991554f2SKenneth D. Merry targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 301*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n"); 302*991554f2SKenneth D. Merry xpt_free_ccb(ccb); 303*991554f2SKenneth D. Merry return; 304*991554f2SKenneth D. Merry } 305*991554f2SKenneth D. Merry 306*991554f2SKenneth D. Merry if (targetid == CAM_TARGET_WILDCARD) 307*991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_BUS; 308*991554f2SKenneth D. Merry else 309*991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_TGT; 310*991554f2SKenneth D. Merry 311*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid); 312*991554f2SKenneth D. Merry xpt_rescan(ccb); 313*991554f2SKenneth D. Merry } 314*991554f2SKenneth D. Merry 315*991554f2SKenneth D. Merry static void 316*991554f2SKenneth D. Merry mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...) 317*991554f2SKenneth D. Merry { 318*991554f2SKenneth D. Merry struct sbuf sb; 319*991554f2SKenneth D. Merry va_list ap; 320*991554f2SKenneth D. Merry char str[192]; 321*991554f2SKenneth D. Merry char path_str[64]; 322*991554f2SKenneth D. Merry 323*991554f2SKenneth D. Merry if (cm == NULL) 324*991554f2SKenneth D. Merry return; 325*991554f2SKenneth D. Merry 326*991554f2SKenneth D. Merry /* No need to be in here if debugging isn't enabled */ 327*991554f2SKenneth D. Merry if ((cm->cm_sc->mpr_debug & level) == 0) 328*991554f2SKenneth D. Merry return; 329*991554f2SKenneth D. Merry 330*991554f2SKenneth D. Merry sbuf_new(&sb, str, sizeof(str), 0); 331*991554f2SKenneth D. Merry 332*991554f2SKenneth D. Merry va_start(ap, fmt); 333*991554f2SKenneth D. Merry 334*991554f2SKenneth D. Merry if (cm->cm_ccb != NULL) { 335*991554f2SKenneth D. Merry xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, 336*991554f2SKenneth D. Merry sizeof(path_str)); 337*991554f2SKenneth D. Merry sbuf_cat(&sb, path_str); 338*991554f2SKenneth D. Merry if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { 339*991554f2SKenneth D. Merry scsi_command_string(&cm->cm_ccb->csio, &sb); 340*991554f2SKenneth D. Merry sbuf_printf(&sb, "length %d ", 341*991554f2SKenneth D. Merry cm->cm_ccb->csio.dxfer_len); 342*991554f2SKenneth D. Merry } 343*991554f2SKenneth D. Merry } else { 344*991554f2SKenneth D. Merry sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", 345*991554f2SKenneth D. Merry cam_sim_name(cm->cm_sc->sassc->sim), 346*991554f2SKenneth D. Merry cam_sim_unit(cm->cm_sc->sassc->sim), 347*991554f2SKenneth D. Merry cam_sim_bus(cm->cm_sc->sassc->sim), 348*991554f2SKenneth D. Merry cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, 349*991554f2SKenneth D. Merry cm->cm_lun); 350*991554f2SKenneth D. Merry } 351*991554f2SKenneth D. Merry 352*991554f2SKenneth D. Merry sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); 353*991554f2SKenneth D. Merry sbuf_vprintf(&sb, fmt, ap); 354*991554f2SKenneth D. Merry sbuf_finish(&sb); 355*991554f2SKenneth D. Merry mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb)); 356*991554f2SKenneth D. Merry 357*991554f2SKenneth D. Merry va_end(ap); 358*991554f2SKenneth D. Merry } 359*991554f2SKenneth D. Merry 360*991554f2SKenneth D. Merry static void 361*991554f2SKenneth D. Merry mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm) 362*991554f2SKenneth D. Merry { 363*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 364*991554f2SKenneth D. Merry struct mprsas_target *targ; 365*991554f2SKenneth D. Merry uint16_t handle; 366*991554f2SKenneth D. Merry 367*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 368*991554f2SKenneth D. Merry 369*991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 370*991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 371*991554f2SKenneth D. Merry targ = tm->cm_targ; 372*991554f2SKenneth D. Merry 373*991554f2SKenneth D. Merry if (reply == NULL) { 374*991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 375*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 376*991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 377*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 378*991554f2SKenneth D. Merry return; 379*991554f2SKenneth D. Merry } 380*991554f2SKenneth D. Merry 381*991554f2SKenneth D. Merry if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { 382*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " 383*991554f2SKenneth D. Merry "device 0x%x\n", reply->IOCStatus, handle); 384*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 385*991554f2SKenneth D. Merry return; 386*991554f2SKenneth D. Merry } 387*991554f2SKenneth D. Merry 388*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 389*991554f2SKenneth D. Merry reply->TerminationCount); 390*991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 391*991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 392*991554f2SKenneth D. Merry 393*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", 394*991554f2SKenneth D. Merry targ->tid, handle); 395*991554f2SKenneth D. Merry 396*991554f2SKenneth D. Merry /* 397*991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 398*991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 399*991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 400*991554f2SKenneth D. Merry * to this device if it comes back in the future. 401*991554f2SKenneth D. Merry */ 402*991554f2SKenneth D. Merry if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) { 403*991554f2SKenneth D. Merry targ = tm->cm_targ; 404*991554f2SKenneth D. Merry targ->handle = 0x0; 405*991554f2SKenneth D. Merry targ->encl_handle = 0x0; 406*991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 407*991554f2SKenneth D. Merry targ->encl_level = 0x0; 408*991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 409*991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 410*991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 411*991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 412*991554f2SKenneth D. Merry targ->encl_slot = 0x0; 413*991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 414*991554f2SKenneth D. Merry targ->phy_num = 0x0; 415*991554f2SKenneth D. Merry targ->linkrate = 0x0; 416*991554f2SKenneth D. Merry targ->devinfo = 0x0; 417*991554f2SKenneth D. Merry targ->flags = 0x0; 418*991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 419*991554f2SKenneth D. Merry } 420*991554f2SKenneth D. Merry 421*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 422*991554f2SKenneth D. Merry } 423*991554f2SKenneth D. Merry 424*991554f2SKenneth D. Merry 425*991554f2SKenneth D. Merry /* 426*991554f2SKenneth D. Merry * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal. 427*991554f2SKenneth D. Merry * Otherwise Volume Delete is same as Bare Drive Removal. 428*991554f2SKenneth D. Merry */ 429*991554f2SKenneth D. Merry void 430*991554f2SKenneth D. Merry mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) 431*991554f2SKenneth D. Merry { 432*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 433*991554f2SKenneth D. Merry struct mpr_softc *sc; 434*991554f2SKenneth D. Merry struct mpr_command *cm; 435*991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 436*991554f2SKenneth D. Merry 437*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 438*991554f2SKenneth D. Merry sc = sassc->sc; 439*991554f2SKenneth D. Merry 440*991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 441*991554f2SKenneth D. Merry if (targ == NULL) { 442*991554f2SKenneth D. Merry /* FIXME: what is the action? */ 443*991554f2SKenneth D. Merry /* We don't know about this device? */ 444*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 445*991554f2SKenneth D. Merry "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle); 446*991554f2SKenneth D. Merry return; 447*991554f2SKenneth D. Merry } 448*991554f2SKenneth D. Merry 449*991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 450*991554f2SKenneth D. Merry 451*991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 452*991554f2SKenneth D. Merry if (cm == NULL) { 453*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 454*991554f2SKenneth D. Merry "%s: command alloc failure\n", __func__); 455*991554f2SKenneth D. Merry return; 456*991554f2SKenneth D. Merry } 457*991554f2SKenneth D. Merry 458*991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 459*991554f2SKenneth D. Merry 460*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 461*991554f2SKenneth D. Merry req->DevHandle = targ->handle; 462*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 463*991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 464*991554f2SKenneth D. Merry 465*991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 466*991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 467*991554f2SKenneth D. Merry 468*991554f2SKenneth D. Merry cm->cm_targ = targ; 469*991554f2SKenneth D. Merry cm->cm_data = NULL; 470*991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 471*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 472*991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_volume; 473*991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 474*991554f2SKenneth D. Merry mpr_map_command(sc, cm); 475*991554f2SKenneth D. Merry } 476*991554f2SKenneth D. Merry 477*991554f2SKenneth D. Merry /* 478*991554f2SKenneth D. Merry * The MPT2 firmware performs debounce on the link to avoid transient link 479*991554f2SKenneth D. Merry * errors and false removals. When it does decide that link has been lost 480*991554f2SKenneth D. Merry * and a device needs to go away, it expects that the host will perform a 481*991554f2SKenneth D. Merry * target reset and then an op remove. The reset has the side-effect of 482*991554f2SKenneth D. Merry * aborting any outstanding requests for the device, which is required for 483*991554f2SKenneth D. Merry * the op-remove to succeed. It's not clear if the host should check for 484*991554f2SKenneth D. Merry * the device coming back alive after the reset. 485*991554f2SKenneth D. Merry */ 486*991554f2SKenneth D. Merry void 487*991554f2SKenneth D. Merry mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) 488*991554f2SKenneth D. Merry { 489*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 490*991554f2SKenneth D. Merry struct mpr_softc *sc; 491*991554f2SKenneth D. Merry struct mpr_command *cm; 492*991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 493*991554f2SKenneth D. Merry 494*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 495*991554f2SKenneth D. Merry 496*991554f2SKenneth D. Merry sc = sassc->sc; 497*991554f2SKenneth D. Merry 498*991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 499*991554f2SKenneth D. Merry if (targ == NULL) { 500*991554f2SKenneth D. Merry /* FIXME: what is the action? */ 501*991554f2SKenneth D. Merry /* We don't know about this device? */ 502*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n", 503*991554f2SKenneth D. Merry __func__, handle); 504*991554f2SKenneth D. Merry return; 505*991554f2SKenneth D. Merry } 506*991554f2SKenneth D. Merry 507*991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 508*991554f2SKenneth D. Merry 509*991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 510*991554f2SKenneth D. Merry if (cm == NULL) { 511*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n", 512*991554f2SKenneth D. Merry __func__); 513*991554f2SKenneth D. Merry return; 514*991554f2SKenneth D. Merry } 515*991554f2SKenneth D. Merry 516*991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 517*991554f2SKenneth D. Merry 518*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 519*991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 520*991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 521*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 522*991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 523*991554f2SKenneth D. Merry 524*991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 525*991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 526*991554f2SKenneth D. Merry 527*991554f2SKenneth D. Merry cm->cm_targ = targ; 528*991554f2SKenneth D. Merry cm->cm_data = NULL; 529*991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 530*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 531*991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_device; 532*991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 533*991554f2SKenneth D. Merry mpr_map_command(sc, cm); 534*991554f2SKenneth D. Merry } 535*991554f2SKenneth D. Merry 536*991554f2SKenneth D. Merry static void 537*991554f2SKenneth D. Merry mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) 538*991554f2SKenneth D. Merry { 539*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 540*991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; 541*991554f2SKenneth D. Merry struct mprsas_target *targ; 542*991554f2SKenneth D. Merry struct mpr_command *next_cm; 543*991554f2SKenneth D. Merry uint16_t handle; 544*991554f2SKenneth D. Merry 545*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 546*991554f2SKenneth D. Merry 547*991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 548*991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 549*991554f2SKenneth D. Merry targ = tm->cm_targ; 550*991554f2SKenneth D. Merry 551*991554f2SKenneth D. Merry /* 552*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 553*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 554*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 555*991554f2SKenneth D. Merry */ 556*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 557*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of " 558*991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 559*991554f2SKenneth D. Merry tm->cm_flags, handle); 560*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 561*991554f2SKenneth D. Merry return; 562*991554f2SKenneth D. Merry } 563*991554f2SKenneth D. Merry 564*991554f2SKenneth D. Merry if (reply == NULL) { 565*991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 566*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 567*991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 568*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 569*991554f2SKenneth D. Merry return; 570*991554f2SKenneth D. Merry } 571*991554f2SKenneth D. Merry 572*991554f2SKenneth D. Merry if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) { 573*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " 574*991554f2SKenneth D. Merry "device 0x%x\n", le16toh(reply->IOCStatus), handle); 575*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 576*991554f2SKenneth D. Merry return; 577*991554f2SKenneth D. Merry } 578*991554f2SKenneth D. Merry 579*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 580*991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 581*991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 582*991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 583*991554f2SKenneth D. Merry 584*991554f2SKenneth D. Merry /* Reuse the existing command */ 585*991554f2SKenneth D. Merry req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; 586*991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 587*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; 588*991554f2SKenneth D. Merry req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; 589*991554f2SKenneth D. Merry req->DevHandle = htole16(handle); 590*991554f2SKenneth D. Merry tm->cm_data = NULL; 591*991554f2SKenneth D. Merry tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 592*991554f2SKenneth D. Merry tm->cm_complete = mprsas_remove_complete; 593*991554f2SKenneth D. Merry tm->cm_complete_data = (void *)(uintptr_t)handle; 594*991554f2SKenneth D. Merry 595*991554f2SKenneth D. Merry mpr_map_command(sc, tm); 596*991554f2SKenneth D. Merry 597*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", 598*991554f2SKenneth D. Merry targ->tid, handle); 599*991554f2SKenneth D. Merry if (targ->encl_level_valid) { 600*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 601*991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 602*991554f2SKenneth D. Merry targ->connector_name); 603*991554f2SKenneth D. Merry } 604*991554f2SKenneth D. Merry TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { 605*991554f2SKenneth D. Merry union ccb *ccb; 606*991554f2SKenneth D. Merry 607*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); 608*991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 609*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 610*991554f2SKenneth D. Merry mprsas_scsiio_complete(sc, tm); 611*991554f2SKenneth D. Merry } 612*991554f2SKenneth D. Merry } 613*991554f2SKenneth D. Merry 614*991554f2SKenneth D. Merry static void 615*991554f2SKenneth D. Merry mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm) 616*991554f2SKenneth D. Merry { 617*991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; 618*991554f2SKenneth D. Merry uint16_t handle; 619*991554f2SKenneth D. Merry struct mprsas_target *targ; 620*991554f2SKenneth D. Merry struct mprsas_lun *lun; 621*991554f2SKenneth D. Merry 622*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 623*991554f2SKenneth D. Merry 624*991554f2SKenneth D. Merry reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; 625*991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 626*991554f2SKenneth D. Merry 627*991554f2SKenneth D. Merry /* 628*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 629*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 630*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 631*991554f2SKenneth D. Merry */ 632*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 633*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of " 634*991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 635*991554f2SKenneth D. Merry tm->cm_flags, handle); 636*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 637*991554f2SKenneth D. Merry return; 638*991554f2SKenneth D. Merry } 639*991554f2SKenneth D. Merry 640*991554f2SKenneth D. Merry if (reply == NULL) { 641*991554f2SKenneth D. Merry /* most likely a chip reset */ 642*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device " 643*991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 644*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 645*991554f2SKenneth D. Merry return; 646*991554f2SKenneth D. Merry } 647*991554f2SKenneth D. Merry 648*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", 649*991554f2SKenneth D. Merry __func__, handle, le16toh(reply->IOCStatus)); 650*991554f2SKenneth D. Merry 651*991554f2SKenneth D. Merry /* 652*991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 653*991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 654*991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 655*991554f2SKenneth D. Merry * to this device if it comes back in the future. 656*991554f2SKenneth D. Merry */ 657*991554f2SKenneth D. Merry if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) { 658*991554f2SKenneth D. Merry targ = tm->cm_targ; 659*991554f2SKenneth D. Merry targ->handle = 0x0; 660*991554f2SKenneth D. Merry targ->encl_handle = 0x0; 661*991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 662*991554f2SKenneth D. Merry targ->encl_level = 0x0; 663*991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 664*991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 665*991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 666*991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 667*991554f2SKenneth D. Merry targ->encl_slot = 0x0; 668*991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 669*991554f2SKenneth D. Merry targ->phy_num = 0x0; 670*991554f2SKenneth D. Merry targ->linkrate = 0x0; 671*991554f2SKenneth D. Merry targ->devinfo = 0x0; 672*991554f2SKenneth D. Merry targ->flags = 0x0; 673*991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 674*991554f2SKenneth D. Merry 675*991554f2SKenneth D. Merry while (!SLIST_EMPTY(&targ->luns)) { 676*991554f2SKenneth D. Merry lun = SLIST_FIRST(&targ->luns); 677*991554f2SKenneth D. Merry SLIST_REMOVE_HEAD(&targ->luns, lun_link); 678*991554f2SKenneth D. Merry free(lun, M_MPR); 679*991554f2SKenneth D. Merry } 680*991554f2SKenneth D. Merry } 681*991554f2SKenneth D. Merry 682*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 683*991554f2SKenneth D. Merry } 684*991554f2SKenneth D. Merry 685*991554f2SKenneth D. Merry static int 686*991554f2SKenneth D. Merry mprsas_register_events(struct mpr_softc *sc) 687*991554f2SKenneth D. Merry { 688*991554f2SKenneth D. Merry uint8_t events[16]; 689*991554f2SKenneth D. Merry 690*991554f2SKenneth D. Merry bzero(events, 16); 691*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); 692*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DISCOVERY); 693*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); 694*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); 695*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); 696*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 697*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); 698*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); 699*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_VOLUME); 700*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); 701*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); 702*991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_TEMP_THRESHOLD); 703*991554f2SKenneth D. Merry 704*991554f2SKenneth D. Merry mpr_register_events(sc, events, mprsas_evt_handler, NULL, 705*991554f2SKenneth D. Merry &sc->sassc->mprsas_eh); 706*991554f2SKenneth D. Merry 707*991554f2SKenneth D. Merry return (0); 708*991554f2SKenneth D. Merry } 709*991554f2SKenneth D. Merry 710*991554f2SKenneth D. Merry int 711*991554f2SKenneth D. Merry mpr_attach_sas(struct mpr_softc *sc) 712*991554f2SKenneth D. Merry { 713*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 714*991554f2SKenneth D. Merry cam_status status; 715*991554f2SKenneth D. Merry int unit, error = 0; 716*991554f2SKenneth D. Merry 717*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 718*991554f2SKenneth D. Merry 719*991554f2SKenneth D. Merry sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO); 720*991554f2SKenneth D. Merry if (!sassc) { 721*991554f2SKenneth D. Merry device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 722*991554f2SKenneth D. Merry __func__, __LINE__); 723*991554f2SKenneth D. Merry return (ENOMEM); 724*991554f2SKenneth D. Merry } 725*991554f2SKenneth D. Merry 726*991554f2SKenneth D. Merry /* 727*991554f2SKenneth D. Merry * XXX MaxTargets could change during a reinit. since we don't 728*991554f2SKenneth D. Merry * resize the targets[] array during such an event, cache the value 729*991554f2SKenneth D. Merry * of MaxTargets here so that we don't get into trouble later. This 730*991554f2SKenneth D. Merry * should move into the reinit logic. 731*991554f2SKenneth D. Merry */ 732*991554f2SKenneth D. Merry sassc->maxtargets = sc->facts->MaxTargets; 733*991554f2SKenneth D. Merry sassc->targets = malloc(sizeof(struct mprsas_target) * 734*991554f2SKenneth D. Merry sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO); 735*991554f2SKenneth D. Merry if (!sassc->targets) { 736*991554f2SKenneth D. Merry device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 737*991554f2SKenneth D. Merry __func__, __LINE__); 738*991554f2SKenneth D. Merry free(sassc, M_MPR); 739*991554f2SKenneth D. Merry return (ENOMEM); 740*991554f2SKenneth D. Merry } 741*991554f2SKenneth D. Merry sc->sassc = sassc; 742*991554f2SKenneth D. Merry sassc->sc = sc; 743*991554f2SKenneth D. Merry 744*991554f2SKenneth D. Merry if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { 745*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n"); 746*991554f2SKenneth D. Merry error = ENOMEM; 747*991554f2SKenneth D. Merry goto out; 748*991554f2SKenneth D. Merry } 749*991554f2SKenneth D. Merry 750*991554f2SKenneth D. Merry unit = device_get_unit(sc->mpr_dev); 751*991554f2SKenneth D. Merry sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc, 752*991554f2SKenneth D. Merry unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq); 753*991554f2SKenneth D. Merry if (sassc->sim == NULL) { 754*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n"); 755*991554f2SKenneth D. Merry error = EINVAL; 756*991554f2SKenneth D. Merry goto out; 757*991554f2SKenneth D. Merry } 758*991554f2SKenneth D. Merry 759*991554f2SKenneth D. Merry TAILQ_INIT(&sassc->ev_queue); 760*991554f2SKenneth D. Merry 761*991554f2SKenneth D. Merry /* Initialize taskqueue for Event Handling */ 762*991554f2SKenneth D. Merry TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc); 763*991554f2SKenneth D. Merry sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO, 764*991554f2SKenneth D. Merry taskqueue_thread_enqueue, &sassc->ev_tq); 765*991554f2SKenneth D. Merry 766*991554f2SKenneth D. Merry /* Run the task queue with lowest priority */ 767*991554f2SKenneth D. Merry taskqueue_start_threads(&sassc->ev_tq, 1, 255, "%s taskq", 768*991554f2SKenneth D. Merry device_get_nameunit(sc->mpr_dev)); 769*991554f2SKenneth D. Merry 770*991554f2SKenneth D. Merry mpr_lock(sc); 771*991554f2SKenneth D. Merry 772*991554f2SKenneth D. Merry /* 773*991554f2SKenneth D. Merry * XXX There should be a bus for every port on the adapter, but since 774*991554f2SKenneth D. Merry * we're just going to fake the topology for now, we'll pretend that 775*991554f2SKenneth D. Merry * everything is just a target on a single bus. 776*991554f2SKenneth D. Merry */ 777*991554f2SKenneth D. Merry if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) { 778*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n", 779*991554f2SKenneth D. Merry error); 780*991554f2SKenneth D. Merry mpr_unlock(sc); 781*991554f2SKenneth D. Merry goto out; 782*991554f2SKenneth D. Merry } 783*991554f2SKenneth D. Merry 784*991554f2SKenneth D. Merry /* 785*991554f2SKenneth D. Merry * Assume that discovery events will start right away. Freezing 786*991554f2SKenneth D. Merry * 787*991554f2SKenneth D. Merry * Hold off boot until discovery is complete. 788*991554f2SKenneth D. Merry */ 789*991554f2SKenneth D. Merry sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY; 790*991554f2SKenneth D. Merry sc->sassc->startup_refcount = 0; 791*991554f2SKenneth D. Merry mprsas_startup_increment(sassc); 792*991554f2SKenneth D. Merry 793*991554f2SKenneth D. Merry callout_init(&sassc->discovery_callout, 1 /*mprafe*/); 794*991554f2SKenneth D. Merry 795*991554f2SKenneth D. Merry sassc->tm_count = 0; 796*991554f2SKenneth D. Merry 797*991554f2SKenneth D. Merry /* 798*991554f2SKenneth D. Merry * Register for async events so we can determine the EEDP 799*991554f2SKenneth D. Merry * capabilities of devices. 800*991554f2SKenneth D. Merry */ 801*991554f2SKenneth D. Merry status = xpt_create_path(&sassc->path, /*periph*/NULL, 802*991554f2SKenneth D. Merry cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD, 803*991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 804*991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 805*991554f2SKenneth D. Merry mpr_printf(sc, "Error %#x creating sim path\n", status); 806*991554f2SKenneth D. Merry sassc->path = NULL; 807*991554f2SKenneth D. Merry } else { 808*991554f2SKenneth D. Merry int event; 809*991554f2SKenneth D. Merry 810*991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 811*991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 812*991554f2SKenneth D. Merry event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE; 813*991554f2SKenneth D. Merry #else 814*991554f2SKenneth D. Merry event = AC_FOUND_DEVICE; 815*991554f2SKenneth D. Merry #endif 816*991554f2SKenneth D. Merry status = xpt_register_async(event, mprsas_async, sc, 817*991554f2SKenneth D. Merry sassc->path); 818*991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 819*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 820*991554f2SKenneth D. Merry "Error %#x registering async handler for " 821*991554f2SKenneth D. Merry "AC_ADVINFO_CHANGED events\n", status); 822*991554f2SKenneth D. Merry xpt_free_path(sassc->path); 823*991554f2SKenneth D. Merry sassc->path = NULL; 824*991554f2SKenneth D. Merry } 825*991554f2SKenneth D. Merry } 826*991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 827*991554f2SKenneth D. Merry /* 828*991554f2SKenneth D. Merry * EEDP use is the exception, not the rule. 829*991554f2SKenneth D. Merry * Warn the user, but do not fail to attach. 830*991554f2SKenneth D. Merry */ 831*991554f2SKenneth D. Merry mpr_printf(sc, "EEDP capabilities disabled.\n"); 832*991554f2SKenneth D. Merry } 833*991554f2SKenneth D. Merry 834*991554f2SKenneth D. Merry mpr_unlock(sc); 835*991554f2SKenneth D. Merry 836*991554f2SKenneth D. Merry mprsas_register_events(sc); 837*991554f2SKenneth D. Merry out: 838*991554f2SKenneth D. Merry if (error) 839*991554f2SKenneth D. Merry mpr_detach_sas(sc); 840*991554f2SKenneth D. Merry return (error); 841*991554f2SKenneth D. Merry } 842*991554f2SKenneth D. Merry 843*991554f2SKenneth D. Merry int 844*991554f2SKenneth D. Merry mpr_detach_sas(struct mpr_softc *sc) 845*991554f2SKenneth D. Merry { 846*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 847*991554f2SKenneth D. Merry struct mprsas_lun *lun, *lun_tmp; 848*991554f2SKenneth D. Merry struct mprsas_target *targ; 849*991554f2SKenneth D. Merry int i; 850*991554f2SKenneth D. Merry 851*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 852*991554f2SKenneth D. Merry 853*991554f2SKenneth D. Merry if (sc->sassc == NULL) 854*991554f2SKenneth D. Merry return (0); 855*991554f2SKenneth D. Merry 856*991554f2SKenneth D. Merry sassc = sc->sassc; 857*991554f2SKenneth D. Merry mpr_deregister_events(sc, sassc->mprsas_eh); 858*991554f2SKenneth D. Merry 859*991554f2SKenneth D. Merry /* 860*991554f2SKenneth D. Merry * Drain and free the event handling taskqueue with the lock 861*991554f2SKenneth D. Merry * unheld so that any parallel processing tasks drain properly 862*991554f2SKenneth D. Merry * without deadlocking. 863*991554f2SKenneth D. Merry */ 864*991554f2SKenneth D. Merry if (sassc->ev_tq != NULL) 865*991554f2SKenneth D. Merry taskqueue_free(sassc->ev_tq); 866*991554f2SKenneth D. Merry 867*991554f2SKenneth D. Merry /* Make sure CAM doesn't wedge if we had to bail out early. */ 868*991554f2SKenneth D. Merry mpr_lock(sc); 869*991554f2SKenneth D. Merry 870*991554f2SKenneth D. Merry /* Deregister our async handler */ 871*991554f2SKenneth D. Merry if (sassc->path != NULL) { 872*991554f2SKenneth D. Merry xpt_register_async(0, mprsas_async, sc, sassc->path); 873*991554f2SKenneth D. Merry xpt_free_path(sassc->path); 874*991554f2SKenneth D. Merry sassc->path = NULL; 875*991554f2SKenneth D. Merry } 876*991554f2SKenneth D. Merry 877*991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_IN_STARTUP) 878*991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 879*991554f2SKenneth D. Merry 880*991554f2SKenneth D. Merry if (sassc->sim != NULL) { 881*991554f2SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sassc->sim)); 882*991554f2SKenneth D. Merry cam_sim_free(sassc->sim, FALSE); 883*991554f2SKenneth D. Merry } 884*991554f2SKenneth D. Merry 885*991554f2SKenneth D. Merry sassc->flags |= MPRSAS_SHUTDOWN; 886*991554f2SKenneth D. Merry mpr_unlock(sc); 887*991554f2SKenneth D. Merry 888*991554f2SKenneth D. Merry if (sassc->devq != NULL) 889*991554f2SKenneth D. Merry cam_simq_free(sassc->devq); 890*991554f2SKenneth D. Merry 891*991554f2SKenneth D. Merry for (i = 0; i < sassc->maxtargets; i++) { 892*991554f2SKenneth D. Merry targ = &sassc->targets[i]; 893*991554f2SKenneth D. Merry SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { 894*991554f2SKenneth D. Merry free(lun, M_MPR); 895*991554f2SKenneth D. Merry } 896*991554f2SKenneth D. Merry } 897*991554f2SKenneth D. Merry free(sassc->targets, M_MPR); 898*991554f2SKenneth D. Merry free(sassc, M_MPR); 899*991554f2SKenneth D. Merry sc->sassc = NULL; 900*991554f2SKenneth D. Merry 901*991554f2SKenneth D. Merry return (0); 902*991554f2SKenneth D. Merry } 903*991554f2SKenneth D. Merry 904*991554f2SKenneth D. Merry void 905*991554f2SKenneth D. Merry mprsas_discovery_end(struct mprsas_softc *sassc) 906*991554f2SKenneth D. Merry { 907*991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 908*991554f2SKenneth D. Merry 909*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 910*991554f2SKenneth D. Merry 911*991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING) 912*991554f2SKenneth D. Merry callout_stop(&sassc->discovery_callout); 913*991554f2SKenneth D. Merry 914*991554f2SKenneth D. Merry } 915*991554f2SKenneth D. Merry 916*991554f2SKenneth D. Merry static void 917*991554f2SKenneth D. Merry mprsas_action(struct cam_sim *sim, union ccb *ccb) 918*991554f2SKenneth D. Merry { 919*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 920*991554f2SKenneth D. Merry 921*991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 922*991554f2SKenneth D. Merry 923*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 924*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__, 925*991554f2SKenneth D. Merry ccb->ccb_h.func_code); 926*991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 927*991554f2SKenneth D. Merry 928*991554f2SKenneth D. Merry switch (ccb->ccb_h.func_code) { 929*991554f2SKenneth D. Merry case XPT_PATH_INQ: 930*991554f2SKenneth D. Merry { 931*991554f2SKenneth D. Merry struct ccb_pathinq *cpi = &ccb->cpi; 932*991554f2SKenneth D. Merry 933*991554f2SKenneth D. Merry cpi->version_num = 1; 934*991554f2SKenneth D. Merry cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 935*991554f2SKenneth D. Merry cpi->target_sprt = 0; 936*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000039 937*991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; 938*991554f2SKenneth D. Merry #else 939*991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 940*991554f2SKenneth D. Merry #endif 941*991554f2SKenneth D. Merry cpi->hba_eng_cnt = 0; 942*991554f2SKenneth D. Merry cpi->max_target = sassc->maxtargets - 1; 943*991554f2SKenneth D. Merry cpi->max_lun = 255; 944*991554f2SKenneth D. Merry cpi->initiator_id = sassc->maxtargets - 1; 945*991554f2SKenneth D. Merry strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 946*991554f2SKenneth D. Merry strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); 947*991554f2SKenneth D. Merry strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 948*991554f2SKenneth D. Merry cpi->unit_number = cam_sim_unit(sim); 949*991554f2SKenneth D. Merry cpi->bus_id = cam_sim_bus(sim); 950*991554f2SKenneth D. Merry /* 951*991554f2SKenneth D. Merry * XXXSLM-I think this needs to change based on config page or 952*991554f2SKenneth D. Merry * something instead of hardcoded to 150000. 953*991554f2SKenneth D. Merry */ 954*991554f2SKenneth D. Merry cpi->base_transfer_speed = 150000; 955*991554f2SKenneth D. Merry cpi->transport = XPORT_SAS; 956*991554f2SKenneth D. Merry cpi->transport_version = 0; 957*991554f2SKenneth D. Merry cpi->protocol = PROTO_SCSI; 958*991554f2SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC; 959*991554f2SKenneth D. Merry #if __FreeBSD_version >= 800001 960*991554f2SKenneth D. Merry /* 961*991554f2SKenneth D. Merry * XXXSLM-probably need to base this number on max SGL's and 962*991554f2SKenneth D. Merry * page size. 963*991554f2SKenneth D. Merry */ 964*991554f2SKenneth D. Merry cpi->maxio = 256 * 1024; 965*991554f2SKenneth D. Merry #endif 966*991554f2SKenneth D. Merry cpi->ccb_h.status = CAM_REQ_CMP; 967*991554f2SKenneth D. Merry break; 968*991554f2SKenneth D. Merry } 969*991554f2SKenneth D. Merry case XPT_GET_TRAN_SETTINGS: 970*991554f2SKenneth D. Merry { 971*991554f2SKenneth D. Merry struct ccb_trans_settings *cts; 972*991554f2SKenneth D. Merry struct ccb_trans_settings_sas *sas; 973*991554f2SKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 974*991554f2SKenneth D. Merry struct mprsas_target *targ; 975*991554f2SKenneth D. Merry 976*991554f2SKenneth D. Merry cts = &ccb->cts; 977*991554f2SKenneth D. Merry sas = &cts->xport_specific.sas; 978*991554f2SKenneth D. Merry scsi = &cts->proto_specific.scsi; 979*991554f2SKenneth D. Merry 980*991554f2SKenneth D. Merry KASSERT(cts->ccb_h.target_id < sassc->maxtargets, 981*991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", 982*991554f2SKenneth D. Merry cts->ccb_h.target_id)); 983*991554f2SKenneth D. Merry targ = &sassc->targets[cts->ccb_h.target_id]; 984*991554f2SKenneth D. Merry if (targ->handle == 0x0) { 985*991554f2SKenneth D. Merry cts->ccb_h.status = CAM_DEV_NOT_THERE; 986*991554f2SKenneth D. Merry break; 987*991554f2SKenneth D. Merry } 988*991554f2SKenneth D. Merry 989*991554f2SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2; 990*991554f2SKenneth D. Merry cts->transport = XPORT_SAS; 991*991554f2SKenneth D. Merry cts->transport_version = 0; 992*991554f2SKenneth D. Merry 993*991554f2SKenneth D. Merry sas->valid = CTS_SAS_VALID_SPEED; 994*991554f2SKenneth D. Merry switch (targ->linkrate) { 995*991554f2SKenneth D. Merry case 0x08: 996*991554f2SKenneth D. Merry sas->bitrate = 150000; 997*991554f2SKenneth D. Merry break; 998*991554f2SKenneth D. Merry case 0x09: 999*991554f2SKenneth D. Merry sas->bitrate = 300000; 1000*991554f2SKenneth D. Merry break; 1001*991554f2SKenneth D. Merry case 0x0a: 1002*991554f2SKenneth D. Merry sas->bitrate = 600000; 1003*991554f2SKenneth D. Merry break; 1004*991554f2SKenneth D. Merry default: 1005*991554f2SKenneth D. Merry sas->valid = 0; 1006*991554f2SKenneth D. Merry } 1007*991554f2SKenneth D. Merry 1008*991554f2SKenneth D. Merry cts->protocol = PROTO_SCSI; 1009*991554f2SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ; 1010*991554f2SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1011*991554f2SKenneth D. Merry 1012*991554f2SKenneth D. Merry cts->ccb_h.status = CAM_REQ_CMP; 1013*991554f2SKenneth D. Merry break; 1014*991554f2SKenneth D. Merry } 1015*991554f2SKenneth D. Merry case XPT_CALC_GEOMETRY: 1016*991554f2SKenneth D. Merry cam_calc_geometry(&ccb->ccg, /*extended*/1); 1017*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 1018*991554f2SKenneth D. Merry break; 1019*991554f2SKenneth D. Merry case XPT_RESET_DEV: 1020*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_XINFO, 1021*991554f2SKenneth D. Merry "mprsas_action XPT_RESET_DEV\n"); 1022*991554f2SKenneth D. Merry mprsas_action_resetdev(sassc, ccb); 1023*991554f2SKenneth D. Merry return; 1024*991554f2SKenneth D. Merry case XPT_RESET_BUS: 1025*991554f2SKenneth D. Merry case XPT_ABORT: 1026*991554f2SKenneth D. Merry case XPT_TERM_IO: 1027*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_XINFO, 1028*991554f2SKenneth D. Merry "mprsas_action faking success for abort or reset\n"); 1029*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 1030*991554f2SKenneth D. Merry break; 1031*991554f2SKenneth D. Merry case XPT_SCSI_IO: 1032*991554f2SKenneth D. Merry mprsas_action_scsiio(sassc, ccb); 1033*991554f2SKenneth D. Merry return; 1034*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 1035*991554f2SKenneth D. Merry case XPT_SMP_IO: 1036*991554f2SKenneth D. Merry mprsas_action_smpio(sassc, ccb); 1037*991554f2SKenneth D. Merry return; 1038*991554f2SKenneth D. Merry #endif 1039*991554f2SKenneth D. Merry default: 1040*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1041*991554f2SKenneth D. Merry break; 1042*991554f2SKenneth D. Merry } 1043*991554f2SKenneth D. Merry xpt_done(ccb); 1044*991554f2SKenneth D. Merry 1045*991554f2SKenneth D. Merry } 1046*991554f2SKenneth D. Merry 1047*991554f2SKenneth D. Merry static void 1048*991554f2SKenneth D. Merry mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code, 1049*991554f2SKenneth D. Merry target_id_t target_id, lun_id_t lun_id) 1050*991554f2SKenneth D. Merry { 1051*991554f2SKenneth D. Merry path_id_t path_id = cam_sim_path(sc->sassc->sim); 1052*991554f2SKenneth D. Merry struct cam_path *path; 1053*991554f2SKenneth D. Merry 1054*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__, 1055*991554f2SKenneth D. Merry ac_code, target_id, (uintmax_t)lun_id); 1056*991554f2SKenneth D. Merry 1057*991554f2SKenneth D. Merry if (xpt_create_path(&path, NULL, 1058*991554f2SKenneth D. Merry path_id, target_id, lun_id) != CAM_REQ_CMP) { 1059*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for reset " 1060*991554f2SKenneth D. Merry "notification\n"); 1061*991554f2SKenneth D. Merry return; 1062*991554f2SKenneth D. Merry } 1063*991554f2SKenneth D. Merry 1064*991554f2SKenneth D. Merry xpt_async(ac_code, path, NULL); 1065*991554f2SKenneth D. Merry xpt_free_path(path); 1066*991554f2SKenneth D. Merry } 1067*991554f2SKenneth D. Merry 1068*991554f2SKenneth D. Merry static void 1069*991554f2SKenneth D. Merry mprsas_complete_all_commands(struct mpr_softc *sc) 1070*991554f2SKenneth D. Merry { 1071*991554f2SKenneth D. Merry struct mpr_command *cm; 1072*991554f2SKenneth D. Merry int i; 1073*991554f2SKenneth D. Merry int completed; 1074*991554f2SKenneth D. Merry 1075*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1076*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1077*991554f2SKenneth D. Merry 1078*991554f2SKenneth D. Merry /* complete all commands with a NULL reply */ 1079*991554f2SKenneth D. Merry for (i = 1; i < sc->num_reqs; i++) { 1080*991554f2SKenneth D. Merry cm = &sc->commands[i]; 1081*991554f2SKenneth D. Merry cm->cm_reply = NULL; 1082*991554f2SKenneth D. Merry completed = 0; 1083*991554f2SKenneth D. Merry 1084*991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_POLLED) 1085*991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; 1086*991554f2SKenneth D. Merry 1087*991554f2SKenneth D. Merry if (cm->cm_complete != NULL) { 1088*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1089*991554f2SKenneth D. Merry "completing cm %p state %x ccb %p for diag reset\n", 1090*991554f2SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb); 1091*991554f2SKenneth D. Merry cm->cm_complete(sc, cm); 1092*991554f2SKenneth D. Merry completed = 1; 1093*991554f2SKenneth D. Merry } 1094*991554f2SKenneth D. Merry 1095*991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { 1096*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1097*991554f2SKenneth D. Merry "waking up cm %p state %x ccb %p for diag reset\n", 1098*991554f2SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb); 1099*991554f2SKenneth D. Merry wakeup(cm); 1100*991554f2SKenneth D. Merry completed = 1; 1101*991554f2SKenneth D. Merry } 1102*991554f2SKenneth D. Merry 1103*991554f2SKenneth D. Merry if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) { 1104*991554f2SKenneth D. Merry /* this should never happen, but if it does, log */ 1105*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1106*991554f2SKenneth D. Merry "cm %p state %x flags 0x%x ccb %p during diag " 1107*991554f2SKenneth D. Merry "reset\n", cm, cm->cm_state, cm->cm_flags, 1108*991554f2SKenneth D. Merry cm->cm_ccb); 1109*991554f2SKenneth D. Merry } 1110*991554f2SKenneth D. Merry } 1111*991554f2SKenneth D. Merry } 1112*991554f2SKenneth D. Merry 1113*991554f2SKenneth D. Merry void 1114*991554f2SKenneth D. Merry mprsas_handle_reinit(struct mpr_softc *sc) 1115*991554f2SKenneth D. Merry { 1116*991554f2SKenneth D. Merry int i; 1117*991554f2SKenneth D. Merry 1118*991554f2SKenneth D. Merry /* Go back into startup mode and freeze the simq, so that CAM 1119*991554f2SKenneth D. Merry * doesn't send any commands until after we've rediscovered all 1120*991554f2SKenneth D. Merry * targets and found the proper device handles for them. 1121*991554f2SKenneth D. Merry * 1122*991554f2SKenneth D. Merry * After the reset, portenable will trigger discovery, and after all 1123*991554f2SKenneth D. Merry * discovery-related activities have finished, the simq will be 1124*991554f2SKenneth D. Merry * released. 1125*991554f2SKenneth D. Merry */ 1126*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__); 1127*991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_STARTUP; 1128*991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_DISCOVERY; 1129*991554f2SKenneth D. Merry mprsas_startup_increment(sc->sassc); 1130*991554f2SKenneth D. Merry 1131*991554f2SKenneth D. Merry /* notify CAM of a bus reset */ 1132*991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 1133*991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1134*991554f2SKenneth D. Merry 1135*991554f2SKenneth D. Merry /* complete and cleanup after all outstanding commands */ 1136*991554f2SKenneth D. Merry mprsas_complete_all_commands(sc); 1137*991554f2SKenneth D. Merry 1138*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command " 1139*991554f2SKenneth D. Merry "completion\n", __func__, sc->sassc->startup_refcount, 1140*991554f2SKenneth D. Merry sc->sassc->tm_count); 1141*991554f2SKenneth D. Merry 1142*991554f2SKenneth D. Merry /* zero all the target handles, since they may change after the 1143*991554f2SKenneth D. Merry * reset, and we have to rediscover all the targets and use the new 1144*991554f2SKenneth D. Merry * handles. 1145*991554f2SKenneth D. Merry */ 1146*991554f2SKenneth D. Merry for (i = 0; i < sc->sassc->maxtargets; i++) { 1147*991554f2SKenneth D. Merry if (sc->sassc->targets[i].outstanding != 0) 1148*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n", 1149*991554f2SKenneth D. Merry i, sc->sassc->targets[i].outstanding); 1150*991554f2SKenneth D. Merry sc->sassc->targets[i].handle = 0x0; 1151*991554f2SKenneth D. Merry sc->sassc->targets[i].exp_dev_handle = 0x0; 1152*991554f2SKenneth D. Merry sc->sassc->targets[i].outstanding = 0; 1153*991554f2SKenneth D. Merry sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET; 1154*991554f2SKenneth D. Merry } 1155*991554f2SKenneth D. Merry } 1156*991554f2SKenneth D. Merry static void 1157*991554f2SKenneth D. Merry mprsas_tm_timeout(void *data) 1158*991554f2SKenneth D. Merry { 1159*991554f2SKenneth D. Merry struct mpr_command *tm = data; 1160*991554f2SKenneth D. Merry struct mpr_softc *sc = tm->cm_sc; 1161*991554f2SKenneth D. Merry 1162*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1163*991554f2SKenneth D. Merry 1164*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY, 1165*991554f2SKenneth D. Merry "task mgmt %p timed out\n", tm); 1166*991554f2SKenneth D. Merry mpr_reinit(sc); 1167*991554f2SKenneth D. Merry } 1168*991554f2SKenneth D. Merry 1169*991554f2SKenneth D. Merry static void 1170*991554f2SKenneth D. Merry mprsas_logical_unit_reset_complete(struct mpr_softc *sc, 1171*991554f2SKenneth D. Merry struct mpr_command *tm) 1172*991554f2SKenneth D. Merry { 1173*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1174*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1175*991554f2SKenneth D. Merry unsigned int cm_count = 0; 1176*991554f2SKenneth D. Merry struct mpr_command *cm; 1177*991554f2SKenneth D. Merry struct mprsas_target *targ; 1178*991554f2SKenneth D. Merry 1179*991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1180*991554f2SKenneth D. Merry 1181*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1182*991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1183*991554f2SKenneth D. Merry targ = tm->cm_targ; 1184*991554f2SKenneth D. Merry 1185*991554f2SKenneth D. Merry /* 1186*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1187*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1188*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1189*991554f2SKenneth D. Merry */ 1190*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1191*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! " 1192*991554f2SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags); 1193*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1194*991554f2SKenneth D. Merry return; 1195*991554f2SKenneth D. Merry } 1196*991554f2SKenneth D. Merry 1197*991554f2SKenneth D. Merry if (reply == NULL) { 1198*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1199*991554f2SKenneth D. Merry "NULL reset reply for tm %p\n", tm); 1200*991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1201*991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1202*991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1203*991554f2SKenneth D. Merry targ->tm = NULL; 1204*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1205*991554f2SKenneth D. Merry } 1206*991554f2SKenneth D. Merry else { 1207*991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1208*991554f2SKenneth D. Merry mpr_reinit(sc); 1209*991554f2SKenneth D. Merry } 1210*991554f2SKenneth D. Merry return; 1211*991554f2SKenneth D. Merry } 1212*991554f2SKenneth D. Merry 1213*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1214*991554f2SKenneth D. Merry "logical unit reset status 0x%x code 0x%x count %u\n", 1215*991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1216*991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1217*991554f2SKenneth D. Merry 1218*991554f2SKenneth D. Merry /* See if there are any outstanding commands for this LUN. 1219*991554f2SKenneth D. Merry * This could be made more efficient by using a per-LU data 1220*991554f2SKenneth D. Merry * structure of some sort. 1221*991554f2SKenneth D. Merry */ 1222*991554f2SKenneth D. Merry TAILQ_FOREACH(cm, &targ->commands, cm_link) { 1223*991554f2SKenneth D. Merry if (cm->cm_lun == tm->cm_lun) 1224*991554f2SKenneth D. Merry cm_count++; 1225*991554f2SKenneth D. Merry } 1226*991554f2SKenneth D. Merry 1227*991554f2SKenneth D. Merry if (cm_count == 0) { 1228*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1229*991554f2SKenneth D. Merry "logical unit %u finished recovery after reset\n", 1230*991554f2SKenneth D. Merry tm->cm_lun, tm); 1231*991554f2SKenneth D. Merry 1232*991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1233*991554f2SKenneth D. Merry tm->cm_lun); 1234*991554f2SKenneth D. Merry 1235*991554f2SKenneth D. Merry /* we've finished recovery for this logical unit. check and 1236*991554f2SKenneth D. Merry * see if some other logical unit has a timedout command 1237*991554f2SKenneth D. Merry * that needs to be processed. 1238*991554f2SKenneth D. Merry */ 1239*991554f2SKenneth D. Merry cm = TAILQ_FIRST(&targ->timedout_commands); 1240*991554f2SKenneth D. Merry if (cm) { 1241*991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1242*991554f2SKenneth D. Merry } 1243*991554f2SKenneth D. Merry else { 1244*991554f2SKenneth D. Merry targ->tm = NULL; 1245*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1246*991554f2SKenneth D. Merry } 1247*991554f2SKenneth D. Merry } 1248*991554f2SKenneth D. Merry else { 1249*991554f2SKenneth D. Merry /* if we still have commands for this LUN, the reset 1250*991554f2SKenneth D. Merry * effectively failed, regardless of the status reported. 1251*991554f2SKenneth D. Merry * Escalate to a target reset. 1252*991554f2SKenneth D. Merry */ 1253*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1254*991554f2SKenneth D. Merry "logical unit reset complete for tm %p, but still have %u " 1255*991554f2SKenneth D. Merry "command(s)\n", tm, cm_count); 1256*991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1257*991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); 1258*991554f2SKenneth D. Merry } 1259*991554f2SKenneth D. Merry } 1260*991554f2SKenneth D. Merry 1261*991554f2SKenneth D. Merry static void 1262*991554f2SKenneth D. Merry mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) 1263*991554f2SKenneth D. Merry { 1264*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1265*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1266*991554f2SKenneth D. Merry struct mprsas_target *targ; 1267*991554f2SKenneth D. Merry 1268*991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1269*991554f2SKenneth D. Merry 1270*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1271*991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1272*991554f2SKenneth D. Merry targ = tm->cm_targ; 1273*991554f2SKenneth D. Merry 1274*991554f2SKenneth D. Merry /* 1275*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1276*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1277*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1278*991554f2SKenneth D. Merry */ 1279*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1280*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! " 1281*991554f2SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags); 1282*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1283*991554f2SKenneth D. Merry return; 1284*991554f2SKenneth D. Merry } 1285*991554f2SKenneth D. Merry 1286*991554f2SKenneth D. Merry if (reply == NULL) { 1287*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1288*991554f2SKenneth D. Merry "NULL reset reply for tm %p\n", tm); 1289*991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1290*991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1291*991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1292*991554f2SKenneth D. Merry targ->tm = NULL; 1293*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1294*991554f2SKenneth D. Merry } 1295*991554f2SKenneth D. Merry else { 1296*991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1297*991554f2SKenneth D. Merry mpr_reinit(sc); 1298*991554f2SKenneth D. Merry } 1299*991554f2SKenneth D. Merry return; 1300*991554f2SKenneth D. Merry } 1301*991554f2SKenneth D. Merry 1302*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1303*991554f2SKenneth D. Merry "target reset status 0x%x code 0x%x count %u\n", 1304*991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1305*991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1306*991554f2SKenneth D. Merry 1307*991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1308*991554f2SKenneth D. Merry 1309*991554f2SKenneth D. Merry if (targ->outstanding == 0) { 1310*991554f2SKenneth D. Merry /* we've finished recovery for this target and all 1311*991554f2SKenneth D. Merry * of its logical units. 1312*991554f2SKenneth D. Merry */ 1313*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1314*991554f2SKenneth D. Merry "recovery finished after target reset\n"); 1315*991554f2SKenneth D. Merry 1316*991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1317*991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1318*991554f2SKenneth D. Merry 1319*991554f2SKenneth D. Merry targ->tm = NULL; 1320*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1321*991554f2SKenneth D. Merry } 1322*991554f2SKenneth D. Merry else { 1323*991554f2SKenneth D. Merry /* after a target reset, if this target still has 1324*991554f2SKenneth D. Merry * outstanding commands, the reset effectively failed, 1325*991554f2SKenneth D. Merry * regardless of the status reported. escalate. 1326*991554f2SKenneth D. Merry */ 1327*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1328*991554f2SKenneth D. Merry "target reset complete for tm %p, but still have %u " 1329*991554f2SKenneth D. Merry "command(s)\n", tm, targ->outstanding); 1330*991554f2SKenneth D. Merry mpr_reinit(sc); 1331*991554f2SKenneth D. Merry } 1332*991554f2SKenneth D. Merry } 1333*991554f2SKenneth D. Merry 1334*991554f2SKenneth D. Merry #define MPR_RESET_TIMEOUT 30 1335*991554f2SKenneth D. Merry 1336*991554f2SKenneth D. Merry static int 1337*991554f2SKenneth D. Merry mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) 1338*991554f2SKenneth D. Merry { 1339*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1340*991554f2SKenneth D. Merry struct mprsas_target *target; 1341*991554f2SKenneth D. Merry int err; 1342*991554f2SKenneth D. Merry 1343*991554f2SKenneth D. Merry target = tm->cm_targ; 1344*991554f2SKenneth D. Merry if (target->handle == 0) { 1345*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", 1346*991554f2SKenneth D. Merry __func__, target->tid); 1347*991554f2SKenneth D. Merry return -1; 1348*991554f2SKenneth D. Merry } 1349*991554f2SKenneth D. Merry 1350*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1351*991554f2SKenneth D. Merry req->DevHandle = htole16(target->handle); 1352*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1353*991554f2SKenneth D. Merry req->TaskType = type; 1354*991554f2SKenneth D. Merry 1355*991554f2SKenneth D. Merry if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { 1356*991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1357*991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, tm->cm_lun); 1358*991554f2SKenneth D. Merry tm->cm_targ->logical_unit_resets++; 1359*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1360*991554f2SKenneth D. Merry "sending logical unit reset\n"); 1361*991554f2SKenneth D. Merry tm->cm_complete = mprsas_logical_unit_reset_complete; 1362*991554f2SKenneth D. Merry } 1363*991554f2SKenneth D. Merry else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { 1364*991554f2SKenneth D. Merry /* 1365*991554f2SKenneth D. Merry * Target reset method = 1366*991554f2SKenneth D. Merry * SAS Hard Link Reset / SATA Link Reset 1367*991554f2SKenneth D. Merry */ 1368*991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 1369*991554f2SKenneth D. Merry tm->cm_targ->target_resets++; 1370*991554f2SKenneth D. Merry tm->cm_targ->flags |= MPRSAS_TARGET_INRESET; 1371*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1372*991554f2SKenneth D. Merry "sending target reset\n"); 1373*991554f2SKenneth D. Merry tm->cm_complete = mprsas_target_reset_complete; 1374*991554f2SKenneth D. Merry } 1375*991554f2SKenneth D. Merry else { 1376*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type); 1377*991554f2SKenneth D. Merry return -1; 1378*991554f2SKenneth D. Merry } 1379*991554f2SKenneth D. Merry 1380*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid, 1381*991554f2SKenneth D. Merry target->handle); 1382*991554f2SKenneth D. Merry if (target->encl_level_valid) { 1383*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 1384*991554f2SKenneth D. Merry "connector name (%4s)\n", target->encl_level, 1385*991554f2SKenneth D. Merry target->encl_slot, target->connector_name); 1386*991554f2SKenneth D. Merry } 1387*991554f2SKenneth D. Merry 1388*991554f2SKenneth D. Merry tm->cm_data = NULL; 1389*991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1390*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1391*991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1392*991554f2SKenneth D. Merry 1393*991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz, 1394*991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1395*991554f2SKenneth D. Merry 1396*991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1397*991554f2SKenneth D. Merry if (err) 1398*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1399*991554f2SKenneth D. Merry "error %d sending reset type %u\n", 1400*991554f2SKenneth D. Merry err, type); 1401*991554f2SKenneth D. Merry 1402*991554f2SKenneth D. Merry return err; 1403*991554f2SKenneth D. Merry } 1404*991554f2SKenneth D. Merry 1405*991554f2SKenneth D. Merry 1406*991554f2SKenneth D. Merry static void 1407*991554f2SKenneth D. Merry mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm) 1408*991554f2SKenneth D. Merry { 1409*991554f2SKenneth D. Merry struct mpr_command *cm; 1410*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1411*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1412*991554f2SKenneth D. Merry struct mprsas_target *targ; 1413*991554f2SKenneth D. Merry 1414*991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1415*991554f2SKenneth D. Merry 1416*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1417*991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1418*991554f2SKenneth D. Merry targ = tm->cm_targ; 1419*991554f2SKenneth D. Merry 1420*991554f2SKenneth D. Merry /* 1421*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1422*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1423*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1424*991554f2SKenneth D. Merry */ 1425*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1426*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1427*991554f2SKenneth D. Merry "cm_flags = %#x for abort %p TaskMID %u!\n", 1428*991554f2SKenneth D. Merry tm->cm_flags, tm, le16toh(req->TaskMID)); 1429*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1430*991554f2SKenneth D. Merry return; 1431*991554f2SKenneth D. Merry } 1432*991554f2SKenneth D. Merry 1433*991554f2SKenneth D. Merry if (reply == NULL) { 1434*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1435*991554f2SKenneth D. Merry "NULL abort reply for tm %p TaskMID %u\n", 1436*991554f2SKenneth D. Merry tm, le16toh(req->TaskMID)); 1437*991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1438*991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1439*991554f2SKenneth D. Merry targ->tm = NULL; 1440*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1441*991554f2SKenneth D. Merry } 1442*991554f2SKenneth D. Merry else { 1443*991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1444*991554f2SKenneth D. Merry mpr_reinit(sc); 1445*991554f2SKenneth D. Merry } 1446*991554f2SKenneth D. Merry return; 1447*991554f2SKenneth D. Merry } 1448*991554f2SKenneth D. Merry 1449*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1450*991554f2SKenneth D. Merry "abort TaskMID %u status 0x%x code 0x%x count %u\n", 1451*991554f2SKenneth D. Merry le16toh(req->TaskMID), 1452*991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1453*991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1454*991554f2SKenneth D. Merry 1455*991554f2SKenneth D. Merry cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); 1456*991554f2SKenneth D. Merry if (cm == NULL) { 1457*991554f2SKenneth D. Merry /* if there are no more timedout commands, we're done with 1458*991554f2SKenneth D. Merry * error recovery for this target. 1459*991554f2SKenneth D. Merry */ 1460*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1461*991554f2SKenneth D. Merry "finished recovery after aborting TaskMID %u\n", 1462*991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1463*991554f2SKenneth D. Merry 1464*991554f2SKenneth D. Merry targ->tm = NULL; 1465*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1466*991554f2SKenneth D. Merry } 1467*991554f2SKenneth D. Merry else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) { 1468*991554f2SKenneth D. Merry /* abort success, but we have more timedout commands to abort */ 1469*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1470*991554f2SKenneth D. Merry "continuing recovery after aborting TaskMID %u\n", 1471*991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1472*991554f2SKenneth D. Merry 1473*991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1474*991554f2SKenneth D. Merry } 1475*991554f2SKenneth D. Merry else { 1476*991554f2SKenneth D. Merry /* we didn't get a command completion, so the abort 1477*991554f2SKenneth D. Merry * failed as far as we're concerned. escalate. 1478*991554f2SKenneth D. Merry */ 1479*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1480*991554f2SKenneth D. Merry "abort failed for TaskMID %u tm %p\n", 1481*991554f2SKenneth D. Merry le16toh(req->TaskMID), tm); 1482*991554f2SKenneth D. Merry 1483*991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1484*991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); 1485*991554f2SKenneth D. Merry } 1486*991554f2SKenneth D. Merry } 1487*991554f2SKenneth D. Merry 1488*991554f2SKenneth D. Merry #define MPR_ABORT_TIMEOUT 5 1489*991554f2SKenneth D. Merry 1490*991554f2SKenneth D. Merry static int 1491*991554f2SKenneth D. Merry mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 1492*991554f2SKenneth D. Merry struct mpr_command *cm) 1493*991554f2SKenneth D. Merry { 1494*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1495*991554f2SKenneth D. Merry struct mprsas_target *targ; 1496*991554f2SKenneth D. Merry int err; 1497*991554f2SKenneth D. Merry 1498*991554f2SKenneth D. Merry targ = cm->cm_targ; 1499*991554f2SKenneth D. Merry if (targ->handle == 0) { 1500*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", 1501*991554f2SKenneth D. Merry __func__, cm->cm_ccb->ccb_h.target_id); 1502*991554f2SKenneth D. Merry return -1; 1503*991554f2SKenneth D. Merry } 1504*991554f2SKenneth D. Merry 1505*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1506*991554f2SKenneth D. Merry "Aborting command %p\n", cm); 1507*991554f2SKenneth D. Merry 1508*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1509*991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1510*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1511*991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; 1512*991554f2SKenneth D. Merry 1513*991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1514*991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); 1515*991554f2SKenneth D. Merry 1516*991554f2SKenneth D. Merry req->TaskMID = htole16(cm->cm_desc.Default.SMID); 1517*991554f2SKenneth D. Merry 1518*991554f2SKenneth D. Merry tm->cm_data = NULL; 1519*991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1520*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1521*991554f2SKenneth D. Merry tm->cm_complete = mprsas_abort_complete; 1522*991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1523*991554f2SKenneth D. Merry tm->cm_targ = cm->cm_targ; 1524*991554f2SKenneth D. Merry tm->cm_lun = cm->cm_lun; 1525*991554f2SKenneth D. Merry 1526*991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz, 1527*991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1528*991554f2SKenneth D. Merry 1529*991554f2SKenneth D. Merry targ->aborts++; 1530*991554f2SKenneth D. Merry 1531*991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1532*991554f2SKenneth D. Merry if (err) 1533*991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1534*991554f2SKenneth D. Merry "error %d sending abort for cm %p SMID %u\n", 1535*991554f2SKenneth D. Merry err, cm, req->TaskMID); 1536*991554f2SKenneth D. Merry return err; 1537*991554f2SKenneth D. Merry } 1538*991554f2SKenneth D. Merry 1539*991554f2SKenneth D. Merry 1540*991554f2SKenneth D. Merry static void 1541*991554f2SKenneth D. Merry mprsas_scsiio_timeout(void *data) 1542*991554f2SKenneth D. Merry { 1543*991554f2SKenneth D. Merry struct mpr_softc *sc; 1544*991554f2SKenneth D. Merry struct mpr_command *cm; 1545*991554f2SKenneth D. Merry struct mprsas_target *targ; 1546*991554f2SKenneth D. Merry 1547*991554f2SKenneth D. Merry cm = (struct mpr_command *)data; 1548*991554f2SKenneth D. Merry sc = cm->cm_sc; 1549*991554f2SKenneth D. Merry 1550*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1551*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1552*991554f2SKenneth D. Merry 1553*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm); 1554*991554f2SKenneth D. Merry 1555*991554f2SKenneth D. Merry /* 1556*991554f2SKenneth D. Merry * Run the interrupt handler to make sure it's not pending. This 1557*991554f2SKenneth D. Merry * isn't perfect because the command could have already completed 1558*991554f2SKenneth D. Merry * and been re-used, though this is unlikely. 1559*991554f2SKenneth D. Merry */ 1560*991554f2SKenneth D. Merry mpr_intr_locked(sc); 1561*991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_FREE) { 1562*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 1563*991554f2SKenneth D. Merry "SCSI command %p almost timed out\n", cm); 1564*991554f2SKenneth D. Merry return; 1565*991554f2SKenneth D. Merry } 1566*991554f2SKenneth D. Merry 1567*991554f2SKenneth D. Merry if (cm->cm_ccb == NULL) { 1568*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); 1569*991554f2SKenneth D. Merry return; 1570*991554f2SKenneth D. Merry } 1571*991554f2SKenneth D. Merry 1572*991554f2SKenneth D. Merry targ = cm->cm_targ; 1573*991554f2SKenneth D. Merry targ->timeouts++; 1574*991554f2SKenneth D. Merry 1575*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p " 1576*991554f2SKenneth D. Merry "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid, 1577*991554f2SKenneth D. Merry targ->handle); 1578*991554f2SKenneth D. Merry if (targ->encl_level_valid) { 1579*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 1580*991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 1581*991554f2SKenneth D. Merry targ->connector_name); 1582*991554f2SKenneth D. Merry } 1583*991554f2SKenneth D. Merry 1584*991554f2SKenneth D. Merry /* XXX first, check the firmware state, to see if it's still 1585*991554f2SKenneth D. Merry * operational. if not, do a diag reset. 1586*991554f2SKenneth D. Merry */ 1587*991554f2SKenneth D. Merry 1588*991554f2SKenneth D. Merry cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1589*991554f2SKenneth D. Merry cm->cm_state = MPR_CM_STATE_TIMEDOUT; 1590*991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); 1591*991554f2SKenneth D. Merry 1592*991554f2SKenneth D. Merry if (targ->tm != NULL) { 1593*991554f2SKenneth D. Merry /* target already in recovery, just queue up another 1594*991554f2SKenneth D. Merry * timedout command to be processed later. 1595*991554f2SKenneth D. Merry */ 1596*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for " 1597*991554f2SKenneth D. Merry "processing by tm %p\n", cm, targ->tm); 1598*991554f2SKenneth D. Merry } 1599*991554f2SKenneth D. Merry else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) { 1600*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n", 1601*991554f2SKenneth D. Merry cm, targ->tm); 1602*991554f2SKenneth D. Merry 1603*991554f2SKenneth D. Merry /* start recovery by aborting the first timedout command */ 1604*991554f2SKenneth D. Merry mprsas_send_abort(sc, targ->tm, cm); 1605*991554f2SKenneth D. Merry } 1606*991554f2SKenneth D. Merry else { 1607*991554f2SKenneth D. Merry /* XXX queue this target up for recovery once a TM becomes 1608*991554f2SKenneth D. Merry * available. The firmware only has a limited number of 1609*991554f2SKenneth D. Merry * HighPriority credits for the high priority requests used 1610*991554f2SKenneth D. Merry * for task management, and we ran out. 1611*991554f2SKenneth D. Merry * 1612*991554f2SKenneth D. Merry * Isilon: don't worry about this for now, since we have 1613*991554f2SKenneth D. Merry * more credits than disks in an enclosure, and limit 1614*991554f2SKenneth D. Merry * ourselves to one TM per target for recovery. 1615*991554f2SKenneth D. Merry */ 1616*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, 1617*991554f2SKenneth D. Merry "timedout cm %p failed to allocate a tm\n", cm); 1618*991554f2SKenneth D. Merry } 1619*991554f2SKenneth D. Merry } 1620*991554f2SKenneth D. Merry 1621*991554f2SKenneth D. Merry static void 1622*991554f2SKenneth D. Merry mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) 1623*991554f2SKenneth D. Merry { 1624*991554f2SKenneth D. Merry MPI2_SCSI_IO_REQUEST *req; 1625*991554f2SKenneth D. Merry struct ccb_scsiio *csio; 1626*991554f2SKenneth D. Merry struct mpr_softc *sc; 1627*991554f2SKenneth D. Merry struct mprsas_target *targ; 1628*991554f2SKenneth D. Merry struct mprsas_lun *lun; 1629*991554f2SKenneth D. Merry struct mpr_command *cm; 1630*991554f2SKenneth D. Merry uint8_t i, lba_byte, *ref_tag_addr; 1631*991554f2SKenneth D. Merry uint16_t eedp_flags; 1632*991554f2SKenneth D. Merry uint32_t mpi_control; 1633*991554f2SKenneth D. Merry 1634*991554f2SKenneth D. Merry sc = sassc->sc; 1635*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1636*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1637*991554f2SKenneth D. Merry 1638*991554f2SKenneth D. Merry csio = &ccb->csio; 1639*991554f2SKenneth D. Merry targ = &sassc->targets[csio->ccb_h.target_id]; 1640*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags); 1641*991554f2SKenneth D. Merry if (targ->handle == 0x0) { 1642*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", 1643*991554f2SKenneth D. Merry __func__, csio->ccb_h.target_id); 1644*991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1645*991554f2SKenneth D. Merry xpt_done(ccb); 1646*991554f2SKenneth D. Merry return; 1647*991554f2SKenneth D. Merry } 1648*991554f2SKenneth D. Merry if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) { 1649*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO " 1650*991554f2SKenneth D. Merry "supported %u\n", __func__, csio->ccb_h.target_id); 1651*991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1652*991554f2SKenneth D. Merry xpt_done(ccb); 1653*991554f2SKenneth D. Merry return; 1654*991554f2SKenneth D. Merry } 1655*991554f2SKenneth D. Merry /* 1656*991554f2SKenneth D. Merry * Sometimes, it is possible to get a command that is not "In 1657*991554f2SKenneth D. Merry * Progress" and was actually aborted by the upper layer. Check for 1658*991554f2SKenneth D. Merry * this here and complete the command without error. 1659*991554f2SKenneth D. Merry */ 1660*991554f2SKenneth D. Merry if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1661*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for " 1662*991554f2SKenneth D. Merry "target %u\n", __func__, csio->ccb_h.target_id); 1663*991554f2SKenneth D. Merry xpt_done(ccb); 1664*991554f2SKenneth D. Merry return; 1665*991554f2SKenneth D. Merry } 1666*991554f2SKenneth D. Merry /* 1667*991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't tell CAM 1668*991554f2SKenneth D. Merry * that the volume has timed out. We want volumes to be enumerated 1669*991554f2SKenneth D. Merry * until they are deleted/removed, not just failed. 1670*991554f2SKenneth D. Merry */ 1671*991554f2SKenneth D. Merry if (targ->flags & MPRSAS_TARGET_INREMOVAL) { 1672*991554f2SKenneth D. Merry if (targ->devinfo == 0) 1673*991554f2SKenneth D. Merry csio->ccb_h.status = CAM_REQ_CMP; 1674*991554f2SKenneth D. Merry else 1675*991554f2SKenneth D. Merry csio->ccb_h.status = CAM_SEL_TIMEOUT; 1676*991554f2SKenneth D. Merry xpt_done(ccb); 1677*991554f2SKenneth D. Merry return; 1678*991554f2SKenneth D. Merry } 1679*991554f2SKenneth D. Merry 1680*991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) { 1681*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__); 1682*991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1683*991554f2SKenneth D. Merry xpt_done(ccb); 1684*991554f2SKenneth D. Merry return; 1685*991554f2SKenneth D. Merry } 1686*991554f2SKenneth D. Merry 1687*991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 1688*991554f2SKenneth D. Merry if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) { 1689*991554f2SKenneth D. Merry if (cm != NULL) { 1690*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 1691*991554f2SKenneth D. Merry } 1692*991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 1693*991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 1694*991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 1695*991554f2SKenneth D. Merry } 1696*991554f2SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1697*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1698*991554f2SKenneth D. Merry xpt_done(ccb); 1699*991554f2SKenneth D. Merry return; 1700*991554f2SKenneth D. Merry } 1701*991554f2SKenneth D. Merry 1702*991554f2SKenneth D. Merry req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; 1703*991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 1704*991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1705*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 1706*991554f2SKenneth D. Merry req->MsgFlags = 0; 1707*991554f2SKenneth D. Merry req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); 1708*991554f2SKenneth D. Merry req->SenseBufferLength = MPR_SENSE_LEN; 1709*991554f2SKenneth D. Merry req->SGLFlags = 0; 1710*991554f2SKenneth D. Merry req->ChainOffset = 0; 1711*991554f2SKenneth D. Merry req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ 1712*991554f2SKenneth D. Merry req->SGLOffset1= 0; 1713*991554f2SKenneth D. Merry req->SGLOffset2= 0; 1714*991554f2SKenneth D. Merry req->SGLOffset3= 0; 1715*991554f2SKenneth D. Merry req->SkipCount = 0; 1716*991554f2SKenneth D. Merry req->DataLength = htole32(csio->dxfer_len); 1717*991554f2SKenneth D. Merry req->BidirectionalDataLength = 0; 1718*991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 1719*991554f2SKenneth D. Merry req->EEDPFlags = 0; 1720*991554f2SKenneth D. Merry 1721*991554f2SKenneth D. Merry /* Note: BiDirectional transfers are not supported */ 1722*991554f2SKenneth D. Merry switch (csio->ccb_h.flags & CAM_DIR_MASK) { 1723*991554f2SKenneth D. Merry case CAM_DIR_IN: 1724*991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_READ; 1725*991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAIN; 1726*991554f2SKenneth D. Merry break; 1727*991554f2SKenneth D. Merry case CAM_DIR_OUT: 1728*991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_WRITE; 1729*991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; 1730*991554f2SKenneth D. Merry break; 1731*991554f2SKenneth D. Merry case CAM_DIR_NONE: 1732*991554f2SKenneth D. Merry default: 1733*991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; 1734*991554f2SKenneth D. Merry break; 1735*991554f2SKenneth D. Merry } 1736*991554f2SKenneth D. Merry 1737*991554f2SKenneth D. Merry if (csio->cdb_len == 32) 1738*991554f2SKenneth D. Merry mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; 1739*991554f2SKenneth D. Merry /* 1740*991554f2SKenneth D. Merry * It looks like the hardware doesn't require an explicit tag 1741*991554f2SKenneth D. Merry * number for each transaction. SAM Task Management not supported 1742*991554f2SKenneth D. Merry * at the moment. 1743*991554f2SKenneth D. Merry */ 1744*991554f2SKenneth D. Merry switch (csio->tag_action) { 1745*991554f2SKenneth D. Merry case MSG_HEAD_OF_Q_TAG: 1746*991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ; 1747*991554f2SKenneth D. Merry break; 1748*991554f2SKenneth D. Merry case MSG_ORDERED_Q_TAG: 1749*991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; 1750*991554f2SKenneth D. Merry break; 1751*991554f2SKenneth D. Merry case MSG_ACA_TASK: 1752*991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ; 1753*991554f2SKenneth D. Merry break; 1754*991554f2SKenneth D. Merry case CAM_TAG_ACTION_NONE: 1755*991554f2SKenneth D. Merry case MSG_SIMPLE_Q_TAG: 1756*991554f2SKenneth D. Merry default: 1757*991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; 1758*991554f2SKenneth D. Merry break; 1759*991554f2SKenneth D. Merry } 1760*991554f2SKenneth D. Merry mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; 1761*991554f2SKenneth D. Merry req->Control = htole32(mpi_control); 1762*991554f2SKenneth D. Merry 1763*991554f2SKenneth D. Merry if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { 1764*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 1765*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_LUN_INVALID; 1766*991554f2SKenneth D. Merry xpt_done(ccb); 1767*991554f2SKenneth D. Merry return; 1768*991554f2SKenneth D. Merry } 1769*991554f2SKenneth D. Merry 1770*991554f2SKenneth D. Merry if (csio->ccb_h.flags & CAM_CDB_POINTER) 1771*991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); 1772*991554f2SKenneth D. Merry else 1773*991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); 1774*991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 1775*991554f2SKenneth D. Merry 1776*991554f2SKenneth D. Merry /* 1777*991554f2SKenneth D. Merry * Check if EEDP is supported and enabled. If it is then check if the 1778*991554f2SKenneth D. Merry * SCSI opcode could be using EEDP. If so, make sure the LUN exists and 1779*991554f2SKenneth D. Merry * is formatted for EEDP support. If all of this is true, set CDB up 1780*991554f2SKenneth D. Merry * for EEDP transfer. 1781*991554f2SKenneth D. Merry */ 1782*991554f2SKenneth D. Merry eedp_flags = op_code_prot[req->CDB.CDB32[0]]; 1783*991554f2SKenneth D. Merry if (sc->eedp_enabled && eedp_flags) { 1784*991554f2SKenneth D. Merry SLIST_FOREACH(lun, &targ->luns, lun_link) { 1785*991554f2SKenneth D. Merry if (lun->lun_id == csio->ccb_h.target_lun) { 1786*991554f2SKenneth D. Merry break; 1787*991554f2SKenneth D. Merry } 1788*991554f2SKenneth D. Merry } 1789*991554f2SKenneth D. Merry 1790*991554f2SKenneth D. Merry if ((lun != NULL) && (lun->eedp_formatted)) { 1791*991554f2SKenneth D. Merry req->EEDPBlockSize = htole16(lun->eedp_block_size); 1792*991554f2SKenneth D. Merry eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 1793*991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 1794*991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); 1795*991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 1796*991554f2SKenneth D. Merry 1797*991554f2SKenneth D. Merry /* 1798*991554f2SKenneth D. Merry * If CDB less than 32, fill in Primary Ref Tag with 1799*991554f2SKenneth D. Merry * low 4 bytes of LBA. If CDB is 32, tag stuff is 1800*991554f2SKenneth D. Merry * already there. Also, set protection bit. FreeBSD 1801*991554f2SKenneth D. Merry * currently does not support CDBs bigger than 16, but 1802*991554f2SKenneth D. Merry * the code doesn't hurt, and will be here for the 1803*991554f2SKenneth D. Merry * future. 1804*991554f2SKenneth D. Merry */ 1805*991554f2SKenneth D. Merry if (csio->cdb_len != 32) { 1806*991554f2SKenneth D. Merry lba_byte = (csio->cdb_len == 16) ? 6 : 2; 1807*991554f2SKenneth D. Merry ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. 1808*991554f2SKenneth D. Merry PrimaryReferenceTag; 1809*991554f2SKenneth D. Merry for (i = 0; i < 4; i++) { 1810*991554f2SKenneth D. Merry *ref_tag_addr = 1811*991554f2SKenneth D. Merry req->CDB.CDB32[lba_byte + i]; 1812*991554f2SKenneth D. Merry ref_tag_addr++; 1813*991554f2SKenneth D. Merry } 1814*991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryReferenceTag = 1815*991554f2SKenneth D. Merry htole32(req-> 1816*991554f2SKenneth D. Merry CDB.EEDP32.PrimaryReferenceTag); 1817*991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryApplicationTagMask = 1818*991554f2SKenneth D. Merry 0xFFFF; 1819*991554f2SKenneth D. Merry req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | 1820*991554f2SKenneth D. Merry 0x20; 1821*991554f2SKenneth D. Merry } else { 1822*991554f2SKenneth D. Merry eedp_flags |= 1823*991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; 1824*991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 1825*991554f2SKenneth D. Merry req->CDB.CDB32[10] = (req->CDB.CDB32[10] & 1826*991554f2SKenneth D. Merry 0x1F) | 0x20; 1827*991554f2SKenneth D. Merry } 1828*991554f2SKenneth D. Merry } 1829*991554f2SKenneth D. Merry } 1830*991554f2SKenneth D. Merry 1831*991554f2SKenneth D. Merry cm->cm_length = csio->dxfer_len; 1832*991554f2SKenneth D. Merry if (cm->cm_length != 0) { 1833*991554f2SKenneth D. Merry cm->cm_data = ccb; 1834*991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_CCB; 1835*991554f2SKenneth D. Merry } else { 1836*991554f2SKenneth D. Merry cm->cm_data = NULL; 1837*991554f2SKenneth D. Merry } 1838*991554f2SKenneth D. Merry cm->cm_sge = &req->SGL; 1839*991554f2SKenneth D. Merry cm->cm_sglsize = (32 - 24) * 4; 1840*991554f2SKenneth D. Merry cm->cm_complete = mprsas_scsiio_complete; 1841*991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 1842*991554f2SKenneth D. Merry cm->cm_targ = targ; 1843*991554f2SKenneth D. Merry cm->cm_lun = csio->ccb_h.target_lun; 1844*991554f2SKenneth D. Merry cm->cm_ccb = ccb; 1845*991554f2SKenneth D. Merry /* 1846*991554f2SKenneth D. Merry * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) 1847*991554f2SKenneth D. Merry * and set descriptor type. 1848*991554f2SKenneth D. Merry */ 1849*991554f2SKenneth D. Merry if (targ->scsi_req_desc_type == 1850*991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { 1851*991554f2SKenneth D. Merry req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; 1852*991554f2SKenneth D. Merry cm->cm_desc.FastPathSCSIIO.RequestFlags = 1853*991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 1854*991554f2SKenneth D. Merry cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle); 1855*991554f2SKenneth D. Merry } else { 1856*991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.RequestFlags = 1857*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 1858*991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); 1859*991554f2SKenneth D. Merry } 1860*991554f2SKenneth D. Merry 1861*991554f2SKenneth D. Merry callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, 1862*991554f2SKenneth D. Merry mprsas_scsiio_timeout, cm); 1863*991554f2SKenneth D. Merry 1864*991554f2SKenneth D. Merry targ->issued++; 1865*991554f2SKenneth D. Merry targ->outstanding++; 1866*991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); 1867*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED; 1868*991554f2SKenneth D. Merry 1869*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", 1870*991554f2SKenneth D. Merry __func__, cm, ccb, targ->outstanding); 1871*991554f2SKenneth D. Merry 1872*991554f2SKenneth D. Merry mpr_map_command(sc, cm); 1873*991554f2SKenneth D. Merry return; 1874*991554f2SKenneth D. Merry } 1875*991554f2SKenneth D. Merry 1876*991554f2SKenneth D. Merry static void 1877*991554f2SKenneth D. Merry mpr_response_code(struct mpr_softc *sc, u8 response_code) 1878*991554f2SKenneth D. Merry { 1879*991554f2SKenneth D. Merry char *desc; 1880*991554f2SKenneth D. Merry 1881*991554f2SKenneth D. Merry switch (response_code) { 1882*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: 1883*991554f2SKenneth D. Merry desc = "task management request completed"; 1884*991554f2SKenneth D. Merry break; 1885*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: 1886*991554f2SKenneth D. Merry desc = "invalid frame"; 1887*991554f2SKenneth D. Merry break; 1888*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: 1889*991554f2SKenneth D. Merry desc = "task management request not supported"; 1890*991554f2SKenneth D. Merry break; 1891*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_FAILED: 1892*991554f2SKenneth D. Merry desc = "task management request failed"; 1893*991554f2SKenneth D. Merry break; 1894*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: 1895*991554f2SKenneth D. Merry desc = "task management request succeeded"; 1896*991554f2SKenneth D. Merry break; 1897*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: 1898*991554f2SKenneth D. Merry desc = "invalid lun"; 1899*991554f2SKenneth D. Merry break; 1900*991554f2SKenneth D. Merry case 0xA: 1901*991554f2SKenneth D. Merry desc = "overlapped tag attempted"; 1902*991554f2SKenneth D. Merry break; 1903*991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: 1904*991554f2SKenneth D. Merry desc = "task queued, however not sent to target"; 1905*991554f2SKenneth D. Merry break; 1906*991554f2SKenneth D. Merry default: 1907*991554f2SKenneth D. Merry desc = "unknown"; 1908*991554f2SKenneth D. Merry break; 1909*991554f2SKenneth D. Merry } 1910*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code, 1911*991554f2SKenneth D. Merry desc); 1912*991554f2SKenneth D. Merry } 1913*991554f2SKenneth D. Merry 1914*991554f2SKenneth D. Merry /** 1915*991554f2SKenneth D. Merry * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request 1916*991554f2SKenneth D. Merry */ 1917*991554f2SKenneth D. Merry static void 1918*991554f2SKenneth D. Merry mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, 1919*991554f2SKenneth D. Merry Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ) 1920*991554f2SKenneth D. Merry { 1921*991554f2SKenneth D. Merry u32 response_info; 1922*991554f2SKenneth D. Merry u8 *response_bytes; 1923*991554f2SKenneth D. Merry u16 ioc_status = le16toh(mpi_reply->IOCStatus) & 1924*991554f2SKenneth D. Merry MPI2_IOCSTATUS_MASK; 1925*991554f2SKenneth D. Merry u8 scsi_state = mpi_reply->SCSIState; 1926*991554f2SKenneth D. Merry u8 scsi_status = mpi_reply->SCSIStatus; 1927*991554f2SKenneth D. Merry char *desc_ioc_state = NULL; 1928*991554f2SKenneth D. Merry char *desc_scsi_status = NULL; 1929*991554f2SKenneth D. Merry char *desc_scsi_state = sc->tmp_string; 1930*991554f2SKenneth D. Merry u32 log_info = le32toh(mpi_reply->IOCLogInfo); 1931*991554f2SKenneth D. Merry 1932*991554f2SKenneth D. Merry if (log_info == 0x31170000) 1933*991554f2SKenneth D. Merry return; 1934*991554f2SKenneth D. Merry 1935*991554f2SKenneth D. Merry switch (ioc_status) { 1936*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 1937*991554f2SKenneth D. Merry desc_ioc_state = "success"; 1938*991554f2SKenneth D. Merry break; 1939*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 1940*991554f2SKenneth D. Merry desc_ioc_state = "invalid function"; 1941*991554f2SKenneth D. Merry break; 1942*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 1943*991554f2SKenneth D. Merry desc_ioc_state = "scsi recovered error"; 1944*991554f2SKenneth D. Merry break; 1945*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 1946*991554f2SKenneth D. Merry desc_ioc_state = "scsi invalid dev handle"; 1947*991554f2SKenneth D. Merry break; 1948*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 1949*991554f2SKenneth D. Merry desc_ioc_state = "scsi device not there"; 1950*991554f2SKenneth D. Merry break; 1951*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 1952*991554f2SKenneth D. Merry desc_ioc_state = "scsi data overrun"; 1953*991554f2SKenneth D. Merry break; 1954*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 1955*991554f2SKenneth D. Merry desc_ioc_state = "scsi data underrun"; 1956*991554f2SKenneth D. Merry break; 1957*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 1958*991554f2SKenneth D. Merry desc_ioc_state = "scsi io data error"; 1959*991554f2SKenneth D. Merry break; 1960*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 1961*991554f2SKenneth D. Merry desc_ioc_state = "scsi protocol error"; 1962*991554f2SKenneth D. Merry break; 1963*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 1964*991554f2SKenneth D. Merry desc_ioc_state = "scsi task terminated"; 1965*991554f2SKenneth D. Merry break; 1966*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 1967*991554f2SKenneth D. Merry desc_ioc_state = "scsi residual mismatch"; 1968*991554f2SKenneth D. Merry break; 1969*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 1970*991554f2SKenneth D. Merry desc_ioc_state = "scsi task mgmt failed"; 1971*991554f2SKenneth D. Merry break; 1972*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 1973*991554f2SKenneth D. Merry desc_ioc_state = "scsi ioc terminated"; 1974*991554f2SKenneth D. Merry break; 1975*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 1976*991554f2SKenneth D. Merry desc_ioc_state = "scsi ext terminated"; 1977*991554f2SKenneth D. Merry break; 1978*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: 1979*991554f2SKenneth D. Merry desc_ioc_state = "eedp guard error"; 1980*991554f2SKenneth D. Merry break; 1981*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: 1982*991554f2SKenneth D. Merry desc_ioc_state = "eedp ref tag error"; 1983*991554f2SKenneth D. Merry break; 1984*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: 1985*991554f2SKenneth D. Merry desc_ioc_state = "eedp app tag error"; 1986*991554f2SKenneth D. Merry break; 1987*991554f2SKenneth D. Merry default: 1988*991554f2SKenneth D. Merry desc_ioc_state = "unknown"; 1989*991554f2SKenneth D. Merry break; 1990*991554f2SKenneth D. Merry } 1991*991554f2SKenneth D. Merry 1992*991554f2SKenneth D. Merry switch (scsi_status) { 1993*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_GOOD: 1994*991554f2SKenneth D. Merry desc_scsi_status = "good"; 1995*991554f2SKenneth D. Merry break; 1996*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CHECK_CONDITION: 1997*991554f2SKenneth D. Merry desc_scsi_status = "check condition"; 1998*991554f2SKenneth D. Merry break; 1999*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CONDITION_MET: 2000*991554f2SKenneth D. Merry desc_scsi_status = "condition met"; 2001*991554f2SKenneth D. Merry break; 2002*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_BUSY: 2003*991554f2SKenneth D. Merry desc_scsi_status = "busy"; 2004*991554f2SKenneth D. Merry break; 2005*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE: 2006*991554f2SKenneth D. Merry desc_scsi_status = "intermediate"; 2007*991554f2SKenneth D. Merry break; 2008*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: 2009*991554f2SKenneth D. Merry desc_scsi_status = "intermediate condmet"; 2010*991554f2SKenneth D. Merry break; 2011*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: 2012*991554f2SKenneth D. Merry desc_scsi_status = "reservation conflict"; 2013*991554f2SKenneth D. Merry break; 2014*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_COMMAND_TERMINATED: 2015*991554f2SKenneth D. Merry desc_scsi_status = "command terminated"; 2016*991554f2SKenneth D. Merry break; 2017*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_SET_FULL: 2018*991554f2SKenneth D. Merry desc_scsi_status = "task set full"; 2019*991554f2SKenneth D. Merry break; 2020*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_ACA_ACTIVE: 2021*991554f2SKenneth D. Merry desc_scsi_status = "aca active"; 2022*991554f2SKenneth D. Merry break; 2023*991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_ABORTED: 2024*991554f2SKenneth D. Merry desc_scsi_status = "task aborted"; 2025*991554f2SKenneth D. Merry break; 2026*991554f2SKenneth D. Merry default: 2027*991554f2SKenneth D. Merry desc_scsi_status = "unknown"; 2028*991554f2SKenneth D. Merry break; 2029*991554f2SKenneth D. Merry } 2030*991554f2SKenneth D. Merry 2031*991554f2SKenneth D. Merry desc_scsi_state[0] = '\0'; 2032*991554f2SKenneth D. Merry if (!scsi_state) 2033*991554f2SKenneth D. Merry desc_scsi_state = " "; 2034*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) 2035*991554f2SKenneth D. Merry strcat(desc_scsi_state, "response info "); 2036*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_TERMINATED) 2037*991554f2SKenneth D. Merry strcat(desc_scsi_state, "state terminated "); 2038*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) 2039*991554f2SKenneth D. Merry strcat(desc_scsi_state, "no status "); 2040*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) 2041*991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense failed "); 2042*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) 2043*991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense valid "); 2044*991554f2SKenneth D. Merry 2045*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n", 2046*991554f2SKenneth D. Merry le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status); 2047*991554f2SKenneth D. Merry if (targ->encl_level_valid) { 2048*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 2049*991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 2050*991554f2SKenneth D. Merry targ->connector_name); 2051*991554f2SKenneth D. Merry } 2052*991554f2SKenneth D. Merry /* We can add more detail about underflow data here 2053*991554f2SKenneth D. Merry * TO-DO 2054*991554f2SKenneth D. Merry * */ 2055*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), " 2056*991554f2SKenneth D. Merry "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status, 2057*991554f2SKenneth D. Merry desc_scsi_state, scsi_state); 2058*991554f2SKenneth D. Merry 2059*991554f2SKenneth D. Merry if (sc->mpr_debug & MPR_XINFO && 2060*991554f2SKenneth D. Merry scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2061*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n"); 2062*991554f2SKenneth D. Merry scsi_sense_print(csio); 2063*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n"); 2064*991554f2SKenneth D. Merry } 2065*991554f2SKenneth D. Merry 2066*991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { 2067*991554f2SKenneth D. Merry response_info = le32toh(mpi_reply->ResponseInfo); 2068*991554f2SKenneth D. Merry response_bytes = (u8 *)&response_info; 2069*991554f2SKenneth D. Merry mpr_response_code(sc,response_bytes[0]); 2070*991554f2SKenneth D. Merry } 2071*991554f2SKenneth D. Merry } 2072*991554f2SKenneth D. Merry 2073*991554f2SKenneth D. Merry static void 2074*991554f2SKenneth D. Merry mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2075*991554f2SKenneth D. Merry { 2076*991554f2SKenneth D. Merry MPI2_SCSI_IO_REPLY *rep; 2077*991554f2SKenneth D. Merry union ccb *ccb; 2078*991554f2SKenneth D. Merry struct ccb_scsiio *csio; 2079*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2080*991554f2SKenneth D. Merry struct scsi_vpd_supported_page_list *vpd_list = NULL; 2081*991554f2SKenneth D. Merry u8 *TLR_bits, TLR_on; 2082*991554f2SKenneth D. Merry int dir = 0, i; 2083*991554f2SKenneth D. Merry u16 alloc_len; 2084*991554f2SKenneth D. Merry 2085*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 2086*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, 2087*991554f2SKenneth D. Merry "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, 2088*991554f2SKenneth D. Merry cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, 2089*991554f2SKenneth D. Merry cm->cm_targ->outstanding); 2090*991554f2SKenneth D. Merry 2091*991554f2SKenneth D. Merry callout_stop(&cm->cm_callout); 2092*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 2093*991554f2SKenneth D. Merry 2094*991554f2SKenneth D. Merry sassc = sc->sassc; 2095*991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 2096*991554f2SKenneth D. Merry csio = &ccb->csio; 2097*991554f2SKenneth D. Merry rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; 2098*991554f2SKenneth D. Merry /* 2099*991554f2SKenneth D. Merry * XXX KDM if the chain allocation fails, does it matter if we do 2100*991554f2SKenneth D. Merry * the sync and unload here? It is simpler to do it in every case, 2101*991554f2SKenneth D. Merry * assuming it doesn't cause problems. 2102*991554f2SKenneth D. Merry */ 2103*991554f2SKenneth D. Merry if (cm->cm_data != NULL) { 2104*991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) 2105*991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTREAD; 2106*991554f2SKenneth D. Merry else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) 2107*991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTWRITE; 2108*991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2109*991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2110*991554f2SKenneth D. Merry } 2111*991554f2SKenneth D. Merry 2112*991554f2SKenneth D. Merry cm->cm_targ->completed++; 2113*991554f2SKenneth D. Merry cm->cm_targ->outstanding--; 2114*991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); 2115*991554f2SKenneth D. Merry ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED); 2116*991554f2SKenneth D. Merry 2117*991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) { 2118*991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); 2119*991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2120*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2121*991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery " 2122*991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb, 2123*991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, 2124*991554f2SKenneth D. Merry rep->SCSIState, le32toh(rep->TransferCount)); 2125*991554f2SKenneth D. Merry else 2126*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2127*991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery\n", 2128*991554f2SKenneth D. Merry cm, cm->cm_ccb); 2129*991554f2SKenneth D. Merry } else if (cm->cm_targ->tm != NULL) { 2130*991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2131*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2132*991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery " 2133*991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2134*991554f2SKenneth D. Merry cm, cm->cm_ccb, le16toh(rep->IOCStatus), 2135*991554f2SKenneth D. Merry rep->SCSIStatus, rep->SCSIState, 2136*991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2137*991554f2SKenneth D. Merry else 2138*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2139*991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery\n", 2140*991554f2SKenneth D. Merry cm, cm->cm_ccb); 2141*991554f2SKenneth D. Merry } else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 2142*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2143*991554f2SKenneth D. Merry "reset completed cm %p ccb %p\n", cm, cm->cm_ccb); 2144*991554f2SKenneth D. Merry } 2145*991554f2SKenneth D. Merry 2146*991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2147*991554f2SKenneth D. Merry /* 2148*991554f2SKenneth D. Merry * We ran into an error after we tried to map the command, 2149*991554f2SKenneth D. Merry * so we're getting a callback without queueing the command 2150*991554f2SKenneth D. Merry * to the hardware. So we set the status here, and it will 2151*991554f2SKenneth D. Merry * be retained below. We'll go through the "fast path", 2152*991554f2SKenneth D. Merry * because there can be no reply when we haven't actually 2153*991554f2SKenneth D. Merry * gone out to the hardware. 2154*991554f2SKenneth D. Merry */ 2155*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQUEUE_REQ; 2156*991554f2SKenneth D. Merry 2157*991554f2SKenneth D. Merry /* 2158*991554f2SKenneth D. Merry * Currently the only error included in the mask is 2159*991554f2SKenneth D. Merry * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of 2160*991554f2SKenneth D. Merry * chain frames. We need to freeze the queue until we get 2161*991554f2SKenneth D. Merry * a command that completed without this error, which will 2162*991554f2SKenneth D. Merry * hopefully have some chain frames attached that we can 2163*991554f2SKenneth D. Merry * use. If we wanted to get smarter about it, we would 2164*991554f2SKenneth D. Merry * only unfreeze the queue in this condition when we're 2165*991554f2SKenneth D. Merry * sure that we're getting some chain frames back. That's 2166*991554f2SKenneth D. Merry * probably unnecessary. 2167*991554f2SKenneth D. Merry */ 2168*991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 2169*991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 2170*991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 2171*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Error sending command, " 2172*991554f2SKenneth D. Merry "freezing SIM queue\n"); 2173*991554f2SKenneth D. Merry } 2174*991554f2SKenneth D. Merry } 2175*991554f2SKenneth D. Merry 2176*991554f2SKenneth D. Merry /* 2177*991554f2SKenneth D. Merry * If this is a Start Stop Unit command and it was issued by the driver 2178*991554f2SKenneth D. Merry * during shutdown, decrement the refcount to account for all of the 2179*991554f2SKenneth D. Merry * commands that were sent. All SSU commands should be completed before 2180*991554f2SKenneth D. Merry * shutdown completes, meaning SSU_refcount will be 0 after SSU_started 2181*991554f2SKenneth D. Merry * is TRUE. 2182*991554f2SKenneth D. Merry */ 2183*991554f2SKenneth D. Merry if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { 2184*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); 2185*991554f2SKenneth D. Merry sc->SSU_refcount--; 2186*991554f2SKenneth D. Merry } 2187*991554f2SKenneth D. Merry 2188*991554f2SKenneth D. Merry /* Take the fast path to completion */ 2189*991554f2SKenneth D. Merry if (cm->cm_reply == NULL) { 2190*991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 2191*991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) 2192*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 2193*991554f2SKenneth D. Merry else { 2194*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2195*991554f2SKenneth D. Merry ccb->csio.scsi_status = SCSI_STATUS_OK; 2196*991554f2SKenneth D. Merry } 2197*991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2198*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2199*991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2200*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 2201*991554f2SKenneth D. Merry "Unfreezing SIM queue\n"); 2202*991554f2SKenneth D. Merry } 2203*991554f2SKenneth D. Merry } 2204*991554f2SKenneth D. Merry 2205*991554f2SKenneth D. Merry /* 2206*991554f2SKenneth D. Merry * There are two scenarios where the status won't be 2207*991554f2SKenneth D. Merry * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is 2208*991554f2SKenneth D. Merry * set, the second is in the MPR_FLAGS_DIAGRESET above. 2209*991554f2SKenneth D. Merry */ 2210*991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2211*991554f2SKenneth D. Merry /* 2212*991554f2SKenneth D. Merry * Freeze the dev queue so that commands are 2213*991554f2SKenneth D. Merry * executed in the correct order with after error 2214*991554f2SKenneth D. Merry * recovery. 2215*991554f2SKenneth D. Merry */ 2216*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2217*991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2218*991554f2SKenneth D. Merry } 2219*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2220*991554f2SKenneth D. Merry xpt_done(ccb); 2221*991554f2SKenneth D. Merry return; 2222*991554f2SKenneth D. Merry } 2223*991554f2SKenneth D. Merry 2224*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2225*991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2226*991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2227*991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2228*991554f2SKenneth D. Merry 2229*991554f2SKenneth D. Merry switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { 2230*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 2231*991554f2SKenneth D. Merry csio->resid = cm->cm_length - le32toh(rep->TransferCount); 2232*991554f2SKenneth D. Merry /* FALLTHROUGH */ 2233*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 2234*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 2235*991554f2SKenneth D. Merry 2236*991554f2SKenneth D. Merry if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == 2237*991554f2SKenneth D. Merry MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) 2238*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); 2239*991554f2SKenneth D. Merry 2240*991554f2SKenneth D. Merry /* Completion failed at the transport level. */ 2241*991554f2SKenneth D. Merry if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | 2242*991554f2SKenneth D. Merry MPI2_SCSI_STATE_TERMINATED)) { 2243*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2244*991554f2SKenneth D. Merry break; 2245*991554f2SKenneth D. Merry } 2246*991554f2SKenneth D. Merry 2247*991554f2SKenneth D. Merry /* In a modern packetized environment, an autosense failure 2248*991554f2SKenneth D. Merry * implies that there's not much else that can be done to 2249*991554f2SKenneth D. Merry * recover the command. 2250*991554f2SKenneth D. Merry */ 2251*991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { 2252*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 2253*991554f2SKenneth D. Merry break; 2254*991554f2SKenneth D. Merry } 2255*991554f2SKenneth D. Merry 2256*991554f2SKenneth D. Merry /* 2257*991554f2SKenneth D. Merry * CAM doesn't care about SAS Response Info data, but if this is 2258*991554f2SKenneth D. Merry * the state check if TLR should be done. If not, clear the 2259*991554f2SKenneth D. Merry * TLR_bits for the target. 2260*991554f2SKenneth D. Merry */ 2261*991554f2SKenneth D. Merry if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && 2262*991554f2SKenneth D. Merry ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) 2263*991554f2SKenneth D. Merry == MPR_SCSI_RI_INVALID_FRAME)) { 2264*991554f2SKenneth D. Merry sc->mapping_table[csio->ccb_h.target_id].TLR_bits = 2265*991554f2SKenneth D. Merry (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2266*991554f2SKenneth D. Merry } 2267*991554f2SKenneth D. Merry 2268*991554f2SKenneth D. Merry /* 2269*991554f2SKenneth D. Merry * Intentionally override the normal SCSI status reporting 2270*991554f2SKenneth D. Merry * for these two cases. These are likely to happen in a 2271*991554f2SKenneth D. Merry * multi-initiator environment, and we want to make sure that 2272*991554f2SKenneth D. Merry * CAM retries these commands rather than fail them. 2273*991554f2SKenneth D. Merry */ 2274*991554f2SKenneth D. Merry if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || 2275*991554f2SKenneth D. Merry (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { 2276*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2277*991554f2SKenneth D. Merry break; 2278*991554f2SKenneth D. Merry } 2279*991554f2SKenneth D. Merry 2280*991554f2SKenneth D. Merry /* Handle normal status and sense */ 2281*991554f2SKenneth D. Merry csio->scsi_status = rep->SCSIStatus; 2282*991554f2SKenneth D. Merry if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) 2283*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2284*991554f2SKenneth D. Merry else 2285*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 2286*991554f2SKenneth D. Merry 2287*991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2288*991554f2SKenneth D. Merry int sense_len, returned_sense_len; 2289*991554f2SKenneth D. Merry 2290*991554f2SKenneth D. Merry returned_sense_len = min(le32toh(rep->SenseCount), 2291*991554f2SKenneth D. Merry sizeof(struct scsi_sense_data)); 2292*991554f2SKenneth D. Merry if (returned_sense_len < csio->sense_len) 2293*991554f2SKenneth D. Merry csio->sense_resid = csio->sense_len - 2294*991554f2SKenneth D. Merry returned_sense_len; 2295*991554f2SKenneth D. Merry else 2296*991554f2SKenneth D. Merry csio->sense_resid = 0; 2297*991554f2SKenneth D. Merry 2298*991554f2SKenneth D. Merry sense_len = min(returned_sense_len, 2299*991554f2SKenneth D. Merry csio->sense_len - csio->sense_resid); 2300*991554f2SKenneth D. Merry bzero(&csio->sense_data, sizeof(csio->sense_data)); 2301*991554f2SKenneth D. Merry bcopy(cm->cm_sense, &csio->sense_data, sense_len); 2302*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 2303*991554f2SKenneth D. Merry } 2304*991554f2SKenneth D. Merry 2305*991554f2SKenneth D. Merry /* 2306*991554f2SKenneth D. Merry * Check if this is an INQUIRY command. If it's a VPD inquiry, 2307*991554f2SKenneth D. Merry * and it's page code 0 (Supported Page List), and there is 2308*991554f2SKenneth D. Merry * inquiry data, and this is for a sequential access device, and 2309*991554f2SKenneth D. Merry * the device is an SSP target, and TLR is supported by the 2310*991554f2SKenneth D. Merry * controller, turn the TLR_bits value ON if page 0x90 is 2311*991554f2SKenneth D. Merry * supported. 2312*991554f2SKenneth D. Merry */ 2313*991554f2SKenneth D. Merry if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && 2314*991554f2SKenneth D. Merry (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && 2315*991554f2SKenneth D. Merry (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && 2316*991554f2SKenneth D. Merry ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && 2317*991554f2SKenneth D. Merry (csio->data_ptr != NULL) && (((uint8_t *)cm->cm_data)[0] == 2318*991554f2SKenneth D. Merry T_SEQUENTIAL) && (sc->control_TLR) && 2319*991554f2SKenneth D. Merry (sc->mapping_table[csio->ccb_h.target_id].device_info & 2320*991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { 2321*991554f2SKenneth D. Merry vpd_list = (struct scsi_vpd_supported_page_list *) 2322*991554f2SKenneth D. Merry csio->data_ptr; 2323*991554f2SKenneth D. Merry TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. 2324*991554f2SKenneth D. Merry TLR_bits; 2325*991554f2SKenneth D. Merry *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2326*991554f2SKenneth D. Merry TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; 2327*991554f2SKenneth D. Merry alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + 2328*991554f2SKenneth D. Merry csio->cdb_io.cdb_bytes[4]; 2329*991554f2SKenneth D. Merry for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { 2330*991554f2SKenneth D. Merry if (vpd_list->list[i] == 0x90) { 2331*991554f2SKenneth D. Merry *TLR_bits = TLR_on; 2332*991554f2SKenneth D. Merry break; 2333*991554f2SKenneth D. Merry } 2334*991554f2SKenneth D. Merry } 2335*991554f2SKenneth D. Merry } 2336*991554f2SKenneth D. Merry break; 2337*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 2338*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 2339*991554f2SKenneth D. Merry /* 2340*991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't 2341*991554f2SKenneth D. Merry * tell CAM that the volume is not there. We want volumes to 2342*991554f2SKenneth D. Merry * be enumerated until they are deleted/removed, not just 2343*991554f2SKenneth D. Merry * failed. 2344*991554f2SKenneth D. Merry */ 2345*991554f2SKenneth D. Merry if (cm->cm_targ->devinfo == 0) 2346*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2347*991554f2SKenneth D. Merry else 2348*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2349*991554f2SKenneth D. Merry break; 2350*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_SGL: 2351*991554f2SKenneth D. Merry mpr_print_scsiio_cmd(sc, cm); 2352*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; 2353*991554f2SKenneth D. Merry break; 2354*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 2355*991554f2SKenneth D. Merry /* 2356*991554f2SKenneth D. Merry * This is one of the responses that comes back when an I/O 2357*991554f2SKenneth D. Merry * has been aborted. If it is because of a timeout that we 2358*991554f2SKenneth D. Merry * initiated, just set the status to CAM_CMD_TIMEOUT. 2359*991554f2SKenneth D. Merry * Otherwise set it to CAM_REQ_ABORTED. The effect on the 2360*991554f2SKenneth D. Merry * command is the same (it gets retried, subject to the 2361*991554f2SKenneth D. Merry * retry counter), the only difference is what gets printed 2362*991554f2SKenneth D. Merry * on the console. 2363*991554f2SKenneth D. Merry */ 2364*991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) 2365*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_CMD_TIMEOUT; 2366*991554f2SKenneth D. Merry else 2367*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2368*991554f2SKenneth D. Merry break; 2369*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 2370*991554f2SKenneth D. Merry /* resid is ignored for this condition */ 2371*991554f2SKenneth D. Merry csio->resid = 0; 2372*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DATA_RUN_ERR; 2373*991554f2SKenneth D. Merry break; 2374*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 2375*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 2376*991554f2SKenneth D. Merry /* 2377*991554f2SKenneth D. Merry * Since these are generally external (i.e. hopefully 2378*991554f2SKenneth D. Merry * transient transport-related) errors, retry these without 2379*991554f2SKenneth D. Merry * decrementing the retry count. 2380*991554f2SKenneth D. Merry */ 2381*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQUEUE_REQ; 2382*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_INFO, 2383*991554f2SKenneth D. Merry "terminated ioc %x scsi %x state %x xfer %u\n", 2384*991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2385*991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2386*991554f2SKenneth D. Merry break; 2387*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 2388*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INTERNAL_ERROR: 2389*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_VPID: 2390*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FIELD: 2391*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_STATE: 2392*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: 2393*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2394*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2395*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2396*991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2397*991554f2SKenneth D. Merry default: 2398*991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2399*991554f2SKenneth D. Merry "completed ioc %x scsi %x state %x xfer %u\n", 2400*991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2401*991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2402*991554f2SKenneth D. Merry csio->resid = cm->cm_length; 2403*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2404*991554f2SKenneth D. Merry break; 2405*991554f2SKenneth D. Merry } 2406*991554f2SKenneth D. Merry 2407*991554f2SKenneth D. Merry mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); 2408*991554f2SKenneth D. Merry 2409*991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2410*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2411*991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2412*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM " 2413*991554f2SKenneth D. Merry "queue\n"); 2414*991554f2SKenneth D. Merry } 2415*991554f2SKenneth D. Merry 2416*991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2417*991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2418*991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2419*991554f2SKenneth D. Merry } 2420*991554f2SKenneth D. Merry 2421*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2422*991554f2SKenneth D. Merry xpt_done(ccb); 2423*991554f2SKenneth D. Merry } 2424*991554f2SKenneth D. Merry 2425*991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 2426*991554f2SKenneth D. Merry static void 2427*991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2428*991554f2SKenneth D. Merry { 2429*991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REPLY *rpl; 2430*991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 2431*991554f2SKenneth D. Merry uint64_t sasaddr; 2432*991554f2SKenneth D. Merry union ccb *ccb; 2433*991554f2SKenneth D. Merry 2434*991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 2435*991554f2SKenneth D. Merry 2436*991554f2SKenneth D. Merry /* 2437*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 2438*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and SMP 2439*991554f2SKenneth D. Merry * commands require two S/G elements only. That should be handled 2440*991554f2SKenneth D. Merry * in the standard request size. 2441*991554f2SKenneth D. Merry */ 2442*991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2443*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n", 2444*991554f2SKenneth D. Merry __func__, cm->cm_flags); 2445*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2446*991554f2SKenneth D. Merry goto bailout; 2447*991554f2SKenneth D. Merry } 2448*991554f2SKenneth D. Merry 2449*991554f2SKenneth D. Merry rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; 2450*991554f2SKenneth D. Merry if (rpl == NULL) { 2451*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__); 2452*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2453*991554f2SKenneth D. Merry goto bailout; 2454*991554f2SKenneth D. Merry } 2455*991554f2SKenneth D. Merry 2456*991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2457*991554f2SKenneth D. Merry sasaddr = le32toh(req->SASAddress.Low); 2458*991554f2SKenneth D. Merry sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32; 2459*991554f2SKenneth D. Merry 2460*991554f2SKenneth D. Merry if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) != 2461*991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS || 2462*991554f2SKenneth D. Merry rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { 2463*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n", 2464*991554f2SKenneth D. Merry __func__, le16toh(rpl->IOCStatus), rpl->SASStatus); 2465*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2466*991554f2SKenneth D. Merry goto bailout; 2467*991554f2SKenneth D. Merry } 2468*991554f2SKenneth D. Merry 2469*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address " 2470*991554f2SKenneth D. Merry "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr); 2471*991554f2SKenneth D. Merry 2472*991554f2SKenneth D. Merry if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) 2473*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2474*991554f2SKenneth D. Merry else 2475*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SMP_STATUS_ERROR; 2476*991554f2SKenneth D. Merry 2477*991554f2SKenneth D. Merry bailout: 2478*991554f2SKenneth D. Merry /* 2479*991554f2SKenneth D. Merry * We sync in both directions because we had DMAs in the S/G list 2480*991554f2SKenneth D. Merry * in both directions. 2481*991554f2SKenneth D. Merry */ 2482*991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2483*991554f2SKenneth D. Merry BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2484*991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2485*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2486*991554f2SKenneth D. Merry xpt_done(ccb); 2487*991554f2SKenneth D. Merry } 2488*991554f2SKenneth D. Merry 2489*991554f2SKenneth D. Merry static void 2490*991554f2SKenneth D. Merry mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, 2491*991554f2SKenneth D. Merry uint64_t sasaddr) 2492*991554f2SKenneth D. Merry { 2493*991554f2SKenneth D. Merry struct mpr_command *cm; 2494*991554f2SKenneth D. Merry uint8_t *request, *response; 2495*991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 2496*991554f2SKenneth D. Merry struct mpr_softc *sc; 2497*991554f2SKenneth D. Merry struct sglist *sg; 2498*991554f2SKenneth D. Merry int error; 2499*991554f2SKenneth D. Merry 2500*991554f2SKenneth D. Merry sc = sassc->sc; 2501*991554f2SKenneth D. Merry sg = NULL; 2502*991554f2SKenneth D. Merry error = 0; 2503*991554f2SKenneth D. Merry 2504*991554f2SKenneth D. Merry #if __FreeBSD_version >= 1000029 2505*991554f2SKenneth D. Merry switch (ccb->ccb_h.flags & CAM_DATA_MASK) { 2506*991554f2SKenneth D. Merry case CAM_DATA_PADDR: 2507*991554f2SKenneth D. Merry case CAM_DATA_SG_PADDR: 2508*991554f2SKenneth D. Merry /* 2509*991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 2510*991554f2SKenneth D. Merry */ 2511*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " 2512*991554f2SKenneth D. Merry "supported\n", __func__); 2513*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2514*991554f2SKenneth D. Merry xpt_done(ccb); 2515*991554f2SKenneth D. Merry return; 2516*991554f2SKenneth D. Merry case CAM_DATA_SG: 2517*991554f2SKenneth D. Merry /* 2518*991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 2519*991554f2SKenneth D. Merry * request or response. 2520*991554f2SKenneth D. Merry */ 2521*991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 2522*991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 2523*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2524*991554f2SKenneth D. Merry "%s: multiple request or response buffer segments " 2525*991554f2SKenneth D. Merry "not supported for SMP\n", __func__); 2526*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2527*991554f2SKenneth D. Merry xpt_done(ccb); 2528*991554f2SKenneth D. Merry return; 2529*991554f2SKenneth D. Merry } 2530*991554f2SKenneth D. Merry 2531*991554f2SKenneth D. Merry /* 2532*991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 2533*991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 2534*991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 2535*991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 2536*991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 2537*991554f2SKenneth D. Merry * buffer. 2538*991554f2SKenneth D. Merry */ 2539*991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 2540*991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 2541*991554f2SKenneth D. Merry 2542*991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 2543*991554f2SKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; 2544*991554f2SKenneth D. Merry } else 2545*991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2546*991554f2SKenneth D. Merry 2547*991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 2548*991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 2549*991554f2SKenneth D. Merry 2550*991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 2551*991554f2SKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; 2552*991554f2SKenneth D. Merry } else 2553*991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2554*991554f2SKenneth D. Merry break; 2555*991554f2SKenneth D. Merry case CAM_DATA_VADDR: 2556*991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2557*991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2558*991554f2SKenneth D. Merry break; 2559*991554f2SKenneth D. Merry default: 2560*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2561*991554f2SKenneth D. Merry xpt_done(ccb); 2562*991554f2SKenneth D. Merry return; 2563*991554f2SKenneth D. Merry } 2564*991554f2SKenneth D. Merry #else //__FreeBSD_version < 1000029 2565*991554f2SKenneth D. Merry /* 2566*991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 2567*991554f2SKenneth D. Merry */ 2568*991554f2SKenneth D. Merry if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { 2569*991554f2SKenneth D. Merry mpr_printf(sc, "%s: physical addresses not supported\n", 2570*991554f2SKenneth D. Merry __func__); 2571*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2572*991554f2SKenneth D. Merry xpt_done(ccb); 2573*991554f2SKenneth D. Merry return; 2574*991554f2SKenneth D. Merry } 2575*991554f2SKenneth D. Merry 2576*991554f2SKenneth D. Merry /* 2577*991554f2SKenneth D. Merry * If the user wants to send an S/G list, check to make sure they 2578*991554f2SKenneth D. Merry * have single buffers. 2579*991554f2SKenneth D. Merry */ 2580*991554f2SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { 2581*991554f2SKenneth D. Merry /* 2582*991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 2583*991554f2SKenneth D. Merry * request or response. 2584*991554f2SKenneth D. Merry */ 2585*991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 2586*991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 2587*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " 2588*991554f2SKenneth D. Merry "response buffer segments not supported for SMP\n", 2589*991554f2SKenneth D. Merry __func__); 2590*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2591*991554f2SKenneth D. Merry xpt_done(ccb); 2592*991554f2SKenneth D. Merry return; 2593*991554f2SKenneth D. Merry } 2594*991554f2SKenneth D. Merry 2595*991554f2SKenneth D. Merry /* 2596*991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 2597*991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 2598*991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 2599*991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 2600*991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 2601*991554f2SKenneth D. Merry * buffer. 2602*991554f2SKenneth D. Merry */ 2603*991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 2604*991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 2605*991554f2SKenneth D. Merry 2606*991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 2607*991554f2SKenneth D. Merry request = (uint8_t *)req_sg[0].ds_addr; 2608*991554f2SKenneth D. Merry } else 2609*991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2610*991554f2SKenneth D. Merry 2611*991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 2612*991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 2613*991554f2SKenneth D. Merry 2614*991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 2615*991554f2SKenneth D. Merry response = (uint8_t *)rsp_sg[0].ds_addr; 2616*991554f2SKenneth D. Merry } else 2617*991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2618*991554f2SKenneth D. Merry } else { 2619*991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2620*991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2621*991554f2SKenneth D. Merry } 2622*991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 1000029 2623*991554f2SKenneth D. Merry 2624*991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 2625*991554f2SKenneth D. Merry if (cm == NULL) { 2626*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2627*991554f2SKenneth D. Merry "%s: cannot allocate command\n", __func__); 2628*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2629*991554f2SKenneth D. Merry xpt_done(ccb); 2630*991554f2SKenneth D. Merry return; 2631*991554f2SKenneth D. Merry } 2632*991554f2SKenneth D. Merry 2633*991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2634*991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 2635*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; 2636*991554f2SKenneth D. Merry 2637*991554f2SKenneth D. Merry /* Allow the chip to use any route to this SAS address. */ 2638*991554f2SKenneth D. Merry req->PhysicalPort = 0xff; 2639*991554f2SKenneth D. Merry 2640*991554f2SKenneth D. Merry req->RequestDataLength = htole16(ccb->smpio.smp_request_len); 2641*991554f2SKenneth D. Merry req->SGLFlags = 2642*991554f2SKenneth D. Merry MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI; 2643*991554f2SKenneth D. Merry 2644*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address " 2645*991554f2SKenneth D. Merry "%#jx\n", __func__, (uintmax_t)sasaddr); 2646*991554f2SKenneth D. Merry 2647*991554f2SKenneth D. Merry mpr_init_sge(cm, req, &req->SGL); 2648*991554f2SKenneth D. Merry 2649*991554f2SKenneth D. Merry /* 2650*991554f2SKenneth D. Merry * Set up a uio to pass into mpr_map_command(). This allows us to 2651*991554f2SKenneth D. Merry * do one map command, and one busdma call in there. 2652*991554f2SKenneth D. Merry */ 2653*991554f2SKenneth D. Merry cm->cm_uio.uio_iov = cm->cm_iovec; 2654*991554f2SKenneth D. Merry cm->cm_uio.uio_iovcnt = 2; 2655*991554f2SKenneth D. Merry cm->cm_uio.uio_segflg = UIO_SYSSPACE; 2656*991554f2SKenneth D. Merry 2657*991554f2SKenneth D. Merry /* 2658*991554f2SKenneth D. Merry * The read/write flag isn't used by busdma, but set it just in 2659*991554f2SKenneth D. Merry * case. This isn't exactly accurate, either, since we're going in 2660*991554f2SKenneth D. Merry * both directions. 2661*991554f2SKenneth D. Merry */ 2662*991554f2SKenneth D. Merry cm->cm_uio.uio_rw = UIO_WRITE; 2663*991554f2SKenneth D. Merry 2664*991554f2SKenneth D. Merry cm->cm_iovec[0].iov_base = request; 2665*991554f2SKenneth D. Merry cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength); 2666*991554f2SKenneth D. Merry cm->cm_iovec[1].iov_base = response; 2667*991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len; 2668*991554f2SKenneth D. Merry 2669*991554f2SKenneth D. Merry cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len + 2670*991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len; 2671*991554f2SKenneth D. Merry 2672*991554f2SKenneth D. Merry /* 2673*991554f2SKenneth D. Merry * Trigger a warning message in mpr_data_cb() for the user if we 2674*991554f2SKenneth D. Merry * wind up exceeding two S/G segments. The chip expects one 2675*991554f2SKenneth D. Merry * segment for the request and another for the response. 2676*991554f2SKenneth D. Merry */ 2677*991554f2SKenneth D. Merry cm->cm_max_segs = 2; 2678*991554f2SKenneth D. Merry 2679*991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2680*991554f2SKenneth D. Merry cm->cm_complete = mprsas_smpio_complete; 2681*991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 2682*991554f2SKenneth D. Merry 2683*991554f2SKenneth D. Merry /* 2684*991554f2SKenneth D. Merry * Tell the mapping code that we're using a uio, and that this is 2685*991554f2SKenneth D. Merry * an SMP passthrough request. There is a little special-case 2686*991554f2SKenneth D. Merry * logic there (in mpr_data_cb()) to handle the bidirectional 2687*991554f2SKenneth D. Merry * transfer. 2688*991554f2SKenneth D. Merry */ 2689*991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS | 2690*991554f2SKenneth D. Merry MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT; 2691*991554f2SKenneth D. Merry 2692*991554f2SKenneth D. Merry /* The chip data format is little endian. */ 2693*991554f2SKenneth D. Merry req->SASAddress.High = htole32(sasaddr >> 32); 2694*991554f2SKenneth D. Merry req->SASAddress.Low = htole32(sasaddr); 2695*991554f2SKenneth D. Merry 2696*991554f2SKenneth D. Merry /* 2697*991554f2SKenneth D. Merry * XXX Note that we don't have a timeout/abort mechanism here. 2698*991554f2SKenneth D. Merry * From the manual, it looks like task management requests only 2699*991554f2SKenneth D. Merry * work for SCSI IO and SATA passthrough requests. We may need to 2700*991554f2SKenneth D. Merry * have a mechanism to retry requests in the event of a chip reset 2701*991554f2SKenneth D. Merry * at least. Hopefully the chip will insure that any errors short 2702*991554f2SKenneth D. Merry * of that are relayed back to the driver. 2703*991554f2SKenneth D. Merry */ 2704*991554f2SKenneth D. Merry error = mpr_map_command(sc, cm); 2705*991554f2SKenneth D. Merry if ((error != 0) && (error != EINPROGRESS)) { 2706*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from " 2707*991554f2SKenneth D. Merry "mpr_map_command()\n", __func__, error); 2708*991554f2SKenneth D. Merry goto bailout_error; 2709*991554f2SKenneth D. Merry } 2710*991554f2SKenneth D. Merry 2711*991554f2SKenneth D. Merry return; 2712*991554f2SKenneth D. Merry 2713*991554f2SKenneth D. Merry bailout_error: 2714*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2715*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2716*991554f2SKenneth D. Merry xpt_done(ccb); 2717*991554f2SKenneth D. Merry return; 2718*991554f2SKenneth D. Merry } 2719*991554f2SKenneth D. Merry 2720*991554f2SKenneth D. Merry static void 2721*991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) 2722*991554f2SKenneth D. Merry { 2723*991554f2SKenneth D. Merry struct mpr_softc *sc; 2724*991554f2SKenneth D. Merry struct mprsas_target *targ; 2725*991554f2SKenneth D. Merry uint64_t sasaddr = 0; 2726*991554f2SKenneth D. Merry 2727*991554f2SKenneth D. Merry sc = sassc->sc; 2728*991554f2SKenneth D. Merry 2729*991554f2SKenneth D. Merry /* 2730*991554f2SKenneth D. Merry * Make sure the target exists. 2731*991554f2SKenneth D. Merry */ 2732*991554f2SKenneth D. Merry KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, 2733*991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id)); 2734*991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 2735*991554f2SKenneth D. Merry if (targ->handle == 0x0) { 2736*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n", 2737*991554f2SKenneth D. Merry __func__, ccb->ccb_h.target_id); 2738*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2739*991554f2SKenneth D. Merry xpt_done(ccb); 2740*991554f2SKenneth D. Merry return; 2741*991554f2SKenneth D. Merry } 2742*991554f2SKenneth D. Merry 2743*991554f2SKenneth D. Merry /* 2744*991554f2SKenneth D. Merry * If this device has an embedded SMP target, we'll talk to it 2745*991554f2SKenneth D. Merry * directly. 2746*991554f2SKenneth D. Merry * figure out what the expander's address is. 2747*991554f2SKenneth D. Merry */ 2748*991554f2SKenneth D. Merry if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0) 2749*991554f2SKenneth D. Merry sasaddr = targ->sasaddr; 2750*991554f2SKenneth D. Merry 2751*991554f2SKenneth D. Merry /* 2752*991554f2SKenneth D. Merry * If we don't have a SAS address for the expander yet, try 2753*991554f2SKenneth D. Merry * grabbing it from the page 0x83 information cached in the 2754*991554f2SKenneth D. Merry * transport layer for this target. LSI expanders report the 2755*991554f2SKenneth D. Merry * expander SAS address as the port-associated SAS address in 2756*991554f2SKenneth D. Merry * Inquiry VPD page 0x83. Maxim expanders don't report it in page 2757*991554f2SKenneth D. Merry * 0x83. 2758*991554f2SKenneth D. Merry * 2759*991554f2SKenneth D. Merry * XXX KDM disable this for now, but leave it commented out so that 2760*991554f2SKenneth D. Merry * it is obvious that this is another possible way to get the SAS 2761*991554f2SKenneth D. Merry * address. 2762*991554f2SKenneth D. Merry * 2763*991554f2SKenneth D. Merry * The parent handle method below is a little more reliable, and 2764*991554f2SKenneth D. Merry * the other benefit is that it works for devices other than SES 2765*991554f2SKenneth D. Merry * devices. So you can send a SMP request to a da(4) device and it 2766*991554f2SKenneth D. Merry * will get routed to the expander that device is attached to. 2767*991554f2SKenneth D. Merry * (Assuming the da(4) device doesn't contain an SMP target...) 2768*991554f2SKenneth D. Merry */ 2769*991554f2SKenneth D. Merry #if 0 2770*991554f2SKenneth D. Merry if (sasaddr == 0) 2771*991554f2SKenneth D. Merry sasaddr = xpt_path_sas_addr(ccb->ccb_h.path); 2772*991554f2SKenneth D. Merry #endif 2773*991554f2SKenneth D. Merry 2774*991554f2SKenneth D. Merry /* 2775*991554f2SKenneth D. Merry * If we still don't have a SAS address for the expander, look for 2776*991554f2SKenneth D. Merry * the parent device of this device, which is probably the expander. 2777*991554f2SKenneth D. Merry */ 2778*991554f2SKenneth D. Merry if (sasaddr == 0) { 2779*991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 2780*991554f2SKenneth D. Merry struct mprsas_target *parent_target; 2781*991554f2SKenneth D. Merry #endif 2782*991554f2SKenneth D. Merry 2783*991554f2SKenneth D. Merry if (targ->parent_handle == 0x0) { 2784*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 2785*991554f2SKenneth D. Merry "a valid parent handle!\n", __func__, targ->handle); 2786*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2787*991554f2SKenneth D. Merry goto bailout; 2788*991554f2SKenneth D. Merry } 2789*991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 2790*991554f2SKenneth D. Merry parent_target = mprsas_find_target_by_handle(sassc, 0, 2791*991554f2SKenneth D. Merry targ->parent_handle); 2792*991554f2SKenneth D. Merry 2793*991554f2SKenneth D. Merry if (parent_target == NULL) { 2794*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 2795*991554f2SKenneth D. Merry "a valid parent target!\n", __func__, targ->handle); 2796*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2797*991554f2SKenneth D. Merry goto bailout; 2798*991554f2SKenneth D. Merry } 2799*991554f2SKenneth D. Merry 2800*991554f2SKenneth D. Merry if ((parent_target->devinfo & 2801*991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2802*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 2803*991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 2804*991554f2SKenneth D. Merry targ->handle, parent_target->handle); 2805*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2806*991554f2SKenneth D. Merry goto bailout; 2807*991554f2SKenneth D. Merry 2808*991554f2SKenneth D. Merry } 2809*991554f2SKenneth D. Merry 2810*991554f2SKenneth D. Merry sasaddr = parent_target->sasaddr; 2811*991554f2SKenneth D. Merry #else /* OLD_MPR_PROBE */ 2812*991554f2SKenneth D. Merry if ((targ->parent_devinfo & 2813*991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2814*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 2815*991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 2816*991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 2817*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2818*991554f2SKenneth D. Merry goto bailout; 2819*991554f2SKenneth D. Merry 2820*991554f2SKenneth D. Merry } 2821*991554f2SKenneth D. Merry if (targ->parent_sasaddr == 0x0) { 2822*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle " 2823*991554f2SKenneth D. Merry "%d does not have a valid SAS address!\n", __func__, 2824*991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 2825*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2826*991554f2SKenneth D. Merry goto bailout; 2827*991554f2SKenneth D. Merry } 2828*991554f2SKenneth D. Merry 2829*991554f2SKenneth D. Merry sasaddr = targ->parent_sasaddr; 2830*991554f2SKenneth D. Merry #endif /* OLD_MPR_PROBE */ 2831*991554f2SKenneth D. Merry 2832*991554f2SKenneth D. Merry } 2833*991554f2SKenneth D. Merry 2834*991554f2SKenneth D. Merry if (sasaddr == 0) { 2835*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for " 2836*991554f2SKenneth D. Merry "handle %d\n", __func__, targ->handle); 2837*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2838*991554f2SKenneth D. Merry goto bailout; 2839*991554f2SKenneth D. Merry } 2840*991554f2SKenneth D. Merry mprsas_send_smpcmd(sassc, ccb, sasaddr); 2841*991554f2SKenneth D. Merry 2842*991554f2SKenneth D. Merry return; 2843*991554f2SKenneth D. Merry 2844*991554f2SKenneth D. Merry bailout: 2845*991554f2SKenneth D. Merry xpt_done(ccb); 2846*991554f2SKenneth D. Merry 2847*991554f2SKenneth D. Merry } 2848*991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 900026 2849*991554f2SKenneth D. Merry 2850*991554f2SKenneth D. Merry static void 2851*991554f2SKenneth D. Merry mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) 2852*991554f2SKenneth D. Merry { 2853*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2854*991554f2SKenneth D. Merry struct mpr_softc *sc; 2855*991554f2SKenneth D. Merry struct mpr_command *tm; 2856*991554f2SKenneth D. Merry struct mprsas_target *targ; 2857*991554f2SKenneth D. Merry 2858*991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 2859*991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 2860*991554f2SKenneth D. Merry 2861*991554f2SKenneth D. Merry KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, 2862*991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_RESET_DEV\n", 2863*991554f2SKenneth D. Merry ccb->ccb_h.target_id)); 2864*991554f2SKenneth D. Merry sc = sassc->sc; 2865*991554f2SKenneth D. Merry tm = mpr_alloc_command(sc); 2866*991554f2SKenneth D. Merry if (tm == NULL) { 2867*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2868*991554f2SKenneth D. Merry "command alloc failure in mprsas_action_resetdev\n"); 2869*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2870*991554f2SKenneth D. Merry xpt_done(ccb); 2871*991554f2SKenneth D. Merry return; 2872*991554f2SKenneth D. Merry } 2873*991554f2SKenneth D. Merry 2874*991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 2875*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2876*991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 2877*991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 2878*991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 2879*991554f2SKenneth D. Merry 2880*991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 2881*991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 2882*991554f2SKenneth D. Merry 2883*991554f2SKenneth D. Merry tm->cm_data = NULL; 2884*991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 2885*991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 2886*991554f2SKenneth D. Merry tm->cm_complete = mprsas_resetdev_complete; 2887*991554f2SKenneth D. Merry tm->cm_complete_data = ccb; 2888*991554f2SKenneth D. Merry tm->cm_targ = targ; 2889*991554f2SKenneth D. Merry mpr_map_command(sc, tm); 2890*991554f2SKenneth D. Merry } 2891*991554f2SKenneth D. Merry 2892*991554f2SKenneth D. Merry static void 2893*991554f2SKenneth D. Merry mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) 2894*991554f2SKenneth D. Merry { 2895*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *resp; 2896*991554f2SKenneth D. Merry union ccb *ccb; 2897*991554f2SKenneth D. Merry 2898*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 2899*991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 2900*991554f2SKenneth D. Merry 2901*991554f2SKenneth D. Merry resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 2902*991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 2903*991554f2SKenneth D. Merry 2904*991554f2SKenneth D. Merry /* 2905*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 2906*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 2907*991554f2SKenneth D. Merry * task management commands don't have S/G lists. 2908*991554f2SKenneth D. Merry */ 2909*991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2910*991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2911*991554f2SKenneth D. Merry 2912*991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2913*991554f2SKenneth D. Merry 2914*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of " 2915*991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 2916*991554f2SKenneth D. Merry tm->cm_flags, req->DevHandle); 2917*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2918*991554f2SKenneth D. Merry goto bailout; 2919*991554f2SKenneth D. Merry } 2920*991554f2SKenneth D. Merry 2921*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 2922*991554f2SKenneth D. Merry "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__, 2923*991554f2SKenneth D. Merry le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); 2924*991554f2SKenneth D. Merry 2925*991554f2SKenneth D. Merry if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { 2926*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2927*991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 2928*991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 2929*991554f2SKenneth D. Merry } 2930*991554f2SKenneth D. Merry else 2931*991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2932*991554f2SKenneth D. Merry 2933*991554f2SKenneth D. Merry bailout: 2934*991554f2SKenneth D. Merry 2935*991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 2936*991554f2SKenneth D. Merry xpt_done(ccb); 2937*991554f2SKenneth D. Merry } 2938*991554f2SKenneth D. Merry 2939*991554f2SKenneth D. Merry static void 2940*991554f2SKenneth D. Merry mprsas_poll(struct cam_sim *sim) 2941*991554f2SKenneth D. Merry { 2942*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2943*991554f2SKenneth D. Merry 2944*991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 2945*991554f2SKenneth D. Merry 2946*991554f2SKenneth D. Merry if (sassc->sc->mpr_debug & MPR_TRACE) { 2947*991554f2SKenneth D. Merry /* frequent debug messages during a panic just slow 2948*991554f2SKenneth D. Merry * everything down too much. 2949*991554f2SKenneth D. Merry */ 2950*991554f2SKenneth D. Merry mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__); 2951*991554f2SKenneth D. Merry sassc->sc->mpr_debug &= ~MPR_TRACE; 2952*991554f2SKenneth D. Merry } 2953*991554f2SKenneth D. Merry 2954*991554f2SKenneth D. Merry mpr_intr_locked(sassc->sc); 2955*991554f2SKenneth D. Merry } 2956*991554f2SKenneth D. Merry 2957*991554f2SKenneth D. Merry static void 2958*991554f2SKenneth D. Merry mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, 2959*991554f2SKenneth D. Merry void *arg) 2960*991554f2SKenneth D. Merry { 2961*991554f2SKenneth D. Merry struct mpr_softc *sc; 2962*991554f2SKenneth D. Merry 2963*991554f2SKenneth D. Merry sc = (struct mpr_softc *)callback_arg; 2964*991554f2SKenneth D. Merry 2965*991554f2SKenneth D. Merry switch (code) { 2966*991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 2967*991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 2968*991554f2SKenneth D. Merry case AC_ADVINFO_CHANGED: { 2969*991554f2SKenneth D. Merry struct mprsas_target *target; 2970*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2971*991554f2SKenneth D. Merry struct scsi_read_capacity_data_long rcap_buf; 2972*991554f2SKenneth D. Merry struct ccb_dev_advinfo cdai; 2973*991554f2SKenneth D. Merry struct mprsas_lun *lun; 2974*991554f2SKenneth D. Merry lun_id_t lunid; 2975*991554f2SKenneth D. Merry int found_lun; 2976*991554f2SKenneth D. Merry uintptr_t buftype; 2977*991554f2SKenneth D. Merry 2978*991554f2SKenneth D. Merry buftype = (uintptr_t)arg; 2979*991554f2SKenneth D. Merry 2980*991554f2SKenneth D. Merry found_lun = 0; 2981*991554f2SKenneth D. Merry sassc = sc->sassc; 2982*991554f2SKenneth D. Merry 2983*991554f2SKenneth D. Merry /* 2984*991554f2SKenneth D. Merry * We're only interested in read capacity data changes. 2985*991554f2SKenneth D. Merry */ 2986*991554f2SKenneth D. Merry if (buftype != CDAI_TYPE_RCAPLONG) 2987*991554f2SKenneth D. Merry break; 2988*991554f2SKenneth D. Merry 2989*991554f2SKenneth D. Merry /* 2990*991554f2SKenneth D. Merry * We should have a handle for this, but check to make sure. 2991*991554f2SKenneth D. Merry */ 2992*991554f2SKenneth D. Merry KASSERT(xpt_path_target_id(path) < sassc->maxtargets, 2993*991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_async\n", 2994*991554f2SKenneth D. Merry xpt_path_target_id(path))); 2995*991554f2SKenneth D. Merry target = &sassc->targets[xpt_path_target_id(path)]; 2996*991554f2SKenneth D. Merry if (target->handle == 0) 2997*991554f2SKenneth D. Merry break; 2998*991554f2SKenneth D. Merry 2999*991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3000*991554f2SKenneth D. Merry 3001*991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3002*991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3003*991554f2SKenneth D. Merry found_lun = 1; 3004*991554f2SKenneth D. Merry break; 3005*991554f2SKenneth D. Merry } 3006*991554f2SKenneth D. Merry } 3007*991554f2SKenneth D. Merry 3008*991554f2SKenneth D. Merry if (found_lun == 0) { 3009*991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3010*991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3011*991554f2SKenneth D. Merry if (lun == NULL) { 3012*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc " 3013*991554f2SKenneth D. Merry "LUN for EEDP support.\n"); 3014*991554f2SKenneth D. Merry break; 3015*991554f2SKenneth D. Merry } 3016*991554f2SKenneth D. Merry lun->lun_id = lunid; 3017*991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3018*991554f2SKenneth D. Merry } 3019*991554f2SKenneth D. Merry 3020*991554f2SKenneth D. Merry bzero(&rcap_buf, sizeof(rcap_buf)); 3021*991554f2SKenneth D. Merry xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 3022*991554f2SKenneth D. Merry cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 3023*991554f2SKenneth D. Merry cdai.ccb_h.flags = CAM_DIR_IN; 3024*991554f2SKenneth D. Merry cdai.buftype = CDAI_TYPE_RCAPLONG; 3025*991554f2SKenneth D. Merry cdai.flags = 0; 3026*991554f2SKenneth D. Merry cdai.bufsiz = sizeof(rcap_buf); 3027*991554f2SKenneth D. Merry cdai.buf = (uint8_t *)&rcap_buf; 3028*991554f2SKenneth D. Merry xpt_action((union ccb *)&cdai); 3029*991554f2SKenneth D. Merry if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 3030*991554f2SKenneth D. Merry cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 3031*991554f2SKenneth D. Merry 3032*991554f2SKenneth D. Merry if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 3033*991554f2SKenneth D. Merry && (rcap_buf.prot & SRC16_PROT_EN)) { 3034*991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3035*991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf.length); 3036*991554f2SKenneth D. Merry } else { 3037*991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3038*991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3039*991554f2SKenneth D. Merry } 3040*991554f2SKenneth D. Merry break; 3041*991554f2SKenneth D. Merry } 3042*991554f2SKenneth D. Merry #endif 3043*991554f2SKenneth D. Merry case AC_FOUND_DEVICE: { 3044*991554f2SKenneth D. Merry struct ccb_getdev *cgd; 3045*991554f2SKenneth D. Merry 3046*991554f2SKenneth D. Merry cgd = arg; 3047*991554f2SKenneth D. Merry mprsas_prepare_ssu(sc, path, cgd); 3048*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3049*991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3050*991554f2SKenneth D. Merry mprsas_check_eedp(sc, path, cgd); 3051*991554f2SKenneth D. Merry #endif 3052*991554f2SKenneth D. Merry break; 3053*991554f2SKenneth D. Merry } 3054*991554f2SKenneth D. Merry default: 3055*991554f2SKenneth D. Merry break; 3056*991554f2SKenneth D. Merry } 3057*991554f2SKenneth D. Merry } 3058*991554f2SKenneth D. Merry 3059*991554f2SKenneth D. Merry static void 3060*991554f2SKenneth D. Merry mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, 3061*991554f2SKenneth D. Merry struct ccb_getdev *cgd) 3062*991554f2SKenneth D. Merry { 3063*991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 3064*991554f2SKenneth D. Merry path_id_t pathid; 3065*991554f2SKenneth D. Merry target_id_t targetid; 3066*991554f2SKenneth D. Merry lun_id_t lunid; 3067*991554f2SKenneth D. Merry struct mprsas_target *target; 3068*991554f2SKenneth D. Merry struct mprsas_lun *lun; 3069*991554f2SKenneth D. Merry uint8_t found_lun; 3070*991554f2SKenneth D. Merry 3071*991554f2SKenneth D. Merry sassc = sc->sassc; 3072*991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 3073*991554f2SKenneth D. Merry targetid = xpt_path_target_id(path); 3074*991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3075*991554f2SKenneth D. Merry 3076*991554f2SKenneth D. Merry KASSERT(targetid < sassc->maxtargets, 3077*991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid)); 3078*991554f2SKenneth D. Merry target = &sassc->targets[targetid]; 3079*991554f2SKenneth D. Merry if (target->handle == 0x0) 3080*991554f2SKenneth D. Merry return; 3081*991554f2SKenneth D. Merry 3082*991554f2SKenneth D. Merry /* 3083*991554f2SKenneth D. Merry * If LUN is already in list, don't create a new one. 3084*991554f2SKenneth D. Merry */ 3085*991554f2SKenneth D. Merry found_lun = FALSE; 3086*991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3087*991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3088*991554f2SKenneth D. Merry found_lun = TRUE; 3089*991554f2SKenneth D. Merry break; 3090*991554f2SKenneth D. Merry } 3091*991554f2SKenneth D. Merry } 3092*991554f2SKenneth D. Merry if (!found_lun) { 3093*991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3094*991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3095*991554f2SKenneth D. Merry if (lun == NULL) { 3096*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " 3097*991554f2SKenneth D. Merry "preparing SSU.\n"); 3098*991554f2SKenneth D. Merry return; 3099*991554f2SKenneth D. Merry } 3100*991554f2SKenneth D. Merry lun->lun_id = lunid; 3101*991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3102*991554f2SKenneth D. Merry } 3103*991554f2SKenneth D. Merry 3104*991554f2SKenneth D. Merry /* 3105*991554f2SKenneth D. Merry * If this is a SATA direct-access end device, mark it so that a SCSI 3106*991554f2SKenneth D. Merry * StartStopUnit command will be sent to it when the driver is being 3107*991554f2SKenneth D. Merry * shutdown. 3108*991554f2SKenneth D. Merry */ 3109*991554f2SKenneth D. Merry if (((cgd->inq_data.device & 0x1F) == T_DIRECT) && 3110*991554f2SKenneth D. Merry (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && 3111*991554f2SKenneth D. Merry ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == 3112*991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_END_DEVICE)) { 3113*991554f2SKenneth D. Merry lun->stop_at_shutdown = TRUE; 3114*991554f2SKenneth D. Merry } 3115*991554f2SKenneth D. Merry } 3116*991554f2SKenneth D. Merry 3117*991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3118*991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3119*991554f2SKenneth D. Merry static void 3120*991554f2SKenneth D. Merry mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 3121*991554f2SKenneth D. Merry struct ccb_getdev *cgd) 3122*991554f2SKenneth D. Merry { 3123*991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 3124*991554f2SKenneth D. Merry struct ccb_scsiio *csio; 3125*991554f2SKenneth D. Merry struct scsi_read_capacity_16 *scsi_cmd; 3126*991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3127*991554f2SKenneth D. Merry path_id_t pathid; 3128*991554f2SKenneth D. Merry target_id_t targetid; 3129*991554f2SKenneth D. Merry lun_id_t lunid; 3130*991554f2SKenneth D. Merry union ccb *ccb; 3131*991554f2SKenneth D. Merry struct cam_path *local_path; 3132*991554f2SKenneth D. Merry struct mprsas_target *target; 3133*991554f2SKenneth D. Merry struct mprsas_lun *lun; 3134*991554f2SKenneth D. Merry uint8_t found_lun; 3135*991554f2SKenneth D. Merry char path_str[64]; 3136*991554f2SKenneth D. Merry 3137*991554f2SKenneth D. Merry sassc = sc->sassc; 3138*991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 3139*991554f2SKenneth D. Merry targetid = xpt_path_target_id(path); 3140*991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3141*991554f2SKenneth D. Merry 3142*991554f2SKenneth D. Merry KASSERT(targetid < sassc->maxtargets, 3143*991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_check_eedp\n", targetid)); 3144*991554f2SKenneth D. Merry target = &sassc->targets[targetid]; 3145*991554f2SKenneth D. Merry if (target->handle == 0x0) 3146*991554f2SKenneth D. Merry return; 3147*991554f2SKenneth D. Merry 3148*991554f2SKenneth D. Merry /* 3149*991554f2SKenneth D. Merry * Determine if the device is EEDP capable. 3150*991554f2SKenneth D. Merry * 3151*991554f2SKenneth D. Merry * If this flag is set in the inquiry data, the device supports 3152*991554f2SKenneth D. Merry * protection information, and must support the 16 byte read capacity 3153*991554f2SKenneth D. Merry * command, otherwise continue without sending read cap 16 3154*991554f2SKenneth D. Merry */ 3155*991554f2SKenneth D. Merry if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0) 3156*991554f2SKenneth D. Merry return; 3157*991554f2SKenneth D. Merry 3158*991554f2SKenneth D. Merry /* 3159*991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command. This info is used to determine if 3160*991554f2SKenneth D. Merry * the LUN is formatted for EEDP support. 3161*991554f2SKenneth D. Merry */ 3162*991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 3163*991554f2SKenneth D. Merry if (ccb == NULL) { 3164*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP " 3165*991554f2SKenneth D. Merry "support.\n"); 3166*991554f2SKenneth D. Merry return; 3167*991554f2SKenneth D. Merry } 3168*991554f2SKenneth D. Merry 3169*991554f2SKenneth D. Merry if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid) 3170*991554f2SKenneth D. Merry != CAM_REQ_CMP) { 3171*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP " 3172*991554f2SKenneth D. Merry "support\n"); 3173*991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3174*991554f2SKenneth D. Merry return; 3175*991554f2SKenneth D. Merry } 3176*991554f2SKenneth D. Merry 3177*991554f2SKenneth D. Merry /* 3178*991554f2SKenneth D. Merry * If LUN is already in list, don't create a new one. 3179*991554f2SKenneth D. Merry */ 3180*991554f2SKenneth D. Merry found_lun = FALSE; 3181*991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3182*991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3183*991554f2SKenneth D. Merry found_lun = TRUE; 3184*991554f2SKenneth D. Merry break; 3185*991554f2SKenneth D. Merry } 3186*991554f2SKenneth D. Merry } 3187*991554f2SKenneth D. Merry if (!found_lun) { 3188*991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3189*991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3190*991554f2SKenneth D. Merry if (lun == NULL) { 3191*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " 3192*991554f2SKenneth D. Merry "EEDP support.\n"); 3193*991554f2SKenneth D. Merry xpt_free_path(local_path); 3194*991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3195*991554f2SKenneth D. Merry return; 3196*991554f2SKenneth D. Merry } 3197*991554f2SKenneth D. Merry lun->lun_id = lunid; 3198*991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3199*991554f2SKenneth D. Merry } 3200*991554f2SKenneth D. Merry 3201*991554f2SKenneth D. Merry xpt_path_string(local_path, path_str, sizeof(path_str)); 3202*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n", 3203*991554f2SKenneth D. Merry path_str, target->handle); 3204*991554f2SKenneth D. Merry 3205*991554f2SKenneth D. Merry /* 3206*991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command for the LUN. The 3207*991554f2SKenneth D. Merry * mprsas_read_cap_done function will load the read cap info into the 3208*991554f2SKenneth D. Merry * LUN struct. 3209*991554f2SKenneth D. Merry */ 3210*991554f2SKenneth D. Merry rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR, 3211*991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3212*991554f2SKenneth D. Merry if (rcap_buf == NULL) { 3213*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity " 3214*991554f2SKenneth D. Merry "buffer for EEDP support.\n"); 3215*991554f2SKenneth D. Merry xpt_free_path(ccb->ccb_h.path); 3216*991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3217*991554f2SKenneth D. Merry return; 3218*991554f2SKenneth D. Merry } 3219*991554f2SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT); 3220*991554f2SKenneth D. Merry csio = &ccb->csio; 3221*991554f2SKenneth D. Merry csio->ccb_h.func_code = XPT_SCSI_IO; 3222*991554f2SKenneth D. Merry csio->ccb_h.flags = CAM_DIR_IN; 3223*991554f2SKenneth D. Merry csio->ccb_h.retry_count = 4; 3224*991554f2SKenneth D. Merry csio->ccb_h.cbfcnp = mprsas_read_cap_done; 3225*991554f2SKenneth D. Merry csio->ccb_h.timeout = 60000; 3226*991554f2SKenneth D. Merry csio->data_ptr = (uint8_t *)rcap_buf; 3227*991554f2SKenneth D. Merry csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp); 3228*991554f2SKenneth D. Merry csio->sense_len = MPR_SENSE_LEN; 3229*991554f2SKenneth D. Merry csio->cdb_len = sizeof(*scsi_cmd); 3230*991554f2SKenneth D. Merry csio->tag_action = MSG_SIMPLE_Q_TAG; 3231*991554f2SKenneth D. Merry 3232*991554f2SKenneth D. Merry scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; 3233*991554f2SKenneth D. Merry bzero(scsi_cmd, sizeof(*scsi_cmd)); 3234*991554f2SKenneth D. Merry scsi_cmd->opcode = 0x9E; 3235*991554f2SKenneth D. Merry scsi_cmd->service_action = SRC16_SERVICE_ACTION; 3236*991554f2SKenneth D. Merry ((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp); 3237*991554f2SKenneth D. Merry 3238*991554f2SKenneth D. Merry ccb->ccb_h.ppriv_ptr1 = sassc; 3239*991554f2SKenneth D. Merry xpt_action(ccb); 3240*991554f2SKenneth D. Merry } 3241*991554f2SKenneth D. Merry 3242*991554f2SKenneth D. Merry static void 3243*991554f2SKenneth D. Merry mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) 3244*991554f2SKenneth D. Merry { 3245*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3246*991554f2SKenneth D. Merry struct mprsas_target *target; 3247*991554f2SKenneth D. Merry struct mprsas_lun *lun; 3248*991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3249*991554f2SKenneth D. Merry 3250*991554f2SKenneth D. Merry if (done_ccb == NULL) 3251*991554f2SKenneth D. Merry return; 3252*991554f2SKenneth D. Merry 3253*991554f2SKenneth D. Merry /* Driver need to release devq, it Scsi command is 3254*991554f2SKenneth D. Merry * generated by driver internally. 3255*991554f2SKenneth D. Merry * Currently there is a single place where driver 3256*991554f2SKenneth D. Merry * calls scsi command internally. In future if driver 3257*991554f2SKenneth D. Merry * calls more scsi command internally, it needs to release 3258*991554f2SKenneth D. Merry * devq internally, since those command will not go back to 3259*991554f2SKenneth D. Merry * cam_periph. 3260*991554f2SKenneth D. Merry */ 3261*991554f2SKenneth D. Merry if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) { 3262*991554f2SKenneth D. Merry done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 3263*991554f2SKenneth D. Merry xpt_release_devq(done_ccb->ccb_h.path, 3264*991554f2SKenneth D. Merry /*count*/ 1, /*run_queue*/TRUE); 3265*991554f2SKenneth D. Merry } 3266*991554f2SKenneth D. Merry 3267*991554f2SKenneth D. Merry rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; 3268*991554f2SKenneth D. Merry 3269*991554f2SKenneth D. Merry /* 3270*991554f2SKenneth D. Merry * Get the LUN ID for the path and look it up in the LUN list for the 3271*991554f2SKenneth D. Merry * target. 3272*991554f2SKenneth D. Merry */ 3273*991554f2SKenneth D. Merry sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1; 3274*991554f2SKenneth D. Merry KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets, 3275*991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_read_cap_done\n", 3276*991554f2SKenneth D. Merry done_ccb->ccb_h.target_id)); 3277*991554f2SKenneth D. Merry target = &sassc->targets[done_ccb->ccb_h.target_id]; 3278*991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3279*991554f2SKenneth D. Merry if (lun->lun_id != done_ccb->ccb_h.target_lun) 3280*991554f2SKenneth D. Merry continue; 3281*991554f2SKenneth D. Merry 3282*991554f2SKenneth D. Merry /* 3283*991554f2SKenneth D. Merry * Got the LUN in the target's LUN list. Fill it in with EEDP 3284*991554f2SKenneth D. Merry * info. If the READ CAP 16 command had some SCSI error (common 3285*991554f2SKenneth D. Merry * if command is not supported), mark the lun as not supporting 3286*991554f2SKenneth D. Merry * EEDP and set the block size to 0. 3287*991554f2SKenneth D. Merry */ 3288*991554f2SKenneth D. Merry if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 3289*991554f2SKenneth D. Merry || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { 3290*991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3291*991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3292*991554f2SKenneth D. Merry break; 3293*991554f2SKenneth D. Merry } 3294*991554f2SKenneth D. Merry 3295*991554f2SKenneth D. Merry if (rcap_buf->protect & 0x01) { 3296*991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for " 3297*991554f2SKenneth D. Merry "target ID %d is formatted for EEDP " 3298*991554f2SKenneth D. Merry "support.\n", done_ccb->ccb_h.target_lun, 3299*991554f2SKenneth D. Merry done_ccb->ccb_h.target_id); 3300*991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3301*991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf->length); 3302*991554f2SKenneth D. Merry } 3303*991554f2SKenneth D. Merry break; 3304*991554f2SKenneth D. Merry } 3305*991554f2SKenneth D. Merry 3306*991554f2SKenneth D. Merry // Finished with this CCB and path. 3307*991554f2SKenneth D. Merry free(rcap_buf, M_MPR); 3308*991554f2SKenneth D. Merry xpt_free_path(done_ccb->ccb_h.path); 3309*991554f2SKenneth D. Merry xpt_free_ccb(done_ccb); 3310*991554f2SKenneth D. Merry } 3311*991554f2SKenneth D. Merry #endif /* (__FreeBSD_version < 901503) || \ 3312*991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */ 3313*991554f2SKenneth D. Merry 3314*991554f2SKenneth D. Merry int 3315*991554f2SKenneth D. Merry mprsas_startup(struct mpr_softc *sc) 3316*991554f2SKenneth D. Merry { 3317*991554f2SKenneth D. Merry /* 3318*991554f2SKenneth D. Merry * Send the port enable message and set the wait_for_port_enable flag. 3319*991554f2SKenneth D. Merry * This flag helps to keep the simq frozen until all discovery events 3320*991554f2SKenneth D. Merry * are processed. 3321*991554f2SKenneth D. Merry */ 3322*991554f2SKenneth D. Merry sc->wait_for_port_enable = 1; 3323*991554f2SKenneth D. Merry mprsas_send_portenable(sc); 3324*991554f2SKenneth D. Merry return (0); 3325*991554f2SKenneth D. Merry } 3326*991554f2SKenneth D. Merry 3327*991554f2SKenneth D. Merry static int 3328*991554f2SKenneth D. Merry mprsas_send_portenable(struct mpr_softc *sc) 3329*991554f2SKenneth D. Merry { 3330*991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REQUEST *request; 3331*991554f2SKenneth D. Merry struct mpr_command *cm; 3332*991554f2SKenneth D. Merry 3333*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3334*991554f2SKenneth D. Merry 3335*991554f2SKenneth D. Merry if ((cm = mpr_alloc_command(sc)) == NULL) 3336*991554f2SKenneth D. Merry return (EBUSY); 3337*991554f2SKenneth D. Merry request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; 3338*991554f2SKenneth D. Merry request->Function = MPI2_FUNCTION_PORT_ENABLE; 3339*991554f2SKenneth D. Merry request->MsgFlags = 0; 3340*991554f2SKenneth D. Merry request->VP_ID = 0; 3341*991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 3342*991554f2SKenneth D. Merry cm->cm_complete = mprsas_portenable_complete; 3343*991554f2SKenneth D. Merry cm->cm_data = NULL; 3344*991554f2SKenneth D. Merry cm->cm_sge = NULL; 3345*991554f2SKenneth D. Merry 3346*991554f2SKenneth D. Merry mpr_map_command(sc, cm); 3347*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 3348*991554f2SKenneth D. Merry "mpr_send_portenable finished cm %p req %p complete %p\n", 3349*991554f2SKenneth D. Merry cm, cm->cm_req, cm->cm_complete); 3350*991554f2SKenneth D. Merry return (0); 3351*991554f2SKenneth D. Merry } 3352*991554f2SKenneth D. Merry 3353*991554f2SKenneth D. Merry static void 3354*991554f2SKenneth D. Merry mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm) 3355*991554f2SKenneth D. Merry { 3356*991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REPLY *reply; 3357*991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3358*991554f2SKenneth D. Merry 3359*991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3360*991554f2SKenneth D. Merry sassc = sc->sassc; 3361*991554f2SKenneth D. Merry 3362*991554f2SKenneth D. Merry /* 3363*991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 3364*991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 3365*991554f2SKenneth D. Merry * port enable commands don't have S/G lists. 3366*991554f2SKenneth D. Merry */ 3367*991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 3368*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! " 3369*991554f2SKenneth D. Merry "This should not happen!\n", __func__, cm->cm_flags); 3370*991554f2SKenneth D. Merry } 3371*991554f2SKenneth D. Merry 3372*991554f2SKenneth D. Merry reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; 3373*991554f2SKenneth D. Merry if (reply == NULL) 3374*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n"); 3375*991554f2SKenneth D. Merry else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) != 3376*991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS) 3377*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable failed\n"); 3378*991554f2SKenneth D. Merry 3379*991554f2SKenneth D. Merry mpr_free_command(sc, cm); 3380*991554f2SKenneth D. Merry if (sc->mpr_ich.ich_arg != NULL) { 3381*991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n"); 3382*991554f2SKenneth D. Merry config_intrhook_disestablish(&sc->mpr_ich); 3383*991554f2SKenneth D. Merry sc->mpr_ich.ich_arg = NULL; 3384*991554f2SKenneth D. Merry } 3385*991554f2SKenneth D. Merry 3386*991554f2SKenneth D. Merry /* 3387*991554f2SKenneth D. Merry * Done waiting for port enable to complete. Decrement the refcount. 3388*991554f2SKenneth D. Merry * If refcount is 0, discovery is complete and a rescan of the bus can 3389*991554f2SKenneth D. Merry * take place. 3390*991554f2SKenneth D. Merry */ 3391*991554f2SKenneth D. Merry sc->wait_for_port_enable = 0; 3392*991554f2SKenneth D. Merry sc->port_enable_complete = 1; 3393*991554f2SKenneth D. Merry wakeup(&sc->port_enable_complete); 3394*991554f2SKenneth D. Merry mprsas_startup_decrement(sassc); 3395*991554f2SKenneth D. Merry } 3396*991554f2SKenneth D. Merry 3397*991554f2SKenneth D. Merry int 3398*991554f2SKenneth D. Merry mprsas_check_id(struct mprsas_softc *sassc, int id) 3399*991554f2SKenneth D. Merry { 3400*991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 3401*991554f2SKenneth D. Merry char *ids; 3402*991554f2SKenneth D. Merry char *name; 3403*991554f2SKenneth D. Merry 3404*991554f2SKenneth D. Merry ids = &sc->exclude_ids[0]; 3405*991554f2SKenneth D. Merry while((name = strsep(&ids, ",")) != NULL) { 3406*991554f2SKenneth D. Merry if (name[0] == '\0') 3407*991554f2SKenneth D. Merry continue; 3408*991554f2SKenneth D. Merry if (strtol(name, NULL, 0) == (long)id) 3409*991554f2SKenneth D. Merry return (1); 3410*991554f2SKenneth D. Merry } 3411*991554f2SKenneth D. Merry 3412*991554f2SKenneth D. Merry return (0); 3413*991554f2SKenneth D. Merry } 3414