1991554f2SKenneth D. Merry /*- 2991554f2SKenneth D. Merry * Copyright (c) 2009 Yahoo! Inc. 3991554f2SKenneth D. Merry * Copyright (c) 2011-2014 LSI Corp. 4991554f2SKenneth D. Merry * All rights reserved. 5991554f2SKenneth D. Merry * 6991554f2SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 7991554f2SKenneth D. Merry * modification, are permitted provided that the following conditions 8991554f2SKenneth D. Merry * are met: 9991554f2SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 10991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer. 11991554f2SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright 12991554f2SKenneth D. Merry * notice, this list of conditions and the following disclaimer in the 13991554f2SKenneth D. Merry * documentation and/or other materials provided with the distribution. 14991554f2SKenneth D. Merry * 15991554f2SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16991554f2SKenneth D. Merry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17991554f2SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18991554f2SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19991554f2SKenneth D. Merry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20991554f2SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21991554f2SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22991554f2SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23991554f2SKenneth D. Merry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24991554f2SKenneth D. Merry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25991554f2SKenneth D. Merry * SUCH DAMAGE. 26991554f2SKenneth D. Merry */ 27991554f2SKenneth D. Merry 28991554f2SKenneth D. Merry #include <sys/cdefs.h> 29991554f2SKenneth D. Merry __FBSDID("$FreeBSD$"); 30991554f2SKenneth D. Merry 31991554f2SKenneth D. Merry /* Communications core for LSI MPT2 */ 32991554f2SKenneth D. Merry 33991554f2SKenneth D. Merry /* TODO Move headers to mprvar */ 34991554f2SKenneth D. Merry #include <sys/types.h> 35991554f2SKenneth D. Merry #include <sys/param.h> 36991554f2SKenneth D. Merry #include <sys/systm.h> 37991554f2SKenneth D. Merry #include <sys/kernel.h> 38991554f2SKenneth D. Merry #include <sys/selinfo.h> 39991554f2SKenneth D. Merry #include <sys/module.h> 40991554f2SKenneth D. Merry #include <sys/bus.h> 41991554f2SKenneth D. Merry #include <sys/conf.h> 42991554f2SKenneth D. Merry #include <sys/bio.h> 43991554f2SKenneth D. Merry #include <sys/malloc.h> 44991554f2SKenneth D. Merry #include <sys/uio.h> 45991554f2SKenneth D. Merry #include <sys/sysctl.h> 46991554f2SKenneth D. Merry #include <sys/endian.h> 47991554f2SKenneth D. Merry #include <sys/queue.h> 48991554f2SKenneth D. Merry #include <sys/kthread.h> 49991554f2SKenneth D. Merry #include <sys/taskqueue.h> 50991554f2SKenneth D. Merry #include <sys/sbuf.h> 51991554f2SKenneth D. Merry 52991554f2SKenneth D. Merry #include <machine/bus.h> 53991554f2SKenneth D. Merry #include <machine/resource.h> 54991554f2SKenneth D. Merry #include <sys/rman.h> 55991554f2SKenneth D. Merry 56991554f2SKenneth D. Merry #include <machine/stdarg.h> 57991554f2SKenneth D. Merry 58991554f2SKenneth D. Merry #include <cam/cam.h> 59991554f2SKenneth D. Merry #include <cam/cam_ccb.h> 60991554f2SKenneth D. Merry #include <cam/cam_debug.h> 61991554f2SKenneth D. Merry #include <cam/cam_sim.h> 62991554f2SKenneth D. Merry #include <cam/cam_xpt_sim.h> 63991554f2SKenneth D. Merry #include <cam/cam_xpt_periph.h> 64991554f2SKenneth D. Merry #include <cam/cam_periph.h> 65991554f2SKenneth D. Merry #include <cam/scsi/scsi_all.h> 66991554f2SKenneth D. Merry #include <cam/scsi/scsi_message.h> 67991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 68991554f2SKenneth D. Merry #include <cam/scsi/smp_all.h> 69991554f2SKenneth D. Merry #endif 70991554f2SKenneth D. Merry 71991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_type.h> 72991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2.h> 73991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_ioc.h> 74991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_sas.h> 75991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_cnfg.h> 76991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_init.h> 77991554f2SKenneth D. Merry #include <dev/mpr/mpi/mpi2_tool.h> 78991554f2SKenneth D. Merry #include <dev/mpr/mpr_ioctl.h> 79991554f2SKenneth D. Merry #include <dev/mpr/mprvar.h> 80991554f2SKenneth D. Merry #include <dev/mpr/mpr_table.h> 81991554f2SKenneth D. Merry #include <dev/mpr/mpr_sas.h> 82991554f2SKenneth D. Merry 83991554f2SKenneth D. Merry #define MPRSAS_DISCOVERY_TIMEOUT 20 84991554f2SKenneth D. Merry #define MPRSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */ 85991554f2SKenneth D. Merry 86991554f2SKenneth D. Merry /* 87991554f2SKenneth D. Merry * static array to check SCSI OpCode for EEDP protection bits 88991554f2SKenneth D. Merry */ 89991554f2SKenneth D. Merry #define PRO_R MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP 90991554f2SKenneth D. Merry #define PRO_W MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 91991554f2SKenneth D. Merry #define PRO_V MPI2_SCSIIO_EEDPFLAGS_INSERT_OP 92991554f2SKenneth D. Merry static uint8_t op_code_prot[256] = { 93991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 96991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97991554f2SKenneth D. Merry 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 102991554f2SKenneth D. Merry 0, 0, 0, PRO_W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, PRO_R, 0, PRO_W, 0, 0, 0, PRO_W, PRO_V, 104991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108991554f2SKenneth D. Merry 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 109991554f2SKenneth D. Merry }; 110991554f2SKenneth D. Merry 111991554f2SKenneth D. Merry MALLOC_DEFINE(M_MPRSAS, "MPRSAS", "MPR SAS memory"); 112991554f2SKenneth D. Merry 113991554f2SKenneth D. Merry static void mprsas_remove_device(struct mpr_softc *, struct mpr_command *); 114991554f2SKenneth D. Merry static void mprsas_remove_complete(struct mpr_softc *, struct mpr_command *); 115991554f2SKenneth D. Merry static void mprsas_action(struct cam_sim *sim, union ccb *ccb); 116991554f2SKenneth D. Merry static void mprsas_poll(struct cam_sim *sim); 117991554f2SKenneth D. Merry static void mprsas_scsiio_timeout(void *data); 118991554f2SKenneth D. Merry static void mprsas_abort_complete(struct mpr_softc *sc, 119991554f2SKenneth D. Merry struct mpr_command *cm); 120991554f2SKenneth D. Merry static void mprsas_action_scsiio(struct mprsas_softc *, union ccb *); 121991554f2SKenneth D. Merry static void mprsas_scsiio_complete(struct mpr_softc *, struct mpr_command *); 122991554f2SKenneth D. Merry static void mprsas_action_resetdev(struct mprsas_softc *, union ccb *); 123991554f2SKenneth D. Merry static void mprsas_resetdev_complete(struct mpr_softc *, 124991554f2SKenneth D. Merry struct mpr_command *); 125991554f2SKenneth D. Merry static int mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 126991554f2SKenneth D. Merry struct mpr_command *cm); 127991554f2SKenneth D. Merry static int mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, 128991554f2SKenneth D. Merry uint8_t type); 129991554f2SKenneth D. Merry static void mprsas_async(void *callback_arg, uint32_t code, 130991554f2SKenneth D. Merry struct cam_path *path, void *arg); 131991554f2SKenneth D. Merry static void mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, 132991554f2SKenneth D. Merry struct ccb_getdev *cgd); 133991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 134991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 135991554f2SKenneth D. Merry static void mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 136991554f2SKenneth D. Merry struct ccb_getdev *cgd); 137991554f2SKenneth D. Merry static void mprsas_read_cap_done(struct cam_periph *periph, 138991554f2SKenneth D. Merry union ccb *done_ccb); 139991554f2SKenneth D. Merry #endif 140991554f2SKenneth D. Merry static int mprsas_send_portenable(struct mpr_softc *sc); 141991554f2SKenneth D. Merry static void mprsas_portenable_complete(struct mpr_softc *sc, 142991554f2SKenneth D. Merry struct mpr_command *cm); 143991554f2SKenneth D. Merry 144991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 145991554f2SKenneth D. Merry static void 146991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm); 147991554f2SKenneth D. Merry static void mprsas_send_smpcmd(struct mprsas_softc *sassc, 148991554f2SKenneth D. Merry union ccb *ccb, uint64_t sasaddr); 149991554f2SKenneth D. Merry static void 150991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb); 151991554f2SKenneth D. Merry #endif 152991554f2SKenneth D. Merry 153991554f2SKenneth D. Merry struct mprsas_target * 154991554f2SKenneth D. Merry mprsas_find_target_by_handle(struct mprsas_softc *sassc, int start, 155991554f2SKenneth D. Merry uint16_t handle) 156991554f2SKenneth D. Merry { 157991554f2SKenneth D. Merry struct mprsas_target *target; 158991554f2SKenneth D. Merry int i; 159991554f2SKenneth D. Merry 160991554f2SKenneth D. Merry for (i = start; i < sassc->maxtargets; i++) { 161991554f2SKenneth D. Merry target = &sassc->targets[i]; 162991554f2SKenneth D. Merry if (target->handle == handle) 163991554f2SKenneth D. Merry return (target); 164991554f2SKenneth D. Merry } 165991554f2SKenneth D. Merry 166991554f2SKenneth D. Merry return (NULL); 167991554f2SKenneth D. Merry } 168991554f2SKenneth D. Merry 169991554f2SKenneth D. Merry /* we need to freeze the simq during attach and diag reset, to avoid failing 170991554f2SKenneth D. Merry * commands before device handles have been found by discovery. Since 171991554f2SKenneth D. Merry * discovery involves reading config pages and possibly sending commands, 172991554f2SKenneth D. Merry * discovery actions may continue even after we receive the end of discovery 173991554f2SKenneth D. Merry * event, so refcount discovery actions instead of assuming we can unfreeze 174991554f2SKenneth D. Merry * the simq when we get the event. 175991554f2SKenneth D. Merry */ 176991554f2SKenneth D. Merry void 177991554f2SKenneth D. Merry mprsas_startup_increment(struct mprsas_softc *sassc) 178991554f2SKenneth D. Merry { 179991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 180991554f2SKenneth D. Merry 181991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 182991554f2SKenneth D. Merry if (sassc->startup_refcount++ == 0) { 183991554f2SKenneth D. Merry /* just starting, freeze the simq */ 184991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 185991554f2SKenneth D. Merry "%s freezing simq\n", __func__); 186a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 187a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 188991554f2SKenneth D. Merry xpt_hold_boot(); 189991554f2SKenneth D. Merry #endif 190991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 191991554f2SKenneth D. Merry } 192991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 193991554f2SKenneth D. Merry sassc->startup_refcount); 194991554f2SKenneth D. Merry } 195991554f2SKenneth D. Merry } 196991554f2SKenneth D. Merry 197991554f2SKenneth D. Merry void 198991554f2SKenneth D. Merry mprsas_release_simq_reinit(struct mprsas_softc *sassc) 199991554f2SKenneth D. Merry { 200991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 201991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 202991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 203991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INFO, "Unfreezing SIM queue\n"); 204991554f2SKenneth D. Merry } 205991554f2SKenneth D. Merry } 206991554f2SKenneth D. Merry 207991554f2SKenneth D. Merry void 208991554f2SKenneth D. Merry mprsas_startup_decrement(struct mprsas_softc *sassc) 209991554f2SKenneth D. Merry { 210991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 211991554f2SKenneth D. Merry 212991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_IN_STARTUP) != 0) { 213991554f2SKenneth D. Merry if (--sassc->startup_refcount == 0) { 214991554f2SKenneth D. Merry /* finished all discovery-related actions, release 215991554f2SKenneth D. Merry * the simq and rescan for the latest topology. 216991554f2SKenneth D. Merry */ 217991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, 218991554f2SKenneth D. Merry "%s releasing simq\n", __func__); 219991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_IN_STARTUP; 220991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 221a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 222a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 223991554f2SKenneth D. Merry xpt_release_boot(); 224991554f2SKenneth D. Merry #else 225991554f2SKenneth D. Merry mprsas_rescan_target(sassc->sc, NULL); 226991554f2SKenneth D. Merry #endif 227991554f2SKenneth D. Merry } 228991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INIT, "%s refcount %u\n", __func__, 229991554f2SKenneth D. Merry sassc->startup_refcount); 230991554f2SKenneth D. Merry } 231991554f2SKenneth D. Merry } 232991554f2SKenneth D. Merry 233991554f2SKenneth D. Merry /* LSI's firmware requires us to stop sending commands when we're doing task 234991554f2SKenneth D. Merry * management, so refcount the TMs and keep the simq frozen when any are in 235991554f2SKenneth D. Merry * use. 236991554f2SKenneth D. Merry */ 237991554f2SKenneth D. Merry struct mpr_command * 238991554f2SKenneth D. Merry mprsas_alloc_tm(struct mpr_softc *sc) 239991554f2SKenneth D. Merry { 240991554f2SKenneth D. Merry struct mpr_command *tm; 241991554f2SKenneth D. Merry 242991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 243991554f2SKenneth D. Merry tm = mpr_alloc_high_priority_command(sc); 244991554f2SKenneth D. Merry if (tm != NULL) { 245991554f2SKenneth D. Merry if (sc->sassc->tm_count++ == 0) { 246991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, 247991554f2SKenneth D. Merry "%s freezing simq\n", __func__); 248991554f2SKenneth D. Merry xpt_freeze_simq(sc->sassc->sim, 1); 249991554f2SKenneth D. Merry } 250991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, 251991554f2SKenneth D. Merry sc->sassc->tm_count); 252991554f2SKenneth D. Merry } 253991554f2SKenneth D. Merry return tm; 254991554f2SKenneth D. Merry } 255991554f2SKenneth D. Merry 256991554f2SKenneth D. Merry void 257991554f2SKenneth D. Merry mprsas_free_tm(struct mpr_softc *sc, struct mpr_command *tm) 258991554f2SKenneth D. Merry { 259991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s", __func__); 260991554f2SKenneth D. Merry if (tm == NULL) 261991554f2SKenneth D. Merry return; 262991554f2SKenneth D. Merry 263991554f2SKenneth D. Merry /* if there are no TMs in use, we can release the simq. We use our 264991554f2SKenneth D. Merry * own refcount so that it's easier for a diag reset to cleanup and 265991554f2SKenneth D. Merry * release the simq. 266991554f2SKenneth D. Merry */ 267991554f2SKenneth D. Merry if (--sc->sassc->tm_count == 0) { 268991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s releasing simq\n", __func__); 269991554f2SKenneth D. Merry xpt_release_simq(sc->sassc->sim, 1); 270991554f2SKenneth D. Merry } 271991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "%s tm_count %u\n", __func__, 272991554f2SKenneth D. Merry sc->sassc->tm_count); 273991554f2SKenneth D. Merry 274991554f2SKenneth D. Merry mpr_free_high_priority_command(sc, tm); 275991554f2SKenneth D. Merry } 276991554f2SKenneth D. Merry 277991554f2SKenneth D. Merry void 278991554f2SKenneth D. Merry mprsas_rescan_target(struct mpr_softc *sc, struct mprsas_target *targ) 279991554f2SKenneth D. Merry { 280991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 281991554f2SKenneth D. Merry path_id_t pathid; 282991554f2SKenneth D. Merry target_id_t targetid; 283991554f2SKenneth D. Merry union ccb *ccb; 284991554f2SKenneth D. Merry 285991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 286991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 287991554f2SKenneth D. Merry if (targ == NULL) 288991554f2SKenneth D. Merry targetid = CAM_TARGET_WILDCARD; 289991554f2SKenneth D. Merry else 290991554f2SKenneth D. Merry targetid = targ - sassc->targets; 291991554f2SKenneth D. Merry 292991554f2SKenneth D. Merry /* 293991554f2SKenneth D. Merry * Allocate a CCB and schedule a rescan. 294991554f2SKenneth D. Merry */ 295991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 296991554f2SKenneth D. Merry if (ccb == NULL) { 297991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to alloc CCB for rescan\n"); 298991554f2SKenneth D. Merry return; 299991554f2SKenneth D. Merry } 300991554f2SKenneth D. Merry 301991554f2SKenneth D. Merry if (xpt_create_path(&ccb->ccb_h.path, NULL, pathid, 302991554f2SKenneth D. Merry targetid, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 303991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for rescan\n"); 304991554f2SKenneth D. Merry xpt_free_ccb(ccb); 305991554f2SKenneth D. Merry return; 306991554f2SKenneth D. Merry } 307991554f2SKenneth D. Merry 308991554f2SKenneth D. Merry if (targetid == CAM_TARGET_WILDCARD) 309991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_BUS; 310991554f2SKenneth D. Merry else 311991554f2SKenneth D. Merry ccb->ccb_h.func_code = XPT_SCAN_TGT; 312991554f2SKenneth D. Merry 313991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s targetid %u\n", __func__, targetid); 314991554f2SKenneth D. Merry xpt_rescan(ccb); 315991554f2SKenneth D. Merry } 316991554f2SKenneth D. Merry 317991554f2SKenneth D. Merry static void 318991554f2SKenneth D. Merry mprsas_log_command(struct mpr_command *cm, u_int level, const char *fmt, ...) 319991554f2SKenneth D. Merry { 320991554f2SKenneth D. Merry struct sbuf sb; 321991554f2SKenneth D. Merry va_list ap; 322991554f2SKenneth D. Merry char str[192]; 323991554f2SKenneth D. Merry char path_str[64]; 324991554f2SKenneth D. Merry 325991554f2SKenneth D. Merry if (cm == NULL) 326991554f2SKenneth D. Merry return; 327991554f2SKenneth D. Merry 328991554f2SKenneth D. Merry /* No need to be in here if debugging isn't enabled */ 329991554f2SKenneth D. Merry if ((cm->cm_sc->mpr_debug & level) == 0) 330991554f2SKenneth D. Merry return; 331991554f2SKenneth D. Merry 332991554f2SKenneth D. Merry sbuf_new(&sb, str, sizeof(str), 0); 333991554f2SKenneth D. Merry 334991554f2SKenneth D. Merry va_start(ap, fmt); 335991554f2SKenneth D. Merry 336991554f2SKenneth D. Merry if (cm->cm_ccb != NULL) { 337991554f2SKenneth D. Merry xpt_path_string(cm->cm_ccb->csio.ccb_h.path, path_str, 338991554f2SKenneth D. Merry sizeof(path_str)); 339991554f2SKenneth D. Merry sbuf_cat(&sb, path_str); 340991554f2SKenneth D. Merry if (cm->cm_ccb->ccb_h.func_code == XPT_SCSI_IO) { 341991554f2SKenneth D. Merry scsi_command_string(&cm->cm_ccb->csio, &sb); 342991554f2SKenneth D. Merry sbuf_printf(&sb, "length %d ", 343991554f2SKenneth D. Merry cm->cm_ccb->csio.dxfer_len); 344991554f2SKenneth D. Merry } 345991554f2SKenneth D. Merry } else { 346991554f2SKenneth D. Merry sbuf_printf(&sb, "(noperiph:%s%d:%u:%u:%u): ", 347991554f2SKenneth D. Merry cam_sim_name(cm->cm_sc->sassc->sim), 348991554f2SKenneth D. Merry cam_sim_unit(cm->cm_sc->sassc->sim), 349991554f2SKenneth D. Merry cam_sim_bus(cm->cm_sc->sassc->sim), 350991554f2SKenneth D. Merry cm->cm_targ ? cm->cm_targ->tid : 0xFFFFFFFF, 351991554f2SKenneth D. Merry cm->cm_lun); 352991554f2SKenneth D. Merry } 353991554f2SKenneth D. Merry 354991554f2SKenneth D. Merry sbuf_printf(&sb, "SMID %u ", cm->cm_desc.Default.SMID); 355991554f2SKenneth D. Merry sbuf_vprintf(&sb, fmt, ap); 356991554f2SKenneth D. Merry sbuf_finish(&sb); 357991554f2SKenneth D. Merry mpr_dprint_field(cm->cm_sc, level, "%s", sbuf_data(&sb)); 358991554f2SKenneth D. Merry 359991554f2SKenneth D. Merry va_end(ap); 360991554f2SKenneth D. Merry } 361991554f2SKenneth D. Merry 362991554f2SKenneth D. Merry static void 363991554f2SKenneth D. Merry mprsas_remove_volume(struct mpr_softc *sc, struct mpr_command *tm) 364991554f2SKenneth D. Merry { 365991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 366991554f2SKenneth D. Merry struct mprsas_target *targ; 367991554f2SKenneth D. Merry uint16_t handle; 368991554f2SKenneth D. Merry 369991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 370991554f2SKenneth D. Merry 371991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 372991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 373991554f2SKenneth D. Merry targ = tm->cm_targ; 374991554f2SKenneth D. Merry 375991554f2SKenneth D. Merry if (reply == NULL) { 376991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 377991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 378991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 379991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 380991554f2SKenneth D. Merry return; 381991554f2SKenneth D. Merry } 382991554f2SKenneth D. Merry 383991554f2SKenneth D. Merry if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) { 384991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " 385991554f2SKenneth D. Merry "device 0x%x\n", reply->IOCStatus, handle); 386991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 387991554f2SKenneth D. Merry return; 388991554f2SKenneth D. Merry } 389991554f2SKenneth D. Merry 390991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 391991554f2SKenneth D. Merry reply->TerminationCount); 392991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 393991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 394991554f2SKenneth D. Merry 395991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", 396991554f2SKenneth D. Merry targ->tid, handle); 397991554f2SKenneth D. Merry 398991554f2SKenneth D. Merry /* 399991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 400991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 401991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 402991554f2SKenneth D. Merry * to this device if it comes back in the future. 403991554f2SKenneth D. Merry */ 404991554f2SKenneth D. Merry if (reply->IOCStatus == MPI2_IOCSTATUS_SUCCESS) { 405991554f2SKenneth D. Merry targ = tm->cm_targ; 406991554f2SKenneth D. Merry targ->handle = 0x0; 407991554f2SKenneth D. Merry targ->encl_handle = 0x0; 408991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 409991554f2SKenneth D. Merry targ->encl_level = 0x0; 410991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 411991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 412991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 413991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 414991554f2SKenneth D. Merry targ->encl_slot = 0x0; 415991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 416991554f2SKenneth D. Merry targ->phy_num = 0x0; 417991554f2SKenneth D. Merry targ->linkrate = 0x0; 418991554f2SKenneth D. Merry targ->devinfo = 0x0; 419991554f2SKenneth D. Merry targ->flags = 0x0; 420991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 421991554f2SKenneth D. Merry } 422991554f2SKenneth D. Merry 423991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 424991554f2SKenneth D. Merry } 425991554f2SKenneth D. Merry 426991554f2SKenneth D. Merry 427991554f2SKenneth D. Merry /* 428991554f2SKenneth D. Merry * No Need to call "MPI2_SAS_OP_REMOVE_DEVICE" For Volume removal. 429991554f2SKenneth D. Merry * Otherwise Volume Delete is same as Bare Drive Removal. 430991554f2SKenneth D. Merry */ 431991554f2SKenneth D. Merry void 432991554f2SKenneth D. Merry mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) 433991554f2SKenneth D. Merry { 434991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 435991554f2SKenneth D. Merry struct mpr_softc *sc; 436991554f2SKenneth D. Merry struct mpr_command *cm; 437991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 438991554f2SKenneth D. Merry 439991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 440991554f2SKenneth D. Merry sc = sassc->sc; 441991554f2SKenneth D. Merry 442991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 443991554f2SKenneth D. Merry if (targ == NULL) { 444991554f2SKenneth D. Merry /* FIXME: what is the action? */ 445991554f2SKenneth D. Merry /* We don't know about this device? */ 446991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 447991554f2SKenneth D. Merry "%s %d : invalid handle 0x%x \n", __func__,__LINE__, handle); 448991554f2SKenneth D. Merry return; 449991554f2SKenneth D. Merry } 450991554f2SKenneth D. Merry 451991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 452991554f2SKenneth D. Merry 453991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 454991554f2SKenneth D. Merry if (cm == NULL) { 455991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 456991554f2SKenneth D. Merry "%s: command alloc failure\n", __func__); 457991554f2SKenneth D. Merry return; 458991554f2SKenneth D. Merry } 459991554f2SKenneth D. Merry 460991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 461991554f2SKenneth D. Merry 462991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 463991554f2SKenneth D. Merry req->DevHandle = targ->handle; 464991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 465991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 466991554f2SKenneth D. Merry 467991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 468991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 469991554f2SKenneth D. Merry 470991554f2SKenneth D. Merry cm->cm_targ = targ; 471991554f2SKenneth D. Merry cm->cm_data = NULL; 472991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 473991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 474991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_volume; 475991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 476991554f2SKenneth D. Merry mpr_map_command(sc, cm); 477991554f2SKenneth D. Merry } 478991554f2SKenneth D. Merry 479991554f2SKenneth D. Merry /* 480991554f2SKenneth D. Merry * The MPT2 firmware performs debounce on the link to avoid transient link 481991554f2SKenneth D. Merry * errors and false removals. When it does decide that link has been lost 482991554f2SKenneth D. Merry * and a device needs to go away, it expects that the host will perform a 483991554f2SKenneth D. Merry * target reset and then an op remove. The reset has the side-effect of 484991554f2SKenneth D. Merry * aborting any outstanding requests for the device, which is required for 485991554f2SKenneth D. Merry * the op-remove to succeed. It's not clear if the host should check for 486991554f2SKenneth D. Merry * the device coming back alive after the reset. 487991554f2SKenneth D. Merry */ 488991554f2SKenneth D. Merry void 489991554f2SKenneth D. Merry mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) 490991554f2SKenneth D. Merry { 491991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 492991554f2SKenneth D. Merry struct mpr_softc *sc; 493991554f2SKenneth D. Merry struct mpr_command *cm; 494991554f2SKenneth D. Merry struct mprsas_target *targ = NULL; 495991554f2SKenneth D. Merry 496991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 497991554f2SKenneth D. Merry 498991554f2SKenneth D. Merry sc = sassc->sc; 499991554f2SKenneth D. Merry 500991554f2SKenneth D. Merry targ = mprsas_find_target_by_handle(sassc, 0, handle); 501991554f2SKenneth D. Merry if (targ == NULL) { 502991554f2SKenneth D. Merry /* FIXME: what is the action? */ 503991554f2SKenneth D. Merry /* We don't know about this device? */ 504991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s : invalid handle 0x%x \n", 505991554f2SKenneth D. Merry __func__, handle); 506991554f2SKenneth D. Merry return; 507991554f2SKenneth D. Merry } 508991554f2SKenneth D. Merry 509991554f2SKenneth D. Merry targ->flags |= MPRSAS_TARGET_INREMOVAL; 510991554f2SKenneth D. Merry 511991554f2SKenneth D. Merry cm = mprsas_alloc_tm(sc); 512991554f2SKenneth D. Merry if (cm == NULL) { 513991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: command alloc failure\n", 514991554f2SKenneth D. Merry __func__); 515991554f2SKenneth D. Merry return; 516991554f2SKenneth D. Merry } 517991554f2SKenneth D. Merry 518991554f2SKenneth D. Merry mprsas_rescan_target(sc, targ); 519991554f2SKenneth D. Merry 520991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req; 521991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 522991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 523991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 524991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 525991554f2SKenneth D. Merry 526991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 527991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 528991554f2SKenneth D. Merry 529991554f2SKenneth D. Merry cm->cm_targ = targ; 530991554f2SKenneth D. Merry cm->cm_data = NULL; 531991554f2SKenneth D. Merry cm->cm_desc.HighPriority.RequestFlags = 532991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 533991554f2SKenneth D. Merry cm->cm_complete = mprsas_remove_device; 534991554f2SKenneth D. Merry cm->cm_complete_data = (void *)(uintptr_t)handle; 535991554f2SKenneth D. Merry mpr_map_command(sc, cm); 536991554f2SKenneth D. Merry } 537991554f2SKenneth D. Merry 538991554f2SKenneth D. Merry static void 539991554f2SKenneth D. Merry mprsas_remove_device(struct mpr_softc *sc, struct mpr_command *tm) 540991554f2SKenneth D. Merry { 541991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 542991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REQUEST *req; 543991554f2SKenneth D. Merry struct mprsas_target *targ; 544991554f2SKenneth D. Merry struct mpr_command *next_cm; 545991554f2SKenneth D. Merry uint16_t handle; 546991554f2SKenneth D. Merry 547991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 548991554f2SKenneth D. Merry 549991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 550991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 551991554f2SKenneth D. Merry targ = tm->cm_targ; 552991554f2SKenneth D. Merry 553991554f2SKenneth D. Merry /* 554991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 555991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 556991554f2SKenneth D. Merry * task management commands don't have S/G lists. 557991554f2SKenneth D. Merry */ 558991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 559991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for remove of " 560991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 561991554f2SKenneth D. Merry tm->cm_flags, handle); 562991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 563991554f2SKenneth D. Merry return; 564991554f2SKenneth D. Merry } 565991554f2SKenneth D. Merry 566991554f2SKenneth D. Merry if (reply == NULL) { 567991554f2SKenneth D. Merry /* XXX retry the remove after the diag reset completes? */ 568991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply resetting device " 569991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 570991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 571991554f2SKenneth D. Merry return; 572991554f2SKenneth D. Merry } 573991554f2SKenneth D. Merry 574991554f2SKenneth D. Merry if (le16toh(reply->IOCStatus) != MPI2_IOCSTATUS_SUCCESS) { 575991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "IOCStatus = 0x%x while resetting " 576991554f2SKenneth D. Merry "device 0x%x\n", le16toh(reply->IOCStatus), handle); 577991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 578991554f2SKenneth D. Merry return; 579991554f2SKenneth D. Merry } 580991554f2SKenneth D. Merry 581991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Reset aborted %u commands\n", 582991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 583991554f2SKenneth D. Merry mpr_free_reply(sc, tm->cm_reply_data); 584991554f2SKenneth D. Merry tm->cm_reply = NULL; /* Ensures the reply won't get re-freed */ 585991554f2SKenneth D. Merry 586991554f2SKenneth D. Merry /* Reuse the existing command */ 587991554f2SKenneth D. Merry req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)tm->cm_req; 588991554f2SKenneth D. Merry memset(req, 0, sizeof(*req)); 589991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; 590991554f2SKenneth D. Merry req->Operation = MPI2_SAS_OP_REMOVE_DEVICE; 591991554f2SKenneth D. Merry req->DevHandle = htole16(handle); 592991554f2SKenneth D. Merry tm->cm_data = NULL; 593991554f2SKenneth D. Merry tm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 594991554f2SKenneth D. Merry tm->cm_complete = mprsas_remove_complete; 595991554f2SKenneth D. Merry tm->cm_complete_data = (void *)(uintptr_t)handle; 596991554f2SKenneth D. Merry 597991554f2SKenneth D. Merry mpr_map_command(sc, tm); 598991554f2SKenneth D. Merry 599991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "clearing target %u handle 0x%04x\n", 600991554f2SKenneth D. Merry targ->tid, handle); 601991554f2SKenneth D. Merry if (targ->encl_level_valid) { 602991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 603991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 604991554f2SKenneth D. Merry targ->connector_name); 605991554f2SKenneth D. Merry } 606991554f2SKenneth D. Merry TAILQ_FOREACH_SAFE(tm, &targ->commands, cm_link, next_cm) { 607991554f2SKenneth D. Merry union ccb *ccb; 608991554f2SKenneth D. Merry 609991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Completing missed command %p\n", tm); 610991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 611991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 612991554f2SKenneth D. Merry mprsas_scsiio_complete(sc, tm); 613991554f2SKenneth D. Merry } 614991554f2SKenneth D. Merry } 615991554f2SKenneth D. Merry 616991554f2SKenneth D. Merry static void 617991554f2SKenneth D. Merry mprsas_remove_complete(struct mpr_softc *sc, struct mpr_command *tm) 618991554f2SKenneth D. Merry { 619991554f2SKenneth D. Merry MPI2_SAS_IOUNIT_CONTROL_REPLY *reply; 620991554f2SKenneth D. Merry uint16_t handle; 621991554f2SKenneth D. Merry struct mprsas_target *targ; 622991554f2SKenneth D. Merry struct mprsas_lun *lun; 623991554f2SKenneth D. Merry 624991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 625991554f2SKenneth D. Merry 626991554f2SKenneth D. Merry reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)tm->cm_reply; 627991554f2SKenneth D. Merry handle = (uint16_t)(uintptr_t)tm->cm_complete_data; 628991554f2SKenneth D. Merry 629991554f2SKenneth D. Merry /* 630991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 631991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 632991554f2SKenneth D. Merry * task management commands don't have S/G lists. 633991554f2SKenneth D. Merry */ 634991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 635991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: cm_flags = %#x for remove of " 636991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 637991554f2SKenneth D. Merry tm->cm_flags, handle); 638991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 639991554f2SKenneth D. Merry return; 640991554f2SKenneth D. Merry } 641991554f2SKenneth D. Merry 642991554f2SKenneth D. Merry if (reply == NULL) { 643991554f2SKenneth D. Merry /* most likely a chip reset */ 644991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "%s NULL reply removing device " 645991554f2SKenneth D. Merry "0x%04x\n", __func__, handle); 646991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 647991554f2SKenneth D. Merry return; 648991554f2SKenneth D. Merry } 649991554f2SKenneth D. Merry 650991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s on handle 0x%04x, IOCStatus= 0x%x\n", 651991554f2SKenneth D. Merry __func__, handle, le16toh(reply->IOCStatus)); 652991554f2SKenneth D. Merry 653991554f2SKenneth D. Merry /* 654991554f2SKenneth D. Merry * Don't clear target if remove fails because things will get confusing. 655991554f2SKenneth D. Merry * Leave the devname and sasaddr intact so that we know to avoid reusing 656991554f2SKenneth D. Merry * this target id if possible, and so we can assign the same target id 657991554f2SKenneth D. Merry * to this device if it comes back in the future. 658991554f2SKenneth D. Merry */ 659991554f2SKenneth D. Merry if (le16toh(reply->IOCStatus) == MPI2_IOCSTATUS_SUCCESS) { 660991554f2SKenneth D. Merry targ = tm->cm_targ; 661991554f2SKenneth D. Merry targ->handle = 0x0; 662991554f2SKenneth D. Merry targ->encl_handle = 0x0; 663991554f2SKenneth D. Merry targ->encl_level_valid = 0x0; 664991554f2SKenneth D. Merry targ->encl_level = 0x0; 665991554f2SKenneth D. Merry targ->connector_name[0] = ' '; 666991554f2SKenneth D. Merry targ->connector_name[1] = ' '; 667991554f2SKenneth D. Merry targ->connector_name[2] = ' '; 668991554f2SKenneth D. Merry targ->connector_name[3] = ' '; 669991554f2SKenneth D. Merry targ->encl_slot = 0x0; 670991554f2SKenneth D. Merry targ->exp_dev_handle = 0x0; 671991554f2SKenneth D. Merry targ->phy_num = 0x0; 672991554f2SKenneth D. Merry targ->linkrate = 0x0; 673991554f2SKenneth D. Merry targ->devinfo = 0x0; 674991554f2SKenneth D. Merry targ->flags = 0x0; 675991554f2SKenneth D. Merry targ->scsi_req_desc_type = 0; 676991554f2SKenneth D. Merry 677991554f2SKenneth D. Merry while (!SLIST_EMPTY(&targ->luns)) { 678991554f2SKenneth D. Merry lun = SLIST_FIRST(&targ->luns); 679991554f2SKenneth D. Merry SLIST_REMOVE_HEAD(&targ->luns, lun_link); 680991554f2SKenneth D. Merry free(lun, M_MPR); 681991554f2SKenneth D. Merry } 682991554f2SKenneth D. Merry } 683991554f2SKenneth D. Merry 684991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 685991554f2SKenneth D. Merry } 686991554f2SKenneth D. Merry 687991554f2SKenneth D. Merry static int 688991554f2SKenneth D. Merry mprsas_register_events(struct mpr_softc *sc) 689991554f2SKenneth D. Merry { 690991554f2SKenneth D. Merry uint8_t events[16]; 691991554f2SKenneth D. Merry 692991554f2SKenneth D. Merry bzero(events, 16); 693991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); 694991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_DISCOVERY); 695991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); 696991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE); 697991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); 698991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); 699991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); 700991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); 701991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_VOLUME); 702991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); 703991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); 704991554f2SKenneth D. Merry setbit(events, MPI2_EVENT_TEMP_THRESHOLD); 705991554f2SKenneth D. Merry 706991554f2SKenneth D. Merry mpr_register_events(sc, events, mprsas_evt_handler, NULL, 707991554f2SKenneth D. Merry &sc->sassc->mprsas_eh); 708991554f2SKenneth D. Merry 709991554f2SKenneth D. Merry return (0); 710991554f2SKenneth D. Merry } 711991554f2SKenneth D. Merry 712991554f2SKenneth D. Merry int 713991554f2SKenneth D. Merry mpr_attach_sas(struct mpr_softc *sc) 714991554f2SKenneth D. Merry { 715991554f2SKenneth D. Merry struct mprsas_softc *sassc; 716991554f2SKenneth D. Merry cam_status status; 717991554f2SKenneth D. Merry int unit, error = 0; 718991554f2SKenneth D. Merry 719991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 720991554f2SKenneth D. Merry 721991554f2SKenneth D. Merry sassc = malloc(sizeof(struct mprsas_softc), M_MPR, M_WAITOK|M_ZERO); 722991554f2SKenneth D. Merry if (!sassc) { 723991554f2SKenneth D. Merry device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 724991554f2SKenneth D. Merry __func__, __LINE__); 725991554f2SKenneth D. Merry return (ENOMEM); 726991554f2SKenneth D. Merry } 727991554f2SKenneth D. Merry 728991554f2SKenneth D. Merry /* 729991554f2SKenneth D. Merry * XXX MaxTargets could change during a reinit. since we don't 730991554f2SKenneth D. Merry * resize the targets[] array during such an event, cache the value 731991554f2SKenneth D. Merry * of MaxTargets here so that we don't get into trouble later. This 732991554f2SKenneth D. Merry * should move into the reinit logic. 733991554f2SKenneth D. Merry */ 734991554f2SKenneth D. Merry sassc->maxtargets = sc->facts->MaxTargets; 735991554f2SKenneth D. Merry sassc->targets = malloc(sizeof(struct mprsas_target) * 736991554f2SKenneth D. Merry sassc->maxtargets, M_MPR, M_WAITOK|M_ZERO); 737991554f2SKenneth D. Merry if (!sassc->targets) { 738991554f2SKenneth D. Merry device_printf(sc->mpr_dev, "Cannot allocate memory %s %d\n", 739991554f2SKenneth D. Merry __func__, __LINE__); 740991554f2SKenneth D. Merry free(sassc, M_MPR); 741991554f2SKenneth D. Merry return (ENOMEM); 742991554f2SKenneth D. Merry } 743991554f2SKenneth D. Merry sc->sassc = sassc; 744991554f2SKenneth D. Merry sassc->sc = sc; 745991554f2SKenneth D. Merry 746991554f2SKenneth D. Merry if ((sassc->devq = cam_simq_alloc(sc->num_reqs)) == NULL) { 747991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIMQ\n"); 748991554f2SKenneth D. Merry error = ENOMEM; 749991554f2SKenneth D. Merry goto out; 750991554f2SKenneth D. Merry } 751991554f2SKenneth D. Merry 752991554f2SKenneth D. Merry unit = device_get_unit(sc->mpr_dev); 753991554f2SKenneth D. Merry sassc->sim = cam_sim_alloc(mprsas_action, mprsas_poll, "mpr", sassc, 754991554f2SKenneth D. Merry unit, &sc->mpr_mtx, sc->num_reqs, sc->num_reqs, sassc->devq); 755991554f2SKenneth D. Merry if (sassc->sim == NULL) { 756991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Cannot allocate SIM\n"); 757991554f2SKenneth D. Merry error = EINVAL; 758991554f2SKenneth D. Merry goto out; 759991554f2SKenneth D. Merry } 760991554f2SKenneth D. Merry 761991554f2SKenneth D. Merry TAILQ_INIT(&sassc->ev_queue); 762991554f2SKenneth D. Merry 763991554f2SKenneth D. Merry /* Initialize taskqueue for Event Handling */ 764991554f2SKenneth D. Merry TASK_INIT(&sassc->ev_task, 0, mprsas_firmware_event_work, sc); 765991554f2SKenneth D. Merry sassc->ev_tq = taskqueue_create("mpr_taskq", M_NOWAIT | M_ZERO, 766991554f2SKenneth D. Merry taskqueue_thread_enqueue, &sassc->ev_tq); 767c2a0f07aSAlexander Motin taskqueue_start_threads(&sassc->ev_tq, 1, PRIBIO, "%s taskq", 768991554f2SKenneth D. Merry device_get_nameunit(sc->mpr_dev)); 769991554f2SKenneth D. Merry 770991554f2SKenneth D. Merry mpr_lock(sc); 771991554f2SKenneth D. Merry 772991554f2SKenneth D. Merry /* 773991554f2SKenneth D. Merry * XXX There should be a bus for every port on the adapter, but since 774991554f2SKenneth D. Merry * we're just going to fake the topology for now, we'll pretend that 775991554f2SKenneth D. Merry * everything is just a target on a single bus. 776991554f2SKenneth D. Merry */ 777991554f2SKenneth D. Merry if ((error = xpt_bus_register(sassc->sim, sc->mpr_dev, 0)) != 0) { 778991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Error %d registering SCSI bus\n", 779991554f2SKenneth D. Merry error); 780991554f2SKenneth D. Merry mpr_unlock(sc); 781991554f2SKenneth D. Merry goto out; 782991554f2SKenneth D. Merry } 783991554f2SKenneth D. Merry 784991554f2SKenneth D. Merry /* 785991554f2SKenneth D. Merry * Assume that discovery events will start right away. Freezing 786991554f2SKenneth D. Merry * 787991554f2SKenneth D. Merry * Hold off boot until discovery is complete. 788991554f2SKenneth D. Merry */ 789991554f2SKenneth D. Merry sassc->flags |= MPRSAS_IN_STARTUP | MPRSAS_IN_DISCOVERY; 790991554f2SKenneth D. Merry sc->sassc->startup_refcount = 0; 791991554f2SKenneth D. Merry mprsas_startup_increment(sassc); 792991554f2SKenneth D. Merry 793991554f2SKenneth D. Merry callout_init(&sassc->discovery_callout, 1 /*mprafe*/); 794991554f2SKenneth D. Merry 795991554f2SKenneth D. Merry sassc->tm_count = 0; 796991554f2SKenneth D. Merry 797991554f2SKenneth D. Merry /* 798991554f2SKenneth D. Merry * Register for async events so we can determine the EEDP 799991554f2SKenneth D. Merry * capabilities of devices. 800991554f2SKenneth D. Merry */ 801991554f2SKenneth D. Merry status = xpt_create_path(&sassc->path, /*periph*/NULL, 802991554f2SKenneth D. Merry cam_sim_path(sc->sassc->sim), CAM_TARGET_WILDCARD, 803991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 804991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 805991554f2SKenneth D. Merry mpr_printf(sc, "Error %#x creating sim path\n", status); 806991554f2SKenneth D. Merry sassc->path = NULL; 807991554f2SKenneth D. Merry } else { 808991554f2SKenneth D. Merry int event; 809991554f2SKenneth D. Merry 810991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 811991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 812991554f2SKenneth D. Merry event = AC_ADVINFO_CHANGED | AC_FOUND_DEVICE; 813991554f2SKenneth D. Merry #else 814991554f2SKenneth D. Merry event = AC_FOUND_DEVICE; 815991554f2SKenneth D. Merry #endif 81607aa4de1SKenneth D. Merry 81707aa4de1SKenneth D. Merry /* 81807aa4de1SKenneth D. Merry * Prior to the CAM locking improvements, we can't call 81907aa4de1SKenneth D. Merry * xpt_register_async() with a particular path specified. 82007aa4de1SKenneth D. Merry * 82107aa4de1SKenneth D. Merry * If a path isn't specified, xpt_register_async() will 82207aa4de1SKenneth D. Merry * generate a wildcard path and acquire the XPT lock while 82307aa4de1SKenneth D. Merry * it calls xpt_action() to execute the XPT_SASYNC_CB CCB. 82407aa4de1SKenneth D. Merry * It will then drop the XPT lock once that is done. 82507aa4de1SKenneth D. Merry * 82607aa4de1SKenneth D. Merry * If a path is specified for xpt_register_async(), it will 82707aa4de1SKenneth D. Merry * not acquire and drop the XPT lock around the call to 82807aa4de1SKenneth D. Merry * xpt_action(). xpt_action() asserts that the caller 82907aa4de1SKenneth D. Merry * holds the SIM lock, so the SIM lock has to be held when 83007aa4de1SKenneth D. Merry * calling xpt_register_async() when the path is specified. 83107aa4de1SKenneth D. Merry * 83207aa4de1SKenneth D. Merry * But xpt_register_async calls xpt_for_all_devices(), 83307aa4de1SKenneth D. Merry * which calls xptbustraverse(), which will acquire each 83407aa4de1SKenneth D. Merry * SIM lock. When it traverses our particular bus, it will 83507aa4de1SKenneth D. Merry * necessarily acquire the SIM lock, which will lead to a 83607aa4de1SKenneth D. Merry * recursive lock acquisition. 83707aa4de1SKenneth D. Merry * 83807aa4de1SKenneth D. Merry * The CAM locking changes fix this problem by acquiring 83907aa4de1SKenneth D. Merry * the XPT topology lock around bus traversal in 84007aa4de1SKenneth D. Merry * xptbustraverse(), so the caller can hold the SIM lock 84107aa4de1SKenneth D. Merry * and it does not cause a recursive lock acquisition. 84207aa4de1SKenneth D. Merry * 84307aa4de1SKenneth D. Merry * These __FreeBSD_version values are approximate, especially 84407aa4de1SKenneth D. Merry * for stable/10, which is two months later than the actual 84507aa4de1SKenneth D. Merry * change. 84607aa4de1SKenneth D. Merry */ 84707aa4de1SKenneth D. Merry 84807aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 84907aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 85007aa4de1SKenneth D. Merry mpr_unlock(sc); 85107aa4de1SKenneth D. Merry status = xpt_register_async(event, mprsas_async, sc, 85207aa4de1SKenneth D. Merry NULL); 85307aa4de1SKenneth D. Merry mpr_lock(sc); 85407aa4de1SKenneth D. Merry #else 855991554f2SKenneth D. Merry status = xpt_register_async(event, mprsas_async, sc, 856991554f2SKenneth D. Merry sassc->path); 85707aa4de1SKenneth D. Merry #endif 85807aa4de1SKenneth D. Merry 859991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 860991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 861991554f2SKenneth D. Merry "Error %#x registering async handler for " 862991554f2SKenneth D. Merry "AC_ADVINFO_CHANGED events\n", status); 863991554f2SKenneth D. Merry xpt_free_path(sassc->path); 864991554f2SKenneth D. Merry sassc->path = NULL; 865991554f2SKenneth D. Merry } 866991554f2SKenneth D. Merry } 867991554f2SKenneth D. Merry if (status != CAM_REQ_CMP) { 868991554f2SKenneth D. Merry /* 869991554f2SKenneth D. Merry * EEDP use is the exception, not the rule. 870991554f2SKenneth D. Merry * Warn the user, but do not fail to attach. 871991554f2SKenneth D. Merry */ 872991554f2SKenneth D. Merry mpr_printf(sc, "EEDP capabilities disabled.\n"); 873991554f2SKenneth D. Merry } 874991554f2SKenneth D. Merry 875991554f2SKenneth D. Merry mpr_unlock(sc); 876991554f2SKenneth D. Merry 877991554f2SKenneth D. Merry mprsas_register_events(sc); 878991554f2SKenneth D. Merry out: 879991554f2SKenneth D. Merry if (error) 880991554f2SKenneth D. Merry mpr_detach_sas(sc); 881991554f2SKenneth D. Merry return (error); 882991554f2SKenneth D. Merry } 883991554f2SKenneth D. Merry 884991554f2SKenneth D. Merry int 885991554f2SKenneth D. Merry mpr_detach_sas(struct mpr_softc *sc) 886991554f2SKenneth D. Merry { 887991554f2SKenneth D. Merry struct mprsas_softc *sassc; 888991554f2SKenneth D. Merry struct mprsas_lun *lun, *lun_tmp; 889991554f2SKenneth D. Merry struct mprsas_target *targ; 890991554f2SKenneth D. Merry int i; 891991554f2SKenneth D. Merry 892991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 893991554f2SKenneth D. Merry 894991554f2SKenneth D. Merry if (sc->sassc == NULL) 895991554f2SKenneth D. Merry return (0); 896991554f2SKenneth D. Merry 897991554f2SKenneth D. Merry sassc = sc->sassc; 898991554f2SKenneth D. Merry mpr_deregister_events(sc, sassc->mprsas_eh); 899991554f2SKenneth D. Merry 900991554f2SKenneth D. Merry /* 901991554f2SKenneth D. Merry * Drain and free the event handling taskqueue with the lock 902991554f2SKenneth D. Merry * unheld so that any parallel processing tasks drain properly 903991554f2SKenneth D. Merry * without deadlocking. 904991554f2SKenneth D. Merry */ 905991554f2SKenneth D. Merry if (sassc->ev_tq != NULL) 906991554f2SKenneth D. Merry taskqueue_free(sassc->ev_tq); 907991554f2SKenneth D. Merry 908991554f2SKenneth D. Merry /* Make sure CAM doesn't wedge if we had to bail out early. */ 909991554f2SKenneth D. Merry mpr_lock(sc); 910991554f2SKenneth D. Merry 911991554f2SKenneth D. Merry /* Deregister our async handler */ 912991554f2SKenneth D. Merry if (sassc->path != NULL) { 913991554f2SKenneth D. Merry xpt_register_async(0, mprsas_async, sc, sassc->path); 914991554f2SKenneth D. Merry xpt_free_path(sassc->path); 915991554f2SKenneth D. Merry sassc->path = NULL; 916991554f2SKenneth D. Merry } 917991554f2SKenneth D. Merry 918991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_IN_STARTUP) 919991554f2SKenneth D. Merry xpt_release_simq(sassc->sim, 1); 920991554f2SKenneth D. Merry 921991554f2SKenneth D. Merry if (sassc->sim != NULL) { 922991554f2SKenneth D. Merry xpt_bus_deregister(cam_sim_path(sassc->sim)); 923991554f2SKenneth D. Merry cam_sim_free(sassc->sim, FALSE); 924991554f2SKenneth D. Merry } 925991554f2SKenneth D. Merry 926991554f2SKenneth D. Merry sassc->flags |= MPRSAS_SHUTDOWN; 927991554f2SKenneth D. Merry mpr_unlock(sc); 928991554f2SKenneth D. Merry 929991554f2SKenneth D. Merry if (sassc->devq != NULL) 930991554f2SKenneth D. Merry cam_simq_free(sassc->devq); 931991554f2SKenneth D. Merry 932991554f2SKenneth D. Merry for (i = 0; i < sassc->maxtargets; i++) { 933991554f2SKenneth D. Merry targ = &sassc->targets[i]; 934991554f2SKenneth D. Merry SLIST_FOREACH_SAFE(lun, &targ->luns, lun_link, lun_tmp) { 935991554f2SKenneth D. Merry free(lun, M_MPR); 936991554f2SKenneth D. Merry } 937991554f2SKenneth D. Merry } 938991554f2SKenneth D. Merry free(sassc->targets, M_MPR); 939991554f2SKenneth D. Merry free(sassc, M_MPR); 940991554f2SKenneth D. Merry sc->sassc = NULL; 941991554f2SKenneth D. Merry 942991554f2SKenneth D. Merry return (0); 943991554f2SKenneth D. Merry } 944991554f2SKenneth D. Merry 945991554f2SKenneth D. Merry void 946991554f2SKenneth D. Merry mprsas_discovery_end(struct mprsas_softc *sassc) 947991554f2SKenneth D. Merry { 948991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 949991554f2SKenneth D. Merry 950991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 951991554f2SKenneth D. Merry 952991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_DISCOVERY_TIMEOUT_PENDING) 953991554f2SKenneth D. Merry callout_stop(&sassc->discovery_callout); 954991554f2SKenneth D. Merry 955991554f2SKenneth D. Merry } 956991554f2SKenneth D. Merry 957991554f2SKenneth D. Merry static void 958991554f2SKenneth D. Merry mprsas_action(struct cam_sim *sim, union ccb *ccb) 959991554f2SKenneth D. Merry { 960991554f2SKenneth D. Merry struct mprsas_softc *sassc; 961991554f2SKenneth D. Merry 962991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 963991554f2SKenneth D. Merry 964991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 965991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_TRACE, "%s func 0x%x\n", __func__, 966991554f2SKenneth D. Merry ccb->ccb_h.func_code); 967991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 968991554f2SKenneth D. Merry 969991554f2SKenneth D. Merry switch (ccb->ccb_h.func_code) { 970991554f2SKenneth D. Merry case XPT_PATH_INQ: 971991554f2SKenneth D. Merry { 972991554f2SKenneth D. Merry struct ccb_pathinq *cpi = &ccb->cpi; 973991554f2SKenneth D. Merry 974991554f2SKenneth D. Merry cpi->version_num = 1; 975991554f2SKenneth D. Merry cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16; 976991554f2SKenneth D. Merry cpi->target_sprt = 0; 977a371d6f9SKenneth D. Merry #if (__FreeBSD_version >= 1000039) || \ 978a371d6f9SKenneth D. Merry ((__FreeBSD_version < 1000000) && (__FreeBSD_version >= 902502)) 979991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED | PIM_NOSCAN; 980991554f2SKenneth D. Merry #else 981991554f2SKenneth D. Merry cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; 982991554f2SKenneth D. Merry #endif 983991554f2SKenneth D. Merry cpi->hba_eng_cnt = 0; 984991554f2SKenneth D. Merry cpi->max_target = sassc->maxtargets - 1; 985991554f2SKenneth D. Merry cpi->max_lun = 255; 986991554f2SKenneth D. Merry cpi->initiator_id = sassc->maxtargets - 1; 987991554f2SKenneth D. Merry strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 988991554f2SKenneth D. Merry strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN); 989991554f2SKenneth D. Merry strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 990991554f2SKenneth D. Merry cpi->unit_number = cam_sim_unit(sim); 991991554f2SKenneth D. Merry cpi->bus_id = cam_sim_bus(sim); 992991554f2SKenneth D. Merry /* 993991554f2SKenneth D. Merry * XXXSLM-I think this needs to change based on config page or 994991554f2SKenneth D. Merry * something instead of hardcoded to 150000. 995991554f2SKenneth D. Merry */ 996991554f2SKenneth D. Merry cpi->base_transfer_speed = 150000; 997991554f2SKenneth D. Merry cpi->transport = XPORT_SAS; 998991554f2SKenneth D. Merry cpi->transport_version = 0; 999991554f2SKenneth D. Merry cpi->protocol = PROTO_SCSI; 1000991554f2SKenneth D. Merry cpi->protocol_version = SCSI_REV_SPC; 1001991554f2SKenneth D. Merry #if __FreeBSD_version >= 800001 1002991554f2SKenneth D. Merry /* 1003991554f2SKenneth D. Merry * XXXSLM-probably need to base this number on max SGL's and 1004991554f2SKenneth D. Merry * page size. 1005991554f2SKenneth D. Merry */ 1006991554f2SKenneth D. Merry cpi->maxio = 256 * 1024; 1007991554f2SKenneth D. Merry #endif 1008991554f2SKenneth D. Merry cpi->ccb_h.status = CAM_REQ_CMP; 1009991554f2SKenneth D. Merry break; 1010991554f2SKenneth D. Merry } 1011991554f2SKenneth D. Merry case XPT_GET_TRAN_SETTINGS: 1012991554f2SKenneth D. Merry { 1013991554f2SKenneth D. Merry struct ccb_trans_settings *cts; 1014991554f2SKenneth D. Merry struct ccb_trans_settings_sas *sas; 1015991554f2SKenneth D. Merry struct ccb_trans_settings_scsi *scsi; 1016991554f2SKenneth D. Merry struct mprsas_target *targ; 1017991554f2SKenneth D. Merry 1018991554f2SKenneth D. Merry cts = &ccb->cts; 1019991554f2SKenneth D. Merry sas = &cts->xport_specific.sas; 1020991554f2SKenneth D. Merry scsi = &cts->proto_specific.scsi; 1021991554f2SKenneth D. Merry 1022991554f2SKenneth D. Merry KASSERT(cts->ccb_h.target_id < sassc->maxtargets, 1023991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_GET_TRAN_SETTINGS\n", 1024991554f2SKenneth D. Merry cts->ccb_h.target_id)); 1025991554f2SKenneth D. Merry targ = &sassc->targets[cts->ccb_h.target_id]; 1026991554f2SKenneth D. Merry if (targ->handle == 0x0) { 1027991554f2SKenneth D. Merry cts->ccb_h.status = CAM_DEV_NOT_THERE; 1028991554f2SKenneth D. Merry break; 1029991554f2SKenneth D. Merry } 1030991554f2SKenneth D. Merry 1031991554f2SKenneth D. Merry cts->protocol_version = SCSI_REV_SPC2; 1032991554f2SKenneth D. Merry cts->transport = XPORT_SAS; 1033991554f2SKenneth D. Merry cts->transport_version = 0; 1034991554f2SKenneth D. Merry 1035991554f2SKenneth D. Merry sas->valid = CTS_SAS_VALID_SPEED; 1036991554f2SKenneth D. Merry switch (targ->linkrate) { 1037991554f2SKenneth D. Merry case 0x08: 1038991554f2SKenneth D. Merry sas->bitrate = 150000; 1039991554f2SKenneth D. Merry break; 1040991554f2SKenneth D. Merry case 0x09: 1041991554f2SKenneth D. Merry sas->bitrate = 300000; 1042991554f2SKenneth D. Merry break; 1043991554f2SKenneth D. Merry case 0x0a: 1044991554f2SKenneth D. Merry sas->bitrate = 600000; 1045991554f2SKenneth D. Merry break; 104682315915SAlexander Motin case 0x0b: 104782315915SAlexander Motin sas->bitrate = 1200000; 104882315915SAlexander Motin break; 1049991554f2SKenneth D. Merry default: 1050991554f2SKenneth D. Merry sas->valid = 0; 1051991554f2SKenneth D. Merry } 1052991554f2SKenneth D. Merry 1053991554f2SKenneth D. Merry cts->protocol = PROTO_SCSI; 1054991554f2SKenneth D. Merry scsi->valid = CTS_SCSI_VALID_TQ; 1055991554f2SKenneth D. Merry scsi->flags = CTS_SCSI_FLAGS_TAG_ENB; 1056991554f2SKenneth D. Merry 1057991554f2SKenneth D. Merry cts->ccb_h.status = CAM_REQ_CMP; 1058991554f2SKenneth D. Merry break; 1059991554f2SKenneth D. Merry } 1060991554f2SKenneth D. Merry case XPT_CALC_GEOMETRY: 1061991554f2SKenneth D. Merry cam_calc_geometry(&ccb->ccg, /*extended*/1); 1062991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 1063991554f2SKenneth D. Merry break; 1064991554f2SKenneth D. Merry case XPT_RESET_DEV: 1065991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_XINFO, 1066991554f2SKenneth D. Merry "mprsas_action XPT_RESET_DEV\n"); 1067991554f2SKenneth D. Merry mprsas_action_resetdev(sassc, ccb); 1068991554f2SKenneth D. Merry return; 1069991554f2SKenneth D. Merry case XPT_RESET_BUS: 1070991554f2SKenneth D. Merry case XPT_ABORT: 1071991554f2SKenneth D. Merry case XPT_TERM_IO: 1072991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_XINFO, 1073991554f2SKenneth D. Merry "mprsas_action faking success for abort or reset\n"); 1074991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 1075991554f2SKenneth D. Merry break; 1076991554f2SKenneth D. Merry case XPT_SCSI_IO: 1077991554f2SKenneth D. Merry mprsas_action_scsiio(sassc, ccb); 1078991554f2SKenneth D. Merry return; 1079991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 1080991554f2SKenneth D. Merry case XPT_SMP_IO: 1081991554f2SKenneth D. Merry mprsas_action_smpio(sassc, ccb); 1082991554f2SKenneth D. Merry return; 1083991554f2SKenneth D. Merry #endif 1084991554f2SKenneth D. Merry default: 1085991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 1086991554f2SKenneth D. Merry break; 1087991554f2SKenneth D. Merry } 1088991554f2SKenneth D. Merry xpt_done(ccb); 1089991554f2SKenneth D. Merry 1090991554f2SKenneth D. Merry } 1091991554f2SKenneth D. Merry 1092991554f2SKenneth D. Merry static void 1093991554f2SKenneth D. Merry mprsas_announce_reset(struct mpr_softc *sc, uint32_t ac_code, 1094991554f2SKenneth D. Merry target_id_t target_id, lun_id_t lun_id) 1095991554f2SKenneth D. Merry { 1096991554f2SKenneth D. Merry path_id_t path_id = cam_sim_path(sc->sassc->sim); 1097991554f2SKenneth D. Merry struct cam_path *path; 1098991554f2SKenneth D. Merry 1099991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s code %x target %d lun %jx\n", __func__, 1100991554f2SKenneth D. Merry ac_code, target_id, (uintmax_t)lun_id); 1101991554f2SKenneth D. Merry 1102991554f2SKenneth D. Merry if (xpt_create_path(&path, NULL, 1103991554f2SKenneth D. Merry path_id, target_id, lun_id) != CAM_REQ_CMP) { 1104991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unable to create path for reset " 1105991554f2SKenneth D. Merry "notification\n"); 1106991554f2SKenneth D. Merry return; 1107991554f2SKenneth D. Merry } 1108991554f2SKenneth D. Merry 1109991554f2SKenneth D. Merry xpt_async(ac_code, path, NULL); 1110991554f2SKenneth D. Merry xpt_free_path(path); 1111991554f2SKenneth D. Merry } 1112991554f2SKenneth D. Merry 1113991554f2SKenneth D. Merry static void 1114991554f2SKenneth D. Merry mprsas_complete_all_commands(struct mpr_softc *sc) 1115991554f2SKenneth D. Merry { 1116991554f2SKenneth D. Merry struct mpr_command *cm; 1117991554f2SKenneth D. Merry int i; 1118991554f2SKenneth D. Merry int completed; 1119991554f2SKenneth D. Merry 1120991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1121991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1122991554f2SKenneth D. Merry 1123991554f2SKenneth D. Merry /* complete all commands with a NULL reply */ 1124991554f2SKenneth D. Merry for (i = 1; i < sc->num_reqs; i++) { 1125991554f2SKenneth D. Merry cm = &sc->commands[i]; 1126991554f2SKenneth D. Merry cm->cm_reply = NULL; 1127991554f2SKenneth D. Merry completed = 0; 1128991554f2SKenneth D. Merry 1129991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_POLLED) 1130991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_COMPLETE; 1131991554f2SKenneth D. Merry 1132991554f2SKenneth D. Merry if (cm->cm_complete != NULL) { 1133991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1134991554f2SKenneth D. Merry "completing cm %p state %x ccb %p for diag reset\n", 1135991554f2SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb); 1136991554f2SKenneth D. Merry cm->cm_complete(sc, cm); 1137991554f2SKenneth D. Merry completed = 1; 1138991554f2SKenneth D. Merry } 1139991554f2SKenneth D. Merry 1140991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_WAKEUP) { 1141991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1142991554f2SKenneth D. Merry "waking up cm %p state %x ccb %p for diag reset\n", 1143991554f2SKenneth D. Merry cm, cm->cm_state, cm->cm_ccb); 1144991554f2SKenneth D. Merry wakeup(cm); 1145991554f2SKenneth D. Merry completed = 1; 1146991554f2SKenneth D. Merry } 1147991554f2SKenneth D. Merry 1148991554f2SKenneth D. Merry if ((completed == 0) && (cm->cm_state != MPR_CM_STATE_FREE)) { 1149991554f2SKenneth D. Merry /* this should never happen, but if it does, log */ 1150991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 1151991554f2SKenneth D. Merry "cm %p state %x flags 0x%x ccb %p during diag " 1152991554f2SKenneth D. Merry "reset\n", cm, cm->cm_state, cm->cm_flags, 1153991554f2SKenneth D. Merry cm->cm_ccb); 1154991554f2SKenneth D. Merry } 1155991554f2SKenneth D. Merry } 1156991554f2SKenneth D. Merry } 1157991554f2SKenneth D. Merry 1158991554f2SKenneth D. Merry void 1159991554f2SKenneth D. Merry mprsas_handle_reinit(struct mpr_softc *sc) 1160991554f2SKenneth D. Merry { 1161991554f2SKenneth D. Merry int i; 1162991554f2SKenneth D. Merry 1163991554f2SKenneth D. Merry /* Go back into startup mode and freeze the simq, so that CAM 1164991554f2SKenneth D. Merry * doesn't send any commands until after we've rediscovered all 1165991554f2SKenneth D. Merry * targets and found the proper device handles for them. 1166991554f2SKenneth D. Merry * 1167991554f2SKenneth D. Merry * After the reset, portenable will trigger discovery, and after all 1168991554f2SKenneth D. Merry * discovery-related activities have finished, the simq will be 1169991554f2SKenneth D. Merry * released. 1170991554f2SKenneth D. Merry */ 1171991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "%s startup\n", __func__); 1172991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_STARTUP; 1173991554f2SKenneth D. Merry sc->sassc->flags |= MPRSAS_IN_DISCOVERY; 1174991554f2SKenneth D. Merry mprsas_startup_increment(sc->sassc); 1175991554f2SKenneth D. Merry 1176991554f2SKenneth D. Merry /* notify CAM of a bus reset */ 1177991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_BUS_RESET, CAM_TARGET_WILDCARD, 1178991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1179991554f2SKenneth D. Merry 1180991554f2SKenneth D. Merry /* complete and cleanup after all outstanding commands */ 1181991554f2SKenneth D. Merry mprsas_complete_all_commands(sc); 1182991554f2SKenneth D. Merry 1183991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "%s startup %u tm %u after command " 1184991554f2SKenneth D. Merry "completion\n", __func__, sc->sassc->startup_refcount, 1185991554f2SKenneth D. Merry sc->sassc->tm_count); 1186991554f2SKenneth D. Merry 1187991554f2SKenneth D. Merry /* zero all the target handles, since they may change after the 1188991554f2SKenneth D. Merry * reset, and we have to rediscover all the targets and use the new 1189991554f2SKenneth D. Merry * handles. 1190991554f2SKenneth D. Merry */ 1191991554f2SKenneth D. Merry for (i = 0; i < sc->sassc->maxtargets; i++) { 1192991554f2SKenneth D. Merry if (sc->sassc->targets[i].outstanding != 0) 1193991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INIT, "target %u outstanding %u\n", 1194991554f2SKenneth D. Merry i, sc->sassc->targets[i].outstanding); 1195991554f2SKenneth D. Merry sc->sassc->targets[i].handle = 0x0; 1196991554f2SKenneth D. Merry sc->sassc->targets[i].exp_dev_handle = 0x0; 1197991554f2SKenneth D. Merry sc->sassc->targets[i].outstanding = 0; 1198991554f2SKenneth D. Merry sc->sassc->targets[i].flags = MPRSAS_TARGET_INDIAGRESET; 1199991554f2SKenneth D. Merry } 1200991554f2SKenneth D. Merry } 1201991554f2SKenneth D. Merry static void 1202991554f2SKenneth D. Merry mprsas_tm_timeout(void *data) 1203991554f2SKenneth D. Merry { 1204991554f2SKenneth D. Merry struct mpr_command *tm = data; 1205991554f2SKenneth D. Merry struct mpr_softc *sc = tm->cm_sc; 1206991554f2SKenneth D. Merry 1207991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1208991554f2SKenneth D. Merry 1209991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_INFO|MPR_RECOVERY, 1210991554f2SKenneth D. Merry "task mgmt %p timed out\n", tm); 1211991554f2SKenneth D. Merry mpr_reinit(sc); 1212991554f2SKenneth D. Merry } 1213991554f2SKenneth D. Merry 1214991554f2SKenneth D. Merry static void 1215991554f2SKenneth D. Merry mprsas_logical_unit_reset_complete(struct mpr_softc *sc, 1216991554f2SKenneth D. Merry struct mpr_command *tm) 1217991554f2SKenneth D. Merry { 1218991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1219991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1220991554f2SKenneth D. Merry unsigned int cm_count = 0; 1221991554f2SKenneth D. Merry struct mpr_command *cm; 1222991554f2SKenneth D. Merry struct mprsas_target *targ; 1223991554f2SKenneth D. Merry 1224991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1225991554f2SKenneth D. Merry 1226991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1227991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1228991554f2SKenneth D. Merry targ = tm->cm_targ; 1229991554f2SKenneth D. Merry 1230991554f2SKenneth D. Merry /* 1231991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1232991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1233991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1234991554f2SKenneth D. Merry */ 1235991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1236991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for LUN reset! " 1237991554f2SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags); 1238991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1239991554f2SKenneth D. Merry return; 1240991554f2SKenneth D. Merry } 1241991554f2SKenneth D. Merry 1242991554f2SKenneth D. Merry if (reply == NULL) { 1243991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1244991554f2SKenneth D. Merry "NULL reset reply for tm %p\n", tm); 1245991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1246991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1247991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1248991554f2SKenneth D. Merry targ->tm = NULL; 1249991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1250991554f2SKenneth D. Merry } 1251991554f2SKenneth D. Merry else { 1252991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1253991554f2SKenneth D. Merry mpr_reinit(sc); 1254991554f2SKenneth D. Merry } 1255991554f2SKenneth D. Merry return; 1256991554f2SKenneth D. Merry } 1257991554f2SKenneth D. Merry 1258991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1259991554f2SKenneth D. Merry "logical unit reset status 0x%x code 0x%x count %u\n", 1260991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1261991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1262991554f2SKenneth D. Merry 1263991554f2SKenneth D. Merry /* See if there are any outstanding commands for this LUN. 1264991554f2SKenneth D. Merry * This could be made more efficient by using a per-LU data 1265991554f2SKenneth D. Merry * structure of some sort. 1266991554f2SKenneth D. Merry */ 1267991554f2SKenneth D. Merry TAILQ_FOREACH(cm, &targ->commands, cm_link) { 1268991554f2SKenneth D. Merry if (cm->cm_lun == tm->cm_lun) 1269991554f2SKenneth D. Merry cm_count++; 1270991554f2SKenneth D. Merry } 1271991554f2SKenneth D. Merry 1272991554f2SKenneth D. Merry if (cm_count == 0) { 1273991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1274991554f2SKenneth D. Merry "logical unit %u finished recovery after reset\n", 1275991554f2SKenneth D. Merry tm->cm_lun, tm); 1276991554f2SKenneth D. Merry 1277991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1278991554f2SKenneth D. Merry tm->cm_lun); 1279991554f2SKenneth D. Merry 1280991554f2SKenneth D. Merry /* we've finished recovery for this logical unit. check and 1281991554f2SKenneth D. Merry * see if some other logical unit has a timedout command 1282991554f2SKenneth D. Merry * that needs to be processed. 1283991554f2SKenneth D. Merry */ 1284991554f2SKenneth D. Merry cm = TAILQ_FIRST(&targ->timedout_commands); 1285991554f2SKenneth D. Merry if (cm) { 1286991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1287991554f2SKenneth D. Merry } 1288991554f2SKenneth D. Merry else { 1289991554f2SKenneth D. Merry targ->tm = NULL; 1290991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1291991554f2SKenneth D. Merry } 1292991554f2SKenneth D. Merry } 1293991554f2SKenneth D. Merry else { 1294991554f2SKenneth D. Merry /* if we still have commands for this LUN, the reset 1295991554f2SKenneth D. Merry * effectively failed, regardless of the status reported. 1296991554f2SKenneth D. Merry * Escalate to a target reset. 1297991554f2SKenneth D. Merry */ 1298991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1299991554f2SKenneth D. Merry "logical unit reset complete for tm %p, but still have %u " 1300991554f2SKenneth D. Merry "command(s)\n", tm, cm_count); 1301991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1302991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET); 1303991554f2SKenneth D. Merry } 1304991554f2SKenneth D. Merry } 1305991554f2SKenneth D. Merry 1306991554f2SKenneth D. Merry static void 1307991554f2SKenneth D. Merry mprsas_target_reset_complete(struct mpr_softc *sc, struct mpr_command *tm) 1308991554f2SKenneth D. Merry { 1309991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1310991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1311991554f2SKenneth D. Merry struct mprsas_target *targ; 1312991554f2SKenneth D. Merry 1313991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1314991554f2SKenneth D. Merry 1315991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1316991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1317991554f2SKenneth D. Merry targ = tm->cm_targ; 1318991554f2SKenneth D. Merry 1319991554f2SKenneth D. Merry /* 1320991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1321991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1322991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1323991554f2SKenneth D. Merry */ 1324991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1325991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x for target reset! " 1326991554f2SKenneth D. Merry "This should not happen!\n", __func__, tm->cm_flags); 1327991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1328991554f2SKenneth D. Merry return; 1329991554f2SKenneth D. Merry } 1330991554f2SKenneth D. Merry 1331991554f2SKenneth D. Merry if (reply == NULL) { 1332991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1333991554f2SKenneth D. Merry "NULL reset reply for tm %p\n", tm); 1334991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1335991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1336991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1337991554f2SKenneth D. Merry targ->tm = NULL; 1338991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1339991554f2SKenneth D. Merry } 1340991554f2SKenneth D. Merry else { 1341991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1342991554f2SKenneth D. Merry mpr_reinit(sc); 1343991554f2SKenneth D. Merry } 1344991554f2SKenneth D. Merry return; 1345991554f2SKenneth D. Merry } 1346991554f2SKenneth D. Merry 1347991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1348991554f2SKenneth D. Merry "target reset status 0x%x code 0x%x count %u\n", 1349991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1350991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1351991554f2SKenneth D. Merry 1352991554f2SKenneth D. Merry targ->flags &= ~MPRSAS_TARGET_INRESET; 1353991554f2SKenneth D. Merry 1354991554f2SKenneth D. Merry if (targ->outstanding == 0) { 1355991554f2SKenneth D. Merry /* we've finished recovery for this target and all 1356991554f2SKenneth D. Merry * of its logical units. 1357991554f2SKenneth D. Merry */ 1358991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1359991554f2SKenneth D. Merry "recovery finished after target reset\n"); 1360991554f2SKenneth D. Merry 1361991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 1362991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 1363991554f2SKenneth D. Merry 1364991554f2SKenneth D. Merry targ->tm = NULL; 1365991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1366991554f2SKenneth D. Merry } 1367991554f2SKenneth D. Merry else { 1368991554f2SKenneth D. Merry /* after a target reset, if this target still has 1369991554f2SKenneth D. Merry * outstanding commands, the reset effectively failed, 1370991554f2SKenneth D. Merry * regardless of the status reported. escalate. 1371991554f2SKenneth D. Merry */ 1372991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1373991554f2SKenneth D. Merry "target reset complete for tm %p, but still have %u " 1374991554f2SKenneth D. Merry "command(s)\n", tm, targ->outstanding); 1375991554f2SKenneth D. Merry mpr_reinit(sc); 1376991554f2SKenneth D. Merry } 1377991554f2SKenneth D. Merry } 1378991554f2SKenneth D. Merry 1379991554f2SKenneth D. Merry #define MPR_RESET_TIMEOUT 30 1380991554f2SKenneth D. Merry 1381991554f2SKenneth D. Merry static int 1382991554f2SKenneth D. Merry mprsas_send_reset(struct mpr_softc *sc, struct mpr_command *tm, uint8_t type) 1383991554f2SKenneth D. Merry { 1384991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1385991554f2SKenneth D. Merry struct mprsas_target *target; 1386991554f2SKenneth D. Merry int err; 1387991554f2SKenneth D. Merry 1388991554f2SKenneth D. Merry target = tm->cm_targ; 1389991554f2SKenneth D. Merry if (target->handle == 0) { 1390991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", 1391991554f2SKenneth D. Merry __func__, target->tid); 1392991554f2SKenneth D. Merry return -1; 1393991554f2SKenneth D. Merry } 1394991554f2SKenneth D. Merry 1395991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1396991554f2SKenneth D. Merry req->DevHandle = htole16(target->handle); 1397991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1398991554f2SKenneth D. Merry req->TaskType = type; 1399991554f2SKenneth D. Merry 1400991554f2SKenneth D. Merry if (type == MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET) { 1401991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1402991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, tm->cm_lun); 1403991554f2SKenneth D. Merry tm->cm_targ->logical_unit_resets++; 1404991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1405991554f2SKenneth D. Merry "sending logical unit reset\n"); 1406991554f2SKenneth D. Merry tm->cm_complete = mprsas_logical_unit_reset_complete; 1407991554f2SKenneth D. Merry } 1408991554f2SKenneth D. Merry else if (type == MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { 1409991554f2SKenneth D. Merry /* 1410991554f2SKenneth D. Merry * Target reset method = 1411991554f2SKenneth D. Merry * SAS Hard Link Reset / SATA Link Reset 1412991554f2SKenneth D. Merry */ 1413991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 1414991554f2SKenneth D. Merry tm->cm_targ->target_resets++; 1415991554f2SKenneth D. Merry tm->cm_targ->flags |= MPRSAS_TARGET_INRESET; 1416991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1417991554f2SKenneth D. Merry "sending target reset\n"); 1418991554f2SKenneth D. Merry tm->cm_complete = mprsas_target_reset_complete; 1419991554f2SKenneth D. Merry } 1420991554f2SKenneth D. Merry else { 1421991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "unexpected reset type 0x%x\n", type); 1422991554f2SKenneth D. Merry return -1; 1423991554f2SKenneth D. Merry } 1424991554f2SKenneth D. Merry 1425991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "to target %u handle 0x%04x\n", target->tid, 1426991554f2SKenneth D. Merry target->handle); 1427991554f2SKenneth D. Merry if (target->encl_level_valid) { 1428991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 1429991554f2SKenneth D. Merry "connector name (%4s)\n", target->encl_level, 1430991554f2SKenneth D. Merry target->encl_slot, target->connector_name); 1431991554f2SKenneth D. Merry } 1432991554f2SKenneth D. Merry 1433991554f2SKenneth D. Merry tm->cm_data = NULL; 1434991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1435991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1436991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1437991554f2SKenneth D. Merry 1438991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_RESET_TIMEOUT * hz, 1439991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1440991554f2SKenneth D. Merry 1441991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1442991554f2SKenneth D. Merry if (err) 1443991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1444991554f2SKenneth D. Merry "error %d sending reset type %u\n", 1445991554f2SKenneth D. Merry err, type); 1446991554f2SKenneth D. Merry 1447991554f2SKenneth D. Merry return err; 1448991554f2SKenneth D. Merry } 1449991554f2SKenneth D. Merry 1450991554f2SKenneth D. Merry 1451991554f2SKenneth D. Merry static void 1452991554f2SKenneth D. Merry mprsas_abort_complete(struct mpr_softc *sc, struct mpr_command *tm) 1453991554f2SKenneth D. Merry { 1454991554f2SKenneth D. Merry struct mpr_command *cm; 1455991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *reply; 1456991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1457991554f2SKenneth D. Merry struct mprsas_target *targ; 1458991554f2SKenneth D. Merry 1459991554f2SKenneth D. Merry callout_stop(&tm->cm_callout); 1460991554f2SKenneth D. Merry 1461991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1462991554f2SKenneth D. Merry reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 1463991554f2SKenneth D. Merry targ = tm->cm_targ; 1464991554f2SKenneth D. Merry 1465991554f2SKenneth D. Merry /* 1466991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 1467991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 1468991554f2SKenneth D. Merry * task management commands don't have S/G lists. 1469991554f2SKenneth D. Merry */ 1470991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 1471991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1472991554f2SKenneth D. Merry "cm_flags = %#x for abort %p TaskMID %u!\n", 1473991554f2SKenneth D. Merry tm->cm_flags, tm, le16toh(req->TaskMID)); 1474991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1475991554f2SKenneth D. Merry return; 1476991554f2SKenneth D. Merry } 1477991554f2SKenneth D. Merry 1478991554f2SKenneth D. Merry if (reply == NULL) { 1479991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1480991554f2SKenneth D. Merry "NULL abort reply for tm %p TaskMID %u\n", 1481991554f2SKenneth D. Merry tm, le16toh(req->TaskMID)); 1482991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 1483991554f2SKenneth D. Merry /* this completion was due to a reset, just cleanup */ 1484991554f2SKenneth D. Merry targ->tm = NULL; 1485991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1486991554f2SKenneth D. Merry } 1487991554f2SKenneth D. Merry else { 1488991554f2SKenneth D. Merry /* we should have gotten a reply. */ 1489991554f2SKenneth D. Merry mpr_reinit(sc); 1490991554f2SKenneth D. Merry } 1491991554f2SKenneth D. Merry return; 1492991554f2SKenneth D. Merry } 1493991554f2SKenneth D. Merry 1494991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1495991554f2SKenneth D. Merry "abort TaskMID %u status 0x%x code 0x%x count %u\n", 1496991554f2SKenneth D. Merry le16toh(req->TaskMID), 1497991554f2SKenneth D. Merry le16toh(reply->IOCStatus), le32toh(reply->ResponseCode), 1498991554f2SKenneth D. Merry le32toh(reply->TerminationCount)); 1499991554f2SKenneth D. Merry 1500991554f2SKenneth D. Merry cm = TAILQ_FIRST(&tm->cm_targ->timedout_commands); 1501991554f2SKenneth D. Merry if (cm == NULL) { 1502991554f2SKenneth D. Merry /* if there are no more timedout commands, we're done with 1503991554f2SKenneth D. Merry * error recovery for this target. 1504991554f2SKenneth D. Merry */ 1505991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1506991554f2SKenneth D. Merry "finished recovery after aborting TaskMID %u\n", 1507991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1508991554f2SKenneth D. Merry 1509991554f2SKenneth D. Merry targ->tm = NULL; 1510991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 1511991554f2SKenneth D. Merry } 1512991554f2SKenneth D. Merry else if (le16toh(req->TaskMID) != cm->cm_desc.Default.SMID) { 1513991554f2SKenneth D. Merry /* abort success, but we have more timedout commands to abort */ 1514991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1515991554f2SKenneth D. Merry "continuing recovery after aborting TaskMID %u\n", 1516991554f2SKenneth D. Merry le16toh(req->TaskMID)); 1517991554f2SKenneth D. Merry 1518991554f2SKenneth D. Merry mprsas_send_abort(sc, tm, cm); 1519991554f2SKenneth D. Merry } 1520991554f2SKenneth D. Merry else { 1521991554f2SKenneth D. Merry /* we didn't get a command completion, so the abort 1522991554f2SKenneth D. Merry * failed as far as we're concerned. escalate. 1523991554f2SKenneth D. Merry */ 1524991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1525991554f2SKenneth D. Merry "abort failed for TaskMID %u tm %p\n", 1526991554f2SKenneth D. Merry le16toh(req->TaskMID), tm); 1527991554f2SKenneth D. Merry 1528991554f2SKenneth D. Merry mprsas_send_reset(sc, tm, 1529991554f2SKenneth D. Merry MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET); 1530991554f2SKenneth D. Merry } 1531991554f2SKenneth D. Merry } 1532991554f2SKenneth D. Merry 1533991554f2SKenneth D. Merry #define MPR_ABORT_TIMEOUT 5 1534991554f2SKenneth D. Merry 1535991554f2SKenneth D. Merry static int 1536991554f2SKenneth D. Merry mprsas_send_abort(struct mpr_softc *sc, struct mpr_command *tm, 1537991554f2SKenneth D. Merry struct mpr_command *cm) 1538991554f2SKenneth D. Merry { 1539991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 1540991554f2SKenneth D. Merry struct mprsas_target *targ; 1541991554f2SKenneth D. Merry int err; 1542991554f2SKenneth D. Merry 1543991554f2SKenneth D. Merry targ = cm->cm_targ; 1544991554f2SKenneth D. Merry if (targ->handle == 0) { 1545991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s null devhandle for target_id %d\n", 1546991554f2SKenneth D. Merry __func__, cm->cm_ccb->ccb_h.target_id); 1547991554f2SKenneth D. Merry return -1; 1548991554f2SKenneth D. Merry } 1549991554f2SKenneth D. Merry 1550991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY|MPR_INFO, 1551991554f2SKenneth D. Merry "Aborting command %p\n", cm); 1552991554f2SKenneth D. Merry 1553991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 1554991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1555991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 1556991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK; 1557991554f2SKenneth D. Merry 1558991554f2SKenneth D. Merry /* XXX Need to handle invalid LUNs */ 1559991554f2SKenneth D. Merry MPR_SET_LUN(req->LUN, cm->cm_ccb->ccb_h.target_lun); 1560991554f2SKenneth D. Merry 1561991554f2SKenneth D. Merry req->TaskMID = htole16(cm->cm_desc.Default.SMID); 1562991554f2SKenneth D. Merry 1563991554f2SKenneth D. Merry tm->cm_data = NULL; 1564991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 1565991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 1566991554f2SKenneth D. Merry tm->cm_complete = mprsas_abort_complete; 1567991554f2SKenneth D. Merry tm->cm_complete_data = (void *)tm; 1568991554f2SKenneth D. Merry tm->cm_targ = cm->cm_targ; 1569991554f2SKenneth D. Merry tm->cm_lun = cm->cm_lun; 1570991554f2SKenneth D. Merry 1571991554f2SKenneth D. Merry callout_reset(&tm->cm_callout, MPR_ABORT_TIMEOUT * hz, 1572991554f2SKenneth D. Merry mprsas_tm_timeout, tm); 1573991554f2SKenneth D. Merry 1574991554f2SKenneth D. Merry targ->aborts++; 1575991554f2SKenneth D. Merry 1576991554f2SKenneth D. Merry err = mpr_map_command(sc, tm); 1577991554f2SKenneth D. Merry if (err) 1578991554f2SKenneth D. Merry mprsas_log_command(tm, MPR_RECOVERY, 1579991554f2SKenneth D. Merry "error %d sending abort for cm %p SMID %u\n", 1580991554f2SKenneth D. Merry err, cm, req->TaskMID); 1581991554f2SKenneth D. Merry return err; 1582991554f2SKenneth D. Merry } 1583991554f2SKenneth D. Merry 1584991554f2SKenneth D. Merry 1585991554f2SKenneth D. Merry static void 1586991554f2SKenneth D. Merry mprsas_scsiio_timeout(void *data) 1587991554f2SKenneth D. Merry { 1588991554f2SKenneth D. Merry struct mpr_softc *sc; 1589991554f2SKenneth D. Merry struct mpr_command *cm; 1590991554f2SKenneth D. Merry struct mprsas_target *targ; 1591991554f2SKenneth D. Merry 1592991554f2SKenneth D. Merry cm = (struct mpr_command *)data; 1593991554f2SKenneth D. Merry sc = cm->cm_sc; 1594991554f2SKenneth D. Merry 1595991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1596991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1597991554f2SKenneth D. Merry 1598991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Timeout checking cm %p\n", cm); 1599991554f2SKenneth D. Merry 1600991554f2SKenneth D. Merry /* 1601991554f2SKenneth D. Merry * Run the interrupt handler to make sure it's not pending. This 1602991554f2SKenneth D. Merry * isn't perfect because the command could have already completed 1603991554f2SKenneth D. Merry * and been re-used, though this is unlikely. 1604991554f2SKenneth D. Merry */ 1605991554f2SKenneth D. Merry mpr_intr_locked(sc); 1606991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_FREE) { 1607991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 1608991554f2SKenneth D. Merry "SCSI command %p almost timed out\n", cm); 1609991554f2SKenneth D. Merry return; 1610991554f2SKenneth D. Merry } 1611991554f2SKenneth D. Merry 1612991554f2SKenneth D. Merry if (cm->cm_ccb == NULL) { 1613991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); 1614991554f2SKenneth D. Merry return; 1615991554f2SKenneth D. Merry } 1616991554f2SKenneth D. Merry 1617991554f2SKenneth D. Merry targ = cm->cm_targ; 1618991554f2SKenneth D. Merry targ->timeouts++; 1619991554f2SKenneth D. Merry 1620991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "command timeout cm %p ccb %p " 1621991554f2SKenneth D. Merry "target %u, handle(0x%04x)\n", cm, cm->cm_ccb, targ->tid, 1622991554f2SKenneth D. Merry targ->handle); 1623991554f2SKenneth D. Merry if (targ->encl_level_valid) { 1624991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 1625991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 1626991554f2SKenneth D. Merry targ->connector_name); 1627991554f2SKenneth D. Merry } 1628991554f2SKenneth D. Merry 1629991554f2SKenneth D. Merry /* XXX first, check the firmware state, to see if it's still 1630991554f2SKenneth D. Merry * operational. if not, do a diag reset. 1631991554f2SKenneth D. Merry */ 1632991554f2SKenneth D. Merry 1633991554f2SKenneth D. Merry cm->cm_ccb->ccb_h.status = CAM_CMD_TIMEOUT; 1634991554f2SKenneth D. Merry cm->cm_state = MPR_CM_STATE_TIMEDOUT; 1635991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->timedout_commands, cm, cm_recovery); 1636991554f2SKenneth D. Merry 1637991554f2SKenneth D. Merry if (targ->tm != NULL) { 1638991554f2SKenneth D. Merry /* target already in recovery, just queue up another 1639991554f2SKenneth D. Merry * timedout command to be processed later. 1640991554f2SKenneth D. Merry */ 1641991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "queued timedout cm %p for " 1642991554f2SKenneth D. Merry "processing by tm %p\n", cm, targ->tm); 1643991554f2SKenneth D. Merry } 1644991554f2SKenneth D. Merry else if ((targ->tm = mprsas_alloc_tm(sc)) != NULL) { 1645991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p allocated tm %p\n", 1646991554f2SKenneth D. Merry cm, targ->tm); 1647991554f2SKenneth D. Merry 1648991554f2SKenneth D. Merry /* start recovery by aborting the first timedout command */ 1649991554f2SKenneth D. Merry mprsas_send_abort(sc, targ->tm, cm); 1650991554f2SKenneth D. Merry } 1651991554f2SKenneth D. Merry else { 1652991554f2SKenneth D. Merry /* XXX queue this target up for recovery once a TM becomes 1653991554f2SKenneth D. Merry * available. The firmware only has a limited number of 1654991554f2SKenneth D. Merry * HighPriority credits for the high priority requests used 1655991554f2SKenneth D. Merry * for task management, and we ran out. 1656991554f2SKenneth D. Merry * 1657991554f2SKenneth D. Merry * Isilon: don't worry about this for now, since we have 1658991554f2SKenneth D. Merry * more credits than disks in an enclosure, and limit 1659991554f2SKenneth D. Merry * ourselves to one TM per target for recovery. 1660991554f2SKenneth D. Merry */ 1661991554f2SKenneth D. Merry mpr_dprint(sc, MPR_RECOVERY, 1662991554f2SKenneth D. Merry "timedout cm %p failed to allocate a tm\n", cm); 1663991554f2SKenneth D. Merry } 1664991554f2SKenneth D. Merry } 1665991554f2SKenneth D. Merry 1666991554f2SKenneth D. Merry static void 1667991554f2SKenneth D. Merry mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) 1668991554f2SKenneth D. Merry { 1669991554f2SKenneth D. Merry MPI2_SCSI_IO_REQUEST *req; 1670991554f2SKenneth D. Merry struct ccb_scsiio *csio; 1671991554f2SKenneth D. Merry struct mpr_softc *sc; 1672991554f2SKenneth D. Merry struct mprsas_target *targ; 1673991554f2SKenneth D. Merry struct mprsas_lun *lun; 1674991554f2SKenneth D. Merry struct mpr_command *cm; 1675991554f2SKenneth D. Merry uint8_t i, lba_byte, *ref_tag_addr; 1676991554f2SKenneth D. Merry uint16_t eedp_flags; 1677991554f2SKenneth D. Merry uint32_t mpi_control; 1678991554f2SKenneth D. Merry 1679991554f2SKenneth D. Merry sc = sassc->sc; 1680991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 1681991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 1682991554f2SKenneth D. Merry 1683991554f2SKenneth D. Merry csio = &ccb->csio; 1684991554f2SKenneth D. Merry targ = &sassc->targets[csio->ccb_h.target_id]; 1685991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "ccb %p target flag %x\n", ccb, targ->flags); 1686991554f2SKenneth D. Merry if (targ->handle == 0x0) { 1687991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s NULL handle for target %u\n", 1688991554f2SKenneth D. Merry __func__, csio->ccb_h.target_id); 1689991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1690991554f2SKenneth D. Merry xpt_done(ccb); 1691991554f2SKenneth D. Merry return; 1692991554f2SKenneth D. Merry } 1693991554f2SKenneth D. Merry if (targ->flags & MPR_TARGET_FLAGS_RAID_COMPONENT) { 1694991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s Raid component no SCSI IO " 1695991554f2SKenneth D. Merry "supported %u\n", __func__, csio->ccb_h.target_id); 1696991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1697991554f2SKenneth D. Merry xpt_done(ccb); 1698991554f2SKenneth D. Merry return; 1699991554f2SKenneth D. Merry } 1700991554f2SKenneth D. Merry /* 1701991554f2SKenneth D. Merry * Sometimes, it is possible to get a command that is not "In 1702991554f2SKenneth D. Merry * Progress" and was actually aborted by the upper layer. Check for 1703991554f2SKenneth D. Merry * this here and complete the command without error. 1704991554f2SKenneth D. Merry */ 1705991554f2SKenneth D. Merry if (ccb->ccb_h.status != CAM_REQ_INPROG) { 1706991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s Command is not in progress for " 1707991554f2SKenneth D. Merry "target %u\n", __func__, csio->ccb_h.target_id); 1708991554f2SKenneth D. Merry xpt_done(ccb); 1709991554f2SKenneth D. Merry return; 1710991554f2SKenneth D. Merry } 1711991554f2SKenneth D. Merry /* 1712991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't tell CAM 1713991554f2SKenneth D. Merry * that the volume has timed out. We want volumes to be enumerated 1714991554f2SKenneth D. Merry * until they are deleted/removed, not just failed. 1715991554f2SKenneth D. Merry */ 1716991554f2SKenneth D. Merry if (targ->flags & MPRSAS_TARGET_INREMOVAL) { 1717991554f2SKenneth D. Merry if (targ->devinfo == 0) 1718991554f2SKenneth D. Merry csio->ccb_h.status = CAM_REQ_CMP; 1719991554f2SKenneth D. Merry else 1720991554f2SKenneth D. Merry csio->ccb_h.status = CAM_SEL_TIMEOUT; 1721991554f2SKenneth D. Merry xpt_done(ccb); 1722991554f2SKenneth D. Merry return; 1723991554f2SKenneth D. Merry } 1724991554f2SKenneth D. Merry 1725991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_SHUTDOWN) != 0) { 1726991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, "%s shutting down\n", __func__); 1727991554f2SKenneth D. Merry csio->ccb_h.status = CAM_DEV_NOT_THERE; 1728991554f2SKenneth D. Merry xpt_done(ccb); 1729991554f2SKenneth D. Merry return; 1730991554f2SKenneth D. Merry } 1731991554f2SKenneth D. Merry 1732991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 1733991554f2SKenneth D. Merry if (cm == NULL || (sc->mpr_flags & MPR_FLAGS_DIAGRESET)) { 1734991554f2SKenneth D. Merry if (cm != NULL) { 1735991554f2SKenneth D. Merry mpr_free_command(sc, cm); 1736991554f2SKenneth D. Merry } 1737991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 1738991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 1739991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 1740991554f2SKenneth D. Merry } 1741991554f2SKenneth D. Merry ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 1742991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_REQUEUE_REQ; 1743991554f2SKenneth D. Merry xpt_done(ccb); 1744991554f2SKenneth D. Merry return; 1745991554f2SKenneth D. Merry } 1746991554f2SKenneth D. Merry 1747991554f2SKenneth D. Merry req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; 1748991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 1749991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 1750991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; 1751991554f2SKenneth D. Merry req->MsgFlags = 0; 1752991554f2SKenneth D. Merry req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); 1753991554f2SKenneth D. Merry req->SenseBufferLength = MPR_SENSE_LEN; 1754991554f2SKenneth D. Merry req->SGLFlags = 0; 1755991554f2SKenneth D. Merry req->ChainOffset = 0; 1756991554f2SKenneth D. Merry req->SGLOffset0 = 24; /* 32bit word offset to the SGL */ 1757991554f2SKenneth D. Merry req->SGLOffset1= 0; 1758991554f2SKenneth D. Merry req->SGLOffset2= 0; 1759991554f2SKenneth D. Merry req->SGLOffset3= 0; 1760991554f2SKenneth D. Merry req->SkipCount = 0; 1761991554f2SKenneth D. Merry req->DataLength = htole32(csio->dxfer_len); 1762991554f2SKenneth D. Merry req->BidirectionalDataLength = 0; 1763991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 1764991554f2SKenneth D. Merry req->EEDPFlags = 0; 1765991554f2SKenneth D. Merry 1766991554f2SKenneth D. Merry /* Note: BiDirectional transfers are not supported */ 1767991554f2SKenneth D. Merry switch (csio->ccb_h.flags & CAM_DIR_MASK) { 1768991554f2SKenneth D. Merry case CAM_DIR_IN: 1769991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_READ; 1770991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAIN; 1771991554f2SKenneth D. Merry break; 1772991554f2SKenneth D. Merry case CAM_DIR_OUT: 1773991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_WRITE; 1774991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_DATAOUT; 1775991554f2SKenneth D. Merry break; 1776991554f2SKenneth D. Merry case CAM_DIR_NONE: 1777991554f2SKenneth D. Merry default: 1778991554f2SKenneth D. Merry mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; 1779991554f2SKenneth D. Merry break; 1780991554f2SKenneth D. Merry } 1781991554f2SKenneth D. Merry 1782991554f2SKenneth D. Merry if (csio->cdb_len == 32) 1783991554f2SKenneth D. Merry mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; 1784991554f2SKenneth D. Merry /* 1785991554f2SKenneth D. Merry * It looks like the hardware doesn't require an explicit tag 1786991554f2SKenneth D. Merry * number for each transaction. SAM Task Management not supported 1787991554f2SKenneth D. Merry * at the moment. 1788991554f2SKenneth D. Merry */ 1789991554f2SKenneth D. Merry switch (csio->tag_action) { 1790991554f2SKenneth D. Merry case MSG_HEAD_OF_Q_TAG: 1791991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_HEADOFQ; 1792991554f2SKenneth D. Merry break; 1793991554f2SKenneth D. Merry case MSG_ORDERED_Q_TAG: 1794991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; 1795991554f2SKenneth D. Merry break; 1796991554f2SKenneth D. Merry case MSG_ACA_TASK: 1797991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_ACAQ; 1798991554f2SKenneth D. Merry break; 1799991554f2SKenneth D. Merry case CAM_TAG_ACTION_NONE: 1800991554f2SKenneth D. Merry case MSG_SIMPLE_Q_TAG: 1801991554f2SKenneth D. Merry default: 1802991554f2SKenneth D. Merry mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; 1803991554f2SKenneth D. Merry break; 1804991554f2SKenneth D. Merry } 1805991554f2SKenneth D. Merry mpi_control |= sc->mapping_table[csio->ccb_h.target_id].TLR_bits; 1806991554f2SKenneth D. Merry req->Control = htole32(mpi_control); 1807991554f2SKenneth D. Merry 1808991554f2SKenneth D. Merry if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { 1809991554f2SKenneth D. Merry mpr_free_command(sc, cm); 1810991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_LUN_INVALID; 1811991554f2SKenneth D. Merry xpt_done(ccb); 1812991554f2SKenneth D. Merry return; 1813991554f2SKenneth D. Merry } 1814991554f2SKenneth D. Merry 1815991554f2SKenneth D. Merry if (csio->ccb_h.flags & CAM_CDB_POINTER) 1816991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); 1817991554f2SKenneth D. Merry else 1818991554f2SKenneth D. Merry bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); 1819991554f2SKenneth D. Merry req->IoFlags = htole16(csio->cdb_len); 1820991554f2SKenneth D. Merry 1821991554f2SKenneth D. Merry /* 1822991554f2SKenneth D. Merry * Check if EEDP is supported and enabled. If it is then check if the 1823991554f2SKenneth D. Merry * SCSI opcode could be using EEDP. If so, make sure the LUN exists and 1824991554f2SKenneth D. Merry * is formatted for EEDP support. If all of this is true, set CDB up 1825991554f2SKenneth D. Merry * for EEDP transfer. 1826991554f2SKenneth D. Merry */ 1827991554f2SKenneth D. Merry eedp_flags = op_code_prot[req->CDB.CDB32[0]]; 1828991554f2SKenneth D. Merry if (sc->eedp_enabled && eedp_flags) { 1829991554f2SKenneth D. Merry SLIST_FOREACH(lun, &targ->luns, lun_link) { 1830991554f2SKenneth D. Merry if (lun->lun_id == csio->ccb_h.target_lun) { 1831991554f2SKenneth D. Merry break; 1832991554f2SKenneth D. Merry } 1833991554f2SKenneth D. Merry } 1834991554f2SKenneth D. Merry 1835991554f2SKenneth D. Merry if ((lun != NULL) && (lun->eedp_formatted)) { 1836991554f2SKenneth D. Merry req->EEDPBlockSize = htole16(lun->eedp_block_size); 1837991554f2SKenneth D. Merry eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | 1838991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | 1839991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); 1840991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 1841991554f2SKenneth D. Merry 1842991554f2SKenneth D. Merry /* 1843991554f2SKenneth D. Merry * If CDB less than 32, fill in Primary Ref Tag with 1844991554f2SKenneth D. Merry * low 4 bytes of LBA. If CDB is 32, tag stuff is 1845991554f2SKenneth D. Merry * already there. Also, set protection bit. FreeBSD 1846991554f2SKenneth D. Merry * currently does not support CDBs bigger than 16, but 1847991554f2SKenneth D. Merry * the code doesn't hurt, and will be here for the 1848991554f2SKenneth D. Merry * future. 1849991554f2SKenneth D. Merry */ 1850991554f2SKenneth D. Merry if (csio->cdb_len != 32) { 1851991554f2SKenneth D. Merry lba_byte = (csio->cdb_len == 16) ? 6 : 2; 1852991554f2SKenneth D. Merry ref_tag_addr = (uint8_t *)&req->CDB.EEDP32. 1853991554f2SKenneth D. Merry PrimaryReferenceTag; 1854991554f2SKenneth D. Merry for (i = 0; i < 4; i++) { 1855991554f2SKenneth D. Merry *ref_tag_addr = 1856991554f2SKenneth D. Merry req->CDB.CDB32[lba_byte + i]; 1857991554f2SKenneth D. Merry ref_tag_addr++; 1858991554f2SKenneth D. Merry } 1859991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryReferenceTag = 1860991554f2SKenneth D. Merry htole32(req-> 1861991554f2SKenneth D. Merry CDB.EEDP32.PrimaryReferenceTag); 1862991554f2SKenneth D. Merry req->CDB.EEDP32.PrimaryApplicationTagMask = 1863991554f2SKenneth D. Merry 0xFFFF; 1864991554f2SKenneth D. Merry req->CDB.CDB32[1] = (req->CDB.CDB32[1] & 0x1F) | 1865991554f2SKenneth D. Merry 0x20; 1866991554f2SKenneth D. Merry } else { 1867991554f2SKenneth D. Merry eedp_flags |= 1868991554f2SKenneth D. Merry MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG; 1869991554f2SKenneth D. Merry req->EEDPFlags = htole16(eedp_flags); 1870991554f2SKenneth D. Merry req->CDB.CDB32[10] = (req->CDB.CDB32[10] & 1871991554f2SKenneth D. Merry 0x1F) | 0x20; 1872991554f2SKenneth D. Merry } 1873991554f2SKenneth D. Merry } 1874991554f2SKenneth D. Merry } 1875991554f2SKenneth D. Merry 1876991554f2SKenneth D. Merry cm->cm_length = csio->dxfer_len; 1877991554f2SKenneth D. Merry if (cm->cm_length != 0) { 1878991554f2SKenneth D. Merry cm->cm_data = ccb; 1879991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_CCB; 1880991554f2SKenneth D. Merry } else { 1881991554f2SKenneth D. Merry cm->cm_data = NULL; 1882991554f2SKenneth D. Merry } 1883991554f2SKenneth D. Merry cm->cm_sge = &req->SGL; 1884991554f2SKenneth D. Merry cm->cm_sglsize = (32 - 24) * 4; 1885991554f2SKenneth D. Merry cm->cm_complete = mprsas_scsiio_complete; 1886991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 1887991554f2SKenneth D. Merry cm->cm_targ = targ; 1888991554f2SKenneth D. Merry cm->cm_lun = csio->ccb_h.target_lun; 1889991554f2SKenneth D. Merry cm->cm_ccb = ccb; 1890991554f2SKenneth D. Merry /* 1891991554f2SKenneth D. Merry * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) 1892991554f2SKenneth D. Merry * and set descriptor type. 1893991554f2SKenneth D. Merry */ 1894991554f2SKenneth D. Merry if (targ->scsi_req_desc_type == 1895991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { 1896991554f2SKenneth D. Merry req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; 1897991554f2SKenneth D. Merry cm->cm_desc.FastPathSCSIIO.RequestFlags = 1898991554f2SKenneth D. Merry MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; 1899991554f2SKenneth D. Merry cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle); 1900991554f2SKenneth D. Merry } else { 1901991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.RequestFlags = 1902991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; 1903991554f2SKenneth D. Merry cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); 1904991554f2SKenneth D. Merry } 1905991554f2SKenneth D. Merry 190685c9dd9dSSteven Hartland callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, 190785c9dd9dSSteven Hartland mprsas_scsiio_timeout, cm, 0); 1908991554f2SKenneth D. Merry 1909991554f2SKenneth D. Merry targ->issued++; 1910991554f2SKenneth D. Merry targ->outstanding++; 1911991554f2SKenneth D. Merry TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); 1912991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_SIM_QUEUED; 1913991554f2SKenneth D. Merry 1914991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", 1915991554f2SKenneth D. Merry __func__, cm, ccb, targ->outstanding); 1916991554f2SKenneth D. Merry 1917991554f2SKenneth D. Merry mpr_map_command(sc, cm); 1918991554f2SKenneth D. Merry return; 1919991554f2SKenneth D. Merry } 1920991554f2SKenneth D. Merry 1921991554f2SKenneth D. Merry static void 1922991554f2SKenneth D. Merry mpr_response_code(struct mpr_softc *sc, u8 response_code) 1923991554f2SKenneth D. Merry { 1924991554f2SKenneth D. Merry char *desc; 1925991554f2SKenneth D. Merry 1926991554f2SKenneth D. Merry switch (response_code) { 1927991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: 1928991554f2SKenneth D. Merry desc = "task management request completed"; 1929991554f2SKenneth D. Merry break; 1930991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: 1931991554f2SKenneth D. Merry desc = "invalid frame"; 1932991554f2SKenneth D. Merry break; 1933991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: 1934991554f2SKenneth D. Merry desc = "task management request not supported"; 1935991554f2SKenneth D. Merry break; 1936991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_FAILED: 1937991554f2SKenneth D. Merry desc = "task management request failed"; 1938991554f2SKenneth D. Merry break; 1939991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: 1940991554f2SKenneth D. Merry desc = "task management request succeeded"; 1941991554f2SKenneth D. Merry break; 1942991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: 1943991554f2SKenneth D. Merry desc = "invalid lun"; 1944991554f2SKenneth D. Merry break; 1945991554f2SKenneth D. Merry case 0xA: 1946991554f2SKenneth D. Merry desc = "overlapped tag attempted"; 1947991554f2SKenneth D. Merry break; 1948991554f2SKenneth D. Merry case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: 1949991554f2SKenneth D. Merry desc = "task queued, however not sent to target"; 1950991554f2SKenneth D. Merry break; 1951991554f2SKenneth D. Merry default: 1952991554f2SKenneth D. Merry desc = "unknown"; 1953991554f2SKenneth D. Merry break; 1954991554f2SKenneth D. Merry } 1955991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "response_code(0x%01x): %s\n", response_code, 1956991554f2SKenneth D. Merry desc); 1957991554f2SKenneth D. Merry } 1958991554f2SKenneth D. Merry 1959991554f2SKenneth D. Merry /** 1960991554f2SKenneth D. Merry * mpr_sc_failed_io_info - translated non-succesfull SCSI_IO request 1961991554f2SKenneth D. Merry */ 1962991554f2SKenneth D. Merry static void 1963991554f2SKenneth D. Merry mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, 1964991554f2SKenneth D. Merry Mpi2SCSIIOReply_t *mpi_reply, struct mprsas_target *targ) 1965991554f2SKenneth D. Merry { 1966991554f2SKenneth D. Merry u32 response_info; 1967991554f2SKenneth D. Merry u8 *response_bytes; 1968991554f2SKenneth D. Merry u16 ioc_status = le16toh(mpi_reply->IOCStatus) & 1969991554f2SKenneth D. Merry MPI2_IOCSTATUS_MASK; 1970991554f2SKenneth D. Merry u8 scsi_state = mpi_reply->SCSIState; 1971991554f2SKenneth D. Merry u8 scsi_status = mpi_reply->SCSIStatus; 1972991554f2SKenneth D. Merry char *desc_ioc_state = NULL; 1973991554f2SKenneth D. Merry char *desc_scsi_status = NULL; 1974991554f2SKenneth D. Merry char *desc_scsi_state = sc->tmp_string; 1975991554f2SKenneth D. Merry u32 log_info = le32toh(mpi_reply->IOCLogInfo); 1976991554f2SKenneth D. Merry 1977991554f2SKenneth D. Merry if (log_info == 0x31170000) 1978991554f2SKenneth D. Merry return; 1979991554f2SKenneth D. Merry 1980991554f2SKenneth D. Merry switch (ioc_status) { 1981991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 1982991554f2SKenneth D. Merry desc_ioc_state = "success"; 1983991554f2SKenneth D. Merry break; 1984991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 1985991554f2SKenneth D. Merry desc_ioc_state = "invalid function"; 1986991554f2SKenneth D. Merry break; 1987991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 1988991554f2SKenneth D. Merry desc_ioc_state = "scsi recovered error"; 1989991554f2SKenneth D. Merry break; 1990991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 1991991554f2SKenneth D. Merry desc_ioc_state = "scsi invalid dev handle"; 1992991554f2SKenneth D. Merry break; 1993991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 1994991554f2SKenneth D. Merry desc_ioc_state = "scsi device not there"; 1995991554f2SKenneth D. Merry break; 1996991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 1997991554f2SKenneth D. Merry desc_ioc_state = "scsi data overrun"; 1998991554f2SKenneth D. Merry break; 1999991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 2000991554f2SKenneth D. Merry desc_ioc_state = "scsi data underrun"; 2001991554f2SKenneth D. Merry break; 2002991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2003991554f2SKenneth D. Merry desc_ioc_state = "scsi io data error"; 2004991554f2SKenneth D. Merry break; 2005991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2006991554f2SKenneth D. Merry desc_ioc_state = "scsi protocol error"; 2007991554f2SKenneth D. Merry break; 2008991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 2009991554f2SKenneth D. Merry desc_ioc_state = "scsi task terminated"; 2010991554f2SKenneth D. Merry break; 2011991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2012991554f2SKenneth D. Merry desc_ioc_state = "scsi residual mismatch"; 2013991554f2SKenneth D. Merry break; 2014991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2015991554f2SKenneth D. Merry desc_ioc_state = "scsi task mgmt failed"; 2016991554f2SKenneth D. Merry break; 2017991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 2018991554f2SKenneth D. Merry desc_ioc_state = "scsi ioc terminated"; 2019991554f2SKenneth D. Merry break; 2020991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 2021991554f2SKenneth D. Merry desc_ioc_state = "scsi ext terminated"; 2022991554f2SKenneth D. Merry break; 2023991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: 2024991554f2SKenneth D. Merry desc_ioc_state = "eedp guard error"; 2025991554f2SKenneth D. Merry break; 2026991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: 2027991554f2SKenneth D. Merry desc_ioc_state = "eedp ref tag error"; 2028991554f2SKenneth D. Merry break; 2029991554f2SKenneth D. Merry case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: 2030991554f2SKenneth D. Merry desc_ioc_state = "eedp app tag error"; 2031991554f2SKenneth D. Merry break; 2032991554f2SKenneth D. Merry default: 2033991554f2SKenneth D. Merry desc_ioc_state = "unknown"; 2034991554f2SKenneth D. Merry break; 2035991554f2SKenneth D. Merry } 2036991554f2SKenneth D. Merry 2037991554f2SKenneth D. Merry switch (scsi_status) { 2038991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_GOOD: 2039991554f2SKenneth D. Merry desc_scsi_status = "good"; 2040991554f2SKenneth D. Merry break; 2041991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CHECK_CONDITION: 2042991554f2SKenneth D. Merry desc_scsi_status = "check condition"; 2043991554f2SKenneth D. Merry break; 2044991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_CONDITION_MET: 2045991554f2SKenneth D. Merry desc_scsi_status = "condition met"; 2046991554f2SKenneth D. Merry break; 2047991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_BUSY: 2048991554f2SKenneth D. Merry desc_scsi_status = "busy"; 2049991554f2SKenneth D. Merry break; 2050991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE: 2051991554f2SKenneth D. Merry desc_scsi_status = "intermediate"; 2052991554f2SKenneth D. Merry break; 2053991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: 2054991554f2SKenneth D. Merry desc_scsi_status = "intermediate condmet"; 2055991554f2SKenneth D. Merry break; 2056991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: 2057991554f2SKenneth D. Merry desc_scsi_status = "reservation conflict"; 2058991554f2SKenneth D. Merry break; 2059991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_COMMAND_TERMINATED: 2060991554f2SKenneth D. Merry desc_scsi_status = "command terminated"; 2061991554f2SKenneth D. Merry break; 2062991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_SET_FULL: 2063991554f2SKenneth D. Merry desc_scsi_status = "task set full"; 2064991554f2SKenneth D. Merry break; 2065991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_ACA_ACTIVE: 2066991554f2SKenneth D. Merry desc_scsi_status = "aca active"; 2067991554f2SKenneth D. Merry break; 2068991554f2SKenneth D. Merry case MPI2_SCSI_STATUS_TASK_ABORTED: 2069991554f2SKenneth D. Merry desc_scsi_status = "task aborted"; 2070991554f2SKenneth D. Merry break; 2071991554f2SKenneth D. Merry default: 2072991554f2SKenneth D. Merry desc_scsi_status = "unknown"; 2073991554f2SKenneth D. Merry break; 2074991554f2SKenneth D. Merry } 2075991554f2SKenneth D. Merry 2076991554f2SKenneth D. Merry desc_scsi_state[0] = '\0'; 2077991554f2SKenneth D. Merry if (!scsi_state) 2078991554f2SKenneth D. Merry desc_scsi_state = " "; 2079991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) 2080991554f2SKenneth D. Merry strcat(desc_scsi_state, "response info "); 2081991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_TERMINATED) 2082991554f2SKenneth D. Merry strcat(desc_scsi_state, "state terminated "); 2083991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) 2084991554f2SKenneth D. Merry strcat(desc_scsi_state, "no status "); 2085991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) 2086991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense failed "); 2087991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) 2088991554f2SKenneth D. Merry strcat(desc_scsi_state, "autosense valid "); 2089991554f2SKenneth D. Merry 2090991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\thandle(0x%04x), ioc_status(%s)(0x%04x)\n", 2091991554f2SKenneth D. Merry le16toh(mpi_reply->DevHandle), desc_ioc_state, ioc_status); 2092991554f2SKenneth D. Merry if (targ->encl_level_valid) { 2093991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "At enclosure level %d, slot %d, " 2094991554f2SKenneth D. Merry "connector name (%4s)\n", targ->encl_level, targ->encl_slot, 2095991554f2SKenneth D. Merry targ->connector_name); 2096991554f2SKenneth D. Merry } 2097991554f2SKenneth D. Merry /* We can add more detail about underflow data here 2098991554f2SKenneth D. Merry * TO-DO 2099991554f2SKenneth D. Merry * */ 2100991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "\tscsi_status(%s)(0x%02x), " 2101991554f2SKenneth D. Merry "scsi_state(%s)(0x%02x)\n", desc_scsi_status, scsi_status, 2102991554f2SKenneth D. Merry desc_scsi_state, scsi_state); 2103991554f2SKenneth D. Merry 2104991554f2SKenneth D. Merry if (sc->mpr_debug & MPR_XINFO && 2105991554f2SKenneth D. Merry scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2106991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : Start :\n"); 2107991554f2SKenneth D. Merry scsi_sense_print(csio); 2108991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "-> Sense Buffer Data : End :\n"); 2109991554f2SKenneth D. Merry } 2110991554f2SKenneth D. Merry 2111991554f2SKenneth D. Merry if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { 2112991554f2SKenneth D. Merry response_info = le32toh(mpi_reply->ResponseInfo); 2113991554f2SKenneth D. Merry response_bytes = (u8 *)&response_info; 2114991554f2SKenneth D. Merry mpr_response_code(sc,response_bytes[0]); 2115991554f2SKenneth D. Merry } 2116991554f2SKenneth D. Merry } 2117991554f2SKenneth D. Merry 2118991554f2SKenneth D. Merry static void 2119991554f2SKenneth D. Merry mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2120991554f2SKenneth D. Merry { 2121991554f2SKenneth D. Merry MPI2_SCSI_IO_REPLY *rep; 2122991554f2SKenneth D. Merry union ccb *ccb; 2123991554f2SKenneth D. Merry struct ccb_scsiio *csio; 2124991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2125991554f2SKenneth D. Merry struct scsi_vpd_supported_page_list *vpd_list = NULL; 2126991554f2SKenneth D. Merry u8 *TLR_bits, TLR_on; 2127991554f2SKenneth D. Merry int dir = 0, i; 2128991554f2SKenneth D. Merry u16 alloc_len; 2129991554f2SKenneth D. Merry 2130991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 2131991554f2SKenneth D. Merry mpr_dprint(sc, MPR_TRACE, 2132991554f2SKenneth D. Merry "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, 2133991554f2SKenneth D. Merry cm->cm_desc.Default.SMID, cm->cm_ccb, cm->cm_reply, 2134991554f2SKenneth D. Merry cm->cm_targ->outstanding); 2135991554f2SKenneth D. Merry 2136991554f2SKenneth D. Merry callout_stop(&cm->cm_callout); 2137991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 2138991554f2SKenneth D. Merry 2139991554f2SKenneth D. Merry sassc = sc->sassc; 2140991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 2141991554f2SKenneth D. Merry csio = &ccb->csio; 2142991554f2SKenneth D. Merry rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply; 2143991554f2SKenneth D. Merry /* 2144991554f2SKenneth D. Merry * XXX KDM if the chain allocation fails, does it matter if we do 2145991554f2SKenneth D. Merry * the sync and unload here? It is simpler to do it in every case, 2146991554f2SKenneth D. Merry * assuming it doesn't cause problems. 2147991554f2SKenneth D. Merry */ 2148991554f2SKenneth D. Merry if (cm->cm_data != NULL) { 2149991554f2SKenneth D. Merry if (cm->cm_flags & MPR_CM_FLAGS_DATAIN) 2150991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTREAD; 2151991554f2SKenneth D. Merry else if (cm->cm_flags & MPR_CM_FLAGS_DATAOUT) 2152991554f2SKenneth D. Merry dir = BUS_DMASYNC_POSTWRITE; 2153991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir); 2154991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2155991554f2SKenneth D. Merry } 2156991554f2SKenneth D. Merry 2157991554f2SKenneth D. Merry cm->cm_targ->completed++; 2158991554f2SKenneth D. Merry cm->cm_targ->outstanding--; 2159991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->commands, cm, cm_link); 2160991554f2SKenneth D. Merry ccb->ccb_h.status &= ~(CAM_STATUS_MASK | CAM_SIM_QUEUED); 2161991554f2SKenneth D. Merry 2162991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) { 2163991554f2SKenneth D. Merry TAILQ_REMOVE(&cm->cm_targ->timedout_commands, cm, cm_recovery); 2164991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2165991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2166991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery " 2167991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", cm, cm->cm_ccb, 2168991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, 2169991554f2SKenneth D. Merry rep->SCSIState, le32toh(rep->TransferCount)); 2170991554f2SKenneth D. Merry else 2171991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2172991554f2SKenneth D. Merry "completed timedout cm %p ccb %p during recovery\n", 2173991554f2SKenneth D. Merry cm, cm->cm_ccb); 2174991554f2SKenneth D. Merry } else if (cm->cm_targ->tm != NULL) { 2175991554f2SKenneth D. Merry if (cm->cm_reply != NULL) 2176991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2177991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery " 2178991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2179991554f2SKenneth D. Merry cm, cm->cm_ccb, le16toh(rep->IOCStatus), 2180991554f2SKenneth D. Merry rep->SCSIStatus, rep->SCSIState, 2181991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2182991554f2SKenneth D. Merry else 2183991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2184991554f2SKenneth D. Merry "completed cm %p ccb %p during recovery\n", 2185991554f2SKenneth D. Merry cm, cm->cm_ccb); 2186991554f2SKenneth D. Merry } else if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) { 2187991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_RECOVERY, 2188991554f2SKenneth D. Merry "reset completed cm %p ccb %p\n", cm, cm->cm_ccb); 2189991554f2SKenneth D. Merry } 2190991554f2SKenneth D. Merry 2191991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2192991554f2SKenneth D. Merry /* 2193991554f2SKenneth D. Merry * We ran into an error after we tried to map the command, 2194991554f2SKenneth D. Merry * so we're getting a callback without queueing the command 2195991554f2SKenneth D. Merry * to the hardware. So we set the status here, and it will 2196991554f2SKenneth D. Merry * be retained below. We'll go through the "fast path", 2197991554f2SKenneth D. Merry * because there can be no reply when we haven't actually 2198991554f2SKenneth D. Merry * gone out to the hardware. 2199991554f2SKenneth D. Merry */ 2200991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQUEUE_REQ; 2201991554f2SKenneth D. Merry 2202991554f2SKenneth D. Merry /* 2203991554f2SKenneth D. Merry * Currently the only error included in the mask is 2204991554f2SKenneth D. Merry * MPR_CM_FLAGS_CHAIN_FAILED, which means we're out of 2205991554f2SKenneth D. Merry * chain frames. We need to freeze the queue until we get 2206991554f2SKenneth D. Merry * a command that completed without this error, which will 2207991554f2SKenneth D. Merry * hopefully have some chain frames attached that we can 2208991554f2SKenneth D. Merry * use. If we wanted to get smarter about it, we would 2209991554f2SKenneth D. Merry * only unfreeze the queue in this condition when we're 2210991554f2SKenneth D. Merry * sure that we're getting some chain frames back. That's 2211991554f2SKenneth D. Merry * probably unnecessary. 2212991554f2SKenneth D. Merry */ 2213991554f2SKenneth D. Merry if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { 2214991554f2SKenneth D. Merry xpt_freeze_simq(sassc->sim, 1); 2215991554f2SKenneth D. Merry sassc->flags |= MPRSAS_QUEUE_FROZEN; 2216991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Error sending command, " 2217991554f2SKenneth D. Merry "freezing SIM queue\n"); 2218991554f2SKenneth D. Merry } 2219991554f2SKenneth D. Merry } 2220991554f2SKenneth D. Merry 2221991554f2SKenneth D. Merry /* 2222991554f2SKenneth D. Merry * If this is a Start Stop Unit command and it was issued by the driver 2223991554f2SKenneth D. Merry * during shutdown, decrement the refcount to account for all of the 2224991554f2SKenneth D. Merry * commands that were sent. All SSU commands should be completed before 2225991554f2SKenneth D. Merry * shutdown completes, meaning SSU_refcount will be 0 after SSU_started 2226991554f2SKenneth D. Merry * is TRUE. 2227991554f2SKenneth D. Merry */ 2228991554f2SKenneth D. Merry if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { 2229991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); 2230991554f2SKenneth D. Merry sc->SSU_refcount--; 2231991554f2SKenneth D. Merry } 2232991554f2SKenneth D. Merry 2233991554f2SKenneth D. Merry /* Take the fast path to completion */ 2234991554f2SKenneth D. Merry if (cm->cm_reply == NULL) { 2235991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG) { 2236991554f2SKenneth D. Merry if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) 2237991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SCSI_BUS_RESET; 2238991554f2SKenneth D. Merry else { 2239991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2240991554f2SKenneth D. Merry ccb->csio.scsi_status = SCSI_STATUS_OK; 2241991554f2SKenneth D. Merry } 2242991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2243991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2244991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2245991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 2246991554f2SKenneth D. Merry "Unfreezing SIM queue\n"); 2247991554f2SKenneth D. Merry } 2248991554f2SKenneth D. Merry } 2249991554f2SKenneth D. Merry 2250991554f2SKenneth D. Merry /* 2251991554f2SKenneth D. Merry * There are two scenarios where the status won't be 2252991554f2SKenneth D. Merry * CAM_REQ_CMP. The first is if MPR_CM_FLAGS_ERROR_MASK is 2253991554f2SKenneth D. Merry * set, the second is in the MPR_FLAGS_DIAGRESET above. 2254991554f2SKenneth D. Merry */ 2255991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2256991554f2SKenneth D. Merry /* 2257991554f2SKenneth D. Merry * Freeze the dev queue so that commands are 2258991554f2SKenneth D. Merry * executed in the correct order with after error 2259991554f2SKenneth D. Merry * recovery. 2260991554f2SKenneth D. Merry */ 2261991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2262991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2263991554f2SKenneth D. Merry } 2264991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2265991554f2SKenneth D. Merry xpt_done(ccb); 2266991554f2SKenneth D. Merry return; 2267991554f2SKenneth D. Merry } 2268991554f2SKenneth D. Merry 2269991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2270991554f2SKenneth D. Merry "ioc %x scsi %x state %x xfer %u\n", 2271991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2272991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2273991554f2SKenneth D. Merry 2274991554f2SKenneth D. Merry switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { 2275991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: 2276991554f2SKenneth D. Merry csio->resid = cm->cm_length - le32toh(rep->TransferCount); 2277991554f2SKenneth D. Merry /* FALLTHROUGH */ 2278991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SUCCESS: 2279991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: 2280991554f2SKenneth D. Merry 2281991554f2SKenneth D. Merry if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == 2282991554f2SKenneth D. Merry MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) 2283991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); 2284991554f2SKenneth D. Merry 2285991554f2SKenneth D. Merry /* Completion failed at the transport level. */ 2286991554f2SKenneth D. Merry if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | 2287991554f2SKenneth D. Merry MPI2_SCSI_STATE_TERMINATED)) { 2288991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2289991554f2SKenneth D. Merry break; 2290991554f2SKenneth D. Merry } 2291991554f2SKenneth D. Merry 2292991554f2SKenneth D. Merry /* In a modern packetized environment, an autosense failure 2293991554f2SKenneth D. Merry * implies that there's not much else that can be done to 2294991554f2SKenneth D. Merry * recover the command. 2295991554f2SKenneth D. Merry */ 2296991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED) { 2297991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_AUTOSENSE_FAIL; 2298991554f2SKenneth D. Merry break; 2299991554f2SKenneth D. Merry } 2300991554f2SKenneth D. Merry 2301991554f2SKenneth D. Merry /* 2302991554f2SKenneth D. Merry * CAM doesn't care about SAS Response Info data, but if this is 2303991554f2SKenneth D. Merry * the state check if TLR should be done. If not, clear the 2304991554f2SKenneth D. Merry * TLR_bits for the target. 2305991554f2SKenneth D. Merry */ 2306991554f2SKenneth D. Merry if ((rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) && 2307991554f2SKenneth D. Merry ((le32toh(rep->ResponseInfo) & MPI2_SCSI_RI_MASK_REASONCODE) 2308991554f2SKenneth D. Merry == MPR_SCSI_RI_INVALID_FRAME)) { 2309991554f2SKenneth D. Merry sc->mapping_table[csio->ccb_h.target_id].TLR_bits = 2310991554f2SKenneth D. Merry (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2311991554f2SKenneth D. Merry } 2312991554f2SKenneth D. Merry 2313991554f2SKenneth D. Merry /* 2314991554f2SKenneth D. Merry * Intentionally override the normal SCSI status reporting 2315991554f2SKenneth D. Merry * for these two cases. These are likely to happen in a 2316991554f2SKenneth D. Merry * multi-initiator environment, and we want to make sure that 2317991554f2SKenneth D. Merry * CAM retries these commands rather than fail them. 2318991554f2SKenneth D. Merry */ 2319991554f2SKenneth D. Merry if ((rep->SCSIStatus == MPI2_SCSI_STATUS_COMMAND_TERMINATED) || 2320991554f2SKenneth D. Merry (rep->SCSIStatus == MPI2_SCSI_STATUS_TASK_ABORTED)) { 2321991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2322991554f2SKenneth D. Merry break; 2323991554f2SKenneth D. Merry } 2324991554f2SKenneth D. Merry 2325991554f2SKenneth D. Merry /* Handle normal status and sense */ 2326991554f2SKenneth D. Merry csio->scsi_status = rep->SCSIStatus; 2327991554f2SKenneth D. Merry if (rep->SCSIStatus == MPI2_SCSI_STATUS_GOOD) 2328991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2329991554f2SKenneth D. Merry else 2330991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR; 2331991554f2SKenneth D. Merry 2332991554f2SKenneth D. Merry if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) { 2333991554f2SKenneth D. Merry int sense_len, returned_sense_len; 2334991554f2SKenneth D. Merry 2335991554f2SKenneth D. Merry returned_sense_len = min(le32toh(rep->SenseCount), 2336991554f2SKenneth D. Merry sizeof(struct scsi_sense_data)); 2337991554f2SKenneth D. Merry if (returned_sense_len < csio->sense_len) 2338991554f2SKenneth D. Merry csio->sense_resid = csio->sense_len - 2339991554f2SKenneth D. Merry returned_sense_len; 2340991554f2SKenneth D. Merry else 2341991554f2SKenneth D. Merry csio->sense_resid = 0; 2342991554f2SKenneth D. Merry 2343991554f2SKenneth D. Merry sense_len = min(returned_sense_len, 2344991554f2SKenneth D. Merry csio->sense_len - csio->sense_resid); 2345991554f2SKenneth D. Merry bzero(&csio->sense_data, sizeof(csio->sense_data)); 2346991554f2SKenneth D. Merry bcopy(cm->cm_sense, &csio->sense_data, sense_len); 2347991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_AUTOSNS_VALID; 2348991554f2SKenneth D. Merry } 2349991554f2SKenneth D. Merry 2350991554f2SKenneth D. Merry /* 2351991554f2SKenneth D. Merry * Check if this is an INQUIRY command. If it's a VPD inquiry, 2352991554f2SKenneth D. Merry * and it's page code 0 (Supported Page List), and there is 2353991554f2SKenneth D. Merry * inquiry data, and this is for a sequential access device, and 2354991554f2SKenneth D. Merry * the device is an SSP target, and TLR is supported by the 2355991554f2SKenneth D. Merry * controller, turn the TLR_bits value ON if page 0x90 is 2356991554f2SKenneth D. Merry * supported. 2357991554f2SKenneth D. Merry */ 2358991554f2SKenneth D. Merry if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && 2359991554f2SKenneth D. Merry (csio->cdb_io.cdb_bytes[1] & SI_EVPD) && 2360991554f2SKenneth D. Merry (csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && 2361991554f2SKenneth D. Merry ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && 2362d2b4e18bSKenneth D. Merry (csio->data_ptr != NULL) && 2363d2b4e18bSKenneth D. Merry ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && 2364d2b4e18bSKenneth D. Merry (sc->control_TLR) && 2365991554f2SKenneth D. Merry (sc->mapping_table[csio->ccb_h.target_id].device_info & 2366991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { 2367991554f2SKenneth D. Merry vpd_list = (struct scsi_vpd_supported_page_list *) 2368991554f2SKenneth D. Merry csio->data_ptr; 2369991554f2SKenneth D. Merry TLR_bits = &sc->mapping_table[csio->ccb_h.target_id]. 2370991554f2SKenneth D. Merry TLR_bits; 2371991554f2SKenneth D. Merry *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; 2372991554f2SKenneth D. Merry TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; 2373991554f2SKenneth D. Merry alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + 2374991554f2SKenneth D. Merry csio->cdb_io.cdb_bytes[4]; 2375d2b4e18bSKenneth D. Merry alloc_len -= csio->resid; 2376991554f2SKenneth D. Merry for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { 2377991554f2SKenneth D. Merry if (vpd_list->list[i] == 0x90) { 2378991554f2SKenneth D. Merry *TLR_bits = TLR_on; 2379991554f2SKenneth D. Merry break; 2380991554f2SKenneth D. Merry } 2381991554f2SKenneth D. Merry } 2382991554f2SKenneth D. Merry } 2383991554f2SKenneth D. Merry break; 2384991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: 2385991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: 2386991554f2SKenneth D. Merry /* 2387991554f2SKenneth D. Merry * If devinfo is 0 this will be a volume. In that case don't 2388991554f2SKenneth D. Merry * tell CAM that the volume is not there. We want volumes to 2389991554f2SKenneth D. Merry * be enumerated until they are deleted/removed, not just 2390991554f2SKenneth D. Merry * failed. 2391991554f2SKenneth D. Merry */ 2392991554f2SKenneth D. Merry if (cm->cm_targ->devinfo == 0) 2393991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2394991554f2SKenneth D. Merry else 2395991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2396991554f2SKenneth D. Merry break; 2397991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_SGL: 2398991554f2SKenneth D. Merry mpr_print_scsiio_cmd(sc, cm); 2399991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_UNREC_HBA_ERROR; 2400991554f2SKenneth D. Merry break; 2401991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: 2402991554f2SKenneth D. Merry /* 2403991554f2SKenneth D. Merry * This is one of the responses that comes back when an I/O 2404991554f2SKenneth D. Merry * has been aborted. If it is because of a timeout that we 2405991554f2SKenneth D. Merry * initiated, just set the status to CAM_CMD_TIMEOUT. 2406991554f2SKenneth D. Merry * Otherwise set it to CAM_REQ_ABORTED. The effect on the 2407991554f2SKenneth D. Merry * command is the same (it gets retried, subject to the 2408991554f2SKenneth D. Merry * retry counter), the only difference is what gets printed 2409991554f2SKenneth D. Merry * on the console. 2410991554f2SKenneth D. Merry */ 2411991554f2SKenneth D. Merry if (cm->cm_state == MPR_CM_STATE_TIMEDOUT) 2412991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_CMD_TIMEOUT; 2413991554f2SKenneth D. Merry else 2414991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_ABORTED; 2415991554f2SKenneth D. Merry break; 2416991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: 2417991554f2SKenneth D. Merry /* resid is ignored for this condition */ 2418991554f2SKenneth D. Merry csio->resid = 0; 2419991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DATA_RUN_ERR; 2420991554f2SKenneth D. Merry break; 2421991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: 2422991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: 2423991554f2SKenneth D. Merry /* 2424991554f2SKenneth D. Merry * Since these are generally external (i.e. hopefully 2425991554f2SKenneth D. Merry * transient transport-related) errors, retry these without 2426991554f2SKenneth D. Merry * decrementing the retry count. 2427991554f2SKenneth D. Merry */ 2428991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQUEUE_REQ; 2429991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_INFO, 2430991554f2SKenneth D. Merry "terminated ioc %x scsi %x state %x xfer %u\n", 2431991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2432991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2433991554f2SKenneth D. Merry break; 2434991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FUNCTION: 2435991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INTERNAL_ERROR: 2436991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_VPID: 2437991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_FIELD: 2438991554f2SKenneth D. Merry case MPI2_IOCSTATUS_INVALID_STATE: 2439991554f2SKenneth D. Merry case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: 2440991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: 2441991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: 2442991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: 2443991554f2SKenneth D. Merry case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: 2444991554f2SKenneth D. Merry default: 2445991554f2SKenneth D. Merry mprsas_log_command(cm, MPR_XINFO, 2446991554f2SKenneth D. Merry "completed ioc %x scsi %x state %x xfer %u\n", 2447991554f2SKenneth D. Merry le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, 2448991554f2SKenneth D. Merry le32toh(rep->TransferCount)); 2449991554f2SKenneth D. Merry csio->resid = cm->cm_length; 2450991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2451991554f2SKenneth D. Merry break; 2452991554f2SKenneth D. Merry } 2453991554f2SKenneth D. Merry 2454991554f2SKenneth D. Merry mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); 2455991554f2SKenneth D. Merry 2456991554f2SKenneth D. Merry if (sassc->flags & MPRSAS_QUEUE_FROZEN) { 2457991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_RELEASE_SIMQ; 2458991554f2SKenneth D. Merry sassc->flags &= ~MPRSAS_QUEUE_FROZEN; 2459991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "Command completed, unfreezing SIM " 2460991554f2SKenneth D. Merry "queue\n"); 2461991554f2SKenneth D. Merry } 2462991554f2SKenneth D. Merry 2463991554f2SKenneth D. Merry if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 2464991554f2SKenneth D. Merry ccb->ccb_h.status |= CAM_DEV_QFRZN; 2465991554f2SKenneth D. Merry xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); 2466991554f2SKenneth D. Merry } 2467991554f2SKenneth D. Merry 2468991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2469991554f2SKenneth D. Merry xpt_done(ccb); 2470991554f2SKenneth D. Merry } 2471991554f2SKenneth D. Merry 2472991554f2SKenneth D. Merry #if __FreeBSD_version >= 900026 2473991554f2SKenneth D. Merry static void 2474991554f2SKenneth D. Merry mprsas_smpio_complete(struct mpr_softc *sc, struct mpr_command *cm) 2475991554f2SKenneth D. Merry { 2476991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REPLY *rpl; 2477991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 2478991554f2SKenneth D. Merry uint64_t sasaddr; 2479991554f2SKenneth D. Merry union ccb *ccb; 2480991554f2SKenneth D. Merry 2481991554f2SKenneth D. Merry ccb = cm->cm_complete_data; 2482991554f2SKenneth D. Merry 2483991554f2SKenneth D. Merry /* 2484991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 2485991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and SMP 2486991554f2SKenneth D. Merry * commands require two S/G elements only. That should be handled 2487991554f2SKenneth D. Merry * in the standard request size. 2488991554f2SKenneth D. Merry */ 2489991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2490991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR,"%s: cm_flags = %#x on SMP request!\n", 2491991554f2SKenneth D. Merry __func__, cm->cm_flags); 2492991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2493991554f2SKenneth D. Merry goto bailout; 2494991554f2SKenneth D. Merry } 2495991554f2SKenneth D. Merry 2496991554f2SKenneth D. Merry rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply; 2497991554f2SKenneth D. Merry if (rpl == NULL) { 2498991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: NULL cm_reply!\n", __func__); 2499991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2500991554f2SKenneth D. Merry goto bailout; 2501991554f2SKenneth D. Merry } 2502991554f2SKenneth D. Merry 2503991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2504991554f2SKenneth D. Merry sasaddr = le32toh(req->SASAddress.Low); 2505991554f2SKenneth D. Merry sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32; 2506991554f2SKenneth D. Merry 2507991554f2SKenneth D. Merry if ((le16toh(rpl->IOCStatus) & MPI2_IOCSTATUS_MASK) != 2508991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS || 2509991554f2SKenneth D. Merry rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) { 2510991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: IOCStatus %04x SASStatus %02x\n", 2511991554f2SKenneth D. Merry __func__, le16toh(rpl->IOCStatus), rpl->SASStatus); 2512991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2513991554f2SKenneth D. Merry goto bailout; 2514991554f2SKenneth D. Merry } 2515991554f2SKenneth D. Merry 2516991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: SMP request to SAS address " 2517991554f2SKenneth D. Merry "%#jx completed successfully\n", __func__, (uintmax_t)sasaddr); 2518991554f2SKenneth D. Merry 2519991554f2SKenneth D. Merry if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED) 2520991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2521991554f2SKenneth D. Merry else 2522991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SMP_STATUS_ERROR; 2523991554f2SKenneth D. Merry 2524991554f2SKenneth D. Merry bailout: 2525991554f2SKenneth D. Merry /* 2526991554f2SKenneth D. Merry * We sync in both directions because we had DMAs in the S/G list 2527991554f2SKenneth D. Merry * in both directions. 2528991554f2SKenneth D. Merry */ 2529991554f2SKenneth D. Merry bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, 2530991554f2SKenneth D. Merry BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 2531991554f2SKenneth D. Merry bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap); 2532991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2533991554f2SKenneth D. Merry xpt_done(ccb); 2534991554f2SKenneth D. Merry } 2535991554f2SKenneth D. Merry 2536991554f2SKenneth D. Merry static void 2537991554f2SKenneth D. Merry mprsas_send_smpcmd(struct mprsas_softc *sassc, union ccb *ccb, 2538991554f2SKenneth D. Merry uint64_t sasaddr) 2539991554f2SKenneth D. Merry { 2540991554f2SKenneth D. Merry struct mpr_command *cm; 2541991554f2SKenneth D. Merry uint8_t *request, *response; 2542991554f2SKenneth D. Merry MPI2_SMP_PASSTHROUGH_REQUEST *req; 2543991554f2SKenneth D. Merry struct mpr_softc *sc; 2544991554f2SKenneth D. Merry struct sglist *sg; 2545991554f2SKenneth D. Merry int error; 2546991554f2SKenneth D. Merry 2547991554f2SKenneth D. Merry sc = sassc->sc; 2548991554f2SKenneth D. Merry sg = NULL; 2549991554f2SKenneth D. Merry error = 0; 2550991554f2SKenneth D. Merry 2551c503306dSKenneth D. Merry #if (__FreeBSD_version >= 1000028) || \ 2552c503306dSKenneth D. Merry ((__FreeBSD_version >= 902001) && (__FreeBSD_version < 1000000)) 2553991554f2SKenneth D. Merry switch (ccb->ccb_h.flags & CAM_DATA_MASK) { 2554991554f2SKenneth D. Merry case CAM_DATA_PADDR: 2555991554f2SKenneth D. Merry case CAM_DATA_SG_PADDR: 2556991554f2SKenneth D. Merry /* 2557991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 2558991554f2SKenneth D. Merry */ 2559991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: physical addresses not " 2560991554f2SKenneth D. Merry "supported\n", __func__); 2561991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2562991554f2SKenneth D. Merry xpt_done(ccb); 2563991554f2SKenneth D. Merry return; 2564991554f2SKenneth D. Merry case CAM_DATA_SG: 2565991554f2SKenneth D. Merry /* 2566991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 2567991554f2SKenneth D. Merry * request or response. 2568991554f2SKenneth D. Merry */ 2569991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 2570991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 2571991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2572991554f2SKenneth D. Merry "%s: multiple request or response buffer segments " 2573991554f2SKenneth D. Merry "not supported for SMP\n", __func__); 2574991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2575991554f2SKenneth D. Merry xpt_done(ccb); 2576991554f2SKenneth D. Merry return; 2577991554f2SKenneth D. Merry } 2578991554f2SKenneth D. Merry 2579991554f2SKenneth D. Merry /* 2580991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 2581991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 2582991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 2583991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 2584991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 2585991554f2SKenneth D. Merry * buffer. 2586991554f2SKenneth D. Merry */ 2587991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 2588991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 2589991554f2SKenneth D. Merry 2590991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 2591991554f2SKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; 2592991554f2SKenneth D. Merry } else 2593991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2594991554f2SKenneth D. Merry 2595991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 2596991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 2597991554f2SKenneth D. Merry 2598991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 2599991554f2SKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; 2600991554f2SKenneth D. Merry } else 2601991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2602991554f2SKenneth D. Merry break; 2603991554f2SKenneth D. Merry case CAM_DATA_VADDR: 2604991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2605991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2606991554f2SKenneth D. Merry break; 2607991554f2SKenneth D. Merry default: 2608991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2609991554f2SKenneth D. Merry xpt_done(ccb); 2610991554f2SKenneth D. Merry return; 2611991554f2SKenneth D. Merry } 2612c503306dSKenneth D. Merry #else /* __FreeBSD_version < 1000028 */ 2613991554f2SKenneth D. Merry /* 2614991554f2SKenneth D. Merry * XXX We don't yet support physical addresses here. 2615991554f2SKenneth D. Merry */ 2616991554f2SKenneth D. Merry if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) { 2617991554f2SKenneth D. Merry mpr_printf(sc, "%s: physical addresses not supported\n", 2618991554f2SKenneth D. Merry __func__); 2619991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2620991554f2SKenneth D. Merry xpt_done(ccb); 2621991554f2SKenneth D. Merry return; 2622991554f2SKenneth D. Merry } 2623991554f2SKenneth D. Merry 2624991554f2SKenneth D. Merry /* 2625991554f2SKenneth D. Merry * If the user wants to send an S/G list, check to make sure they 2626991554f2SKenneth D. Merry * have single buffers. 2627991554f2SKenneth D. Merry */ 2628991554f2SKenneth D. Merry if (ccb->ccb_h.flags & CAM_SCATTER_VALID) { 2629991554f2SKenneth D. Merry /* 2630991554f2SKenneth D. Merry * The chip does not support more than one buffer for the 2631991554f2SKenneth D. Merry * request or response. 2632991554f2SKenneth D. Merry */ 2633991554f2SKenneth D. Merry if ((ccb->smpio.smp_request_sglist_cnt > 1) 2634991554f2SKenneth D. Merry || (ccb->smpio.smp_response_sglist_cnt > 1)) { 2635991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: multiple request or " 2636991554f2SKenneth D. Merry "response buffer segments not supported for SMP\n", 2637991554f2SKenneth D. Merry __func__); 2638991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_INVALID; 2639991554f2SKenneth D. Merry xpt_done(ccb); 2640991554f2SKenneth D. Merry return; 2641991554f2SKenneth D. Merry } 2642991554f2SKenneth D. Merry 2643991554f2SKenneth D. Merry /* 2644991554f2SKenneth D. Merry * The CAM_SCATTER_VALID flag was originally implemented 2645991554f2SKenneth D. Merry * for the XPT_SCSI_IO CCB, which only has one data pointer. 2646991554f2SKenneth D. Merry * We have two. So, just take that flag to mean that we 2647991554f2SKenneth D. Merry * might have S/G lists, and look at the S/G segment count 2648991554f2SKenneth D. Merry * to figure out whether that is the case for each individual 2649991554f2SKenneth D. Merry * buffer. 2650991554f2SKenneth D. Merry */ 2651991554f2SKenneth D. Merry if (ccb->smpio.smp_request_sglist_cnt != 0) { 2652991554f2SKenneth D. Merry bus_dma_segment_t *req_sg; 2653991554f2SKenneth D. Merry 2654991554f2SKenneth D. Merry req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request; 2655c503306dSKenneth D. Merry request = (uint8_t *)(uintptr_t)req_sg[0].ds_addr; 2656991554f2SKenneth D. Merry } else 2657991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2658991554f2SKenneth D. Merry 2659991554f2SKenneth D. Merry if (ccb->smpio.smp_response_sglist_cnt != 0) { 2660991554f2SKenneth D. Merry bus_dma_segment_t *rsp_sg; 2661991554f2SKenneth D. Merry 2662991554f2SKenneth D. Merry rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response; 2663c503306dSKenneth D. Merry response = (uint8_t *)(uintptr_t)rsp_sg[0].ds_addr; 2664991554f2SKenneth D. Merry } else 2665991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2666991554f2SKenneth D. Merry } else { 2667991554f2SKenneth D. Merry request = ccb->smpio.smp_request; 2668991554f2SKenneth D. Merry response = ccb->smpio.smp_response; 2669991554f2SKenneth D. Merry } 2670c503306dSKenneth D. Merry #endif /* __FreeBSD_version < 1000028 */ 2671991554f2SKenneth D. Merry 2672991554f2SKenneth D. Merry cm = mpr_alloc_command(sc); 2673991554f2SKenneth D. Merry if (cm == NULL) { 2674991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2675991554f2SKenneth D. Merry "%s: cannot allocate command\n", __func__); 2676991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2677991554f2SKenneth D. Merry xpt_done(ccb); 2678991554f2SKenneth D. Merry return; 2679991554f2SKenneth D. Merry } 2680991554f2SKenneth D. Merry 2681991554f2SKenneth D. Merry req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req; 2682991554f2SKenneth D. Merry bzero(req, sizeof(*req)); 2683991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; 2684991554f2SKenneth D. Merry 2685991554f2SKenneth D. Merry /* Allow the chip to use any route to this SAS address. */ 2686991554f2SKenneth D. Merry req->PhysicalPort = 0xff; 2687991554f2SKenneth D. Merry 2688991554f2SKenneth D. Merry req->RequestDataLength = htole16(ccb->smpio.smp_request_len); 2689991554f2SKenneth D. Merry req->SGLFlags = 2690991554f2SKenneth D. Merry MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI; 2691991554f2SKenneth D. Merry 2692991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "%s: sending SMP request to SAS address " 2693991554f2SKenneth D. Merry "%#jx\n", __func__, (uintmax_t)sasaddr); 2694991554f2SKenneth D. Merry 2695991554f2SKenneth D. Merry mpr_init_sge(cm, req, &req->SGL); 2696991554f2SKenneth D. Merry 2697991554f2SKenneth D. Merry /* 2698991554f2SKenneth D. Merry * Set up a uio to pass into mpr_map_command(). This allows us to 2699991554f2SKenneth D. Merry * do one map command, and one busdma call in there. 2700991554f2SKenneth D. Merry */ 2701991554f2SKenneth D. Merry cm->cm_uio.uio_iov = cm->cm_iovec; 2702991554f2SKenneth D. Merry cm->cm_uio.uio_iovcnt = 2; 2703991554f2SKenneth D. Merry cm->cm_uio.uio_segflg = UIO_SYSSPACE; 2704991554f2SKenneth D. Merry 2705991554f2SKenneth D. Merry /* 2706991554f2SKenneth D. Merry * The read/write flag isn't used by busdma, but set it just in 2707991554f2SKenneth D. Merry * case. This isn't exactly accurate, either, since we're going in 2708991554f2SKenneth D. Merry * both directions. 2709991554f2SKenneth D. Merry */ 2710991554f2SKenneth D. Merry cm->cm_uio.uio_rw = UIO_WRITE; 2711991554f2SKenneth D. Merry 2712991554f2SKenneth D. Merry cm->cm_iovec[0].iov_base = request; 2713991554f2SKenneth D. Merry cm->cm_iovec[0].iov_len = le16toh(req->RequestDataLength); 2714991554f2SKenneth D. Merry cm->cm_iovec[1].iov_base = response; 2715991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len; 2716991554f2SKenneth D. Merry 2717991554f2SKenneth D. Merry cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len + 2718991554f2SKenneth D. Merry cm->cm_iovec[1].iov_len; 2719991554f2SKenneth D. Merry 2720991554f2SKenneth D. Merry /* 2721991554f2SKenneth D. Merry * Trigger a warning message in mpr_data_cb() for the user if we 2722991554f2SKenneth D. Merry * wind up exceeding two S/G segments. The chip expects one 2723991554f2SKenneth D. Merry * segment for the request and another for the response. 2724991554f2SKenneth D. Merry */ 2725991554f2SKenneth D. Merry cm->cm_max_segs = 2; 2726991554f2SKenneth D. Merry 2727991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 2728991554f2SKenneth D. Merry cm->cm_complete = mprsas_smpio_complete; 2729991554f2SKenneth D. Merry cm->cm_complete_data = ccb; 2730991554f2SKenneth D. Merry 2731991554f2SKenneth D. Merry /* 2732991554f2SKenneth D. Merry * Tell the mapping code that we're using a uio, and that this is 2733991554f2SKenneth D. Merry * an SMP passthrough request. There is a little special-case 2734991554f2SKenneth D. Merry * logic there (in mpr_data_cb()) to handle the bidirectional 2735991554f2SKenneth D. Merry * transfer. 2736991554f2SKenneth D. Merry */ 2737991554f2SKenneth D. Merry cm->cm_flags |= MPR_CM_FLAGS_USE_UIO | MPR_CM_FLAGS_SMP_PASS | 2738991554f2SKenneth D. Merry MPR_CM_FLAGS_DATAIN | MPR_CM_FLAGS_DATAOUT; 2739991554f2SKenneth D. Merry 2740991554f2SKenneth D. Merry /* The chip data format is little endian. */ 2741991554f2SKenneth D. Merry req->SASAddress.High = htole32(sasaddr >> 32); 2742991554f2SKenneth D. Merry req->SASAddress.Low = htole32(sasaddr); 2743991554f2SKenneth D. Merry 2744991554f2SKenneth D. Merry /* 2745991554f2SKenneth D. Merry * XXX Note that we don't have a timeout/abort mechanism here. 2746991554f2SKenneth D. Merry * From the manual, it looks like task management requests only 2747991554f2SKenneth D. Merry * work for SCSI IO and SATA passthrough requests. We may need to 2748991554f2SKenneth D. Merry * have a mechanism to retry requests in the event of a chip reset 2749991554f2SKenneth D. Merry * at least. Hopefully the chip will insure that any errors short 2750991554f2SKenneth D. Merry * of that are relayed back to the driver. 2751991554f2SKenneth D. Merry */ 2752991554f2SKenneth D. Merry error = mpr_map_command(sc, cm); 2753991554f2SKenneth D. Merry if ((error != 0) && (error != EINPROGRESS)) { 2754991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: error %d returned from " 2755991554f2SKenneth D. Merry "mpr_map_command()\n", __func__, error); 2756991554f2SKenneth D. Merry goto bailout_error; 2757991554f2SKenneth D. Merry } 2758991554f2SKenneth D. Merry 2759991554f2SKenneth D. Merry return; 2760991554f2SKenneth D. Merry 2761991554f2SKenneth D. Merry bailout_error: 2762991554f2SKenneth D. Merry mpr_free_command(sc, cm); 2763991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2764991554f2SKenneth D. Merry xpt_done(ccb); 2765991554f2SKenneth D. Merry return; 2766991554f2SKenneth D. Merry } 2767991554f2SKenneth D. Merry 2768991554f2SKenneth D. Merry static void 2769991554f2SKenneth D. Merry mprsas_action_smpio(struct mprsas_softc *sassc, union ccb *ccb) 2770991554f2SKenneth D. Merry { 2771991554f2SKenneth D. Merry struct mpr_softc *sc; 2772991554f2SKenneth D. Merry struct mprsas_target *targ; 2773991554f2SKenneth D. Merry uint64_t sasaddr = 0; 2774991554f2SKenneth D. Merry 2775991554f2SKenneth D. Merry sc = sassc->sc; 2776991554f2SKenneth D. Merry 2777991554f2SKenneth D. Merry /* 2778991554f2SKenneth D. Merry * Make sure the target exists. 2779991554f2SKenneth D. Merry */ 2780991554f2SKenneth D. Merry KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, 2781991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_SMP_IO\n", ccb->ccb_h.target_id)); 2782991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 2783991554f2SKenneth D. Merry if (targ->handle == 0x0) { 2784991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: target %d does not exist!\n", 2785991554f2SKenneth D. Merry __func__, ccb->ccb_h.target_id); 2786991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_SEL_TIMEOUT; 2787991554f2SKenneth D. Merry xpt_done(ccb); 2788991554f2SKenneth D. Merry return; 2789991554f2SKenneth D. Merry } 2790991554f2SKenneth D. Merry 2791991554f2SKenneth D. Merry /* 2792991554f2SKenneth D. Merry * If this device has an embedded SMP target, we'll talk to it 2793991554f2SKenneth D. Merry * directly. 2794991554f2SKenneth D. Merry * figure out what the expander's address is. 2795991554f2SKenneth D. Merry */ 2796991554f2SKenneth D. Merry if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0) 2797991554f2SKenneth D. Merry sasaddr = targ->sasaddr; 2798991554f2SKenneth D. Merry 2799991554f2SKenneth D. Merry /* 2800991554f2SKenneth D. Merry * If we don't have a SAS address for the expander yet, try 2801991554f2SKenneth D. Merry * grabbing it from the page 0x83 information cached in the 2802991554f2SKenneth D. Merry * transport layer for this target. LSI expanders report the 2803991554f2SKenneth D. Merry * expander SAS address as the port-associated SAS address in 2804991554f2SKenneth D. Merry * Inquiry VPD page 0x83. Maxim expanders don't report it in page 2805991554f2SKenneth D. Merry * 0x83. 2806991554f2SKenneth D. Merry * 2807991554f2SKenneth D. Merry * XXX KDM disable this for now, but leave it commented out so that 2808991554f2SKenneth D. Merry * it is obvious that this is another possible way to get the SAS 2809991554f2SKenneth D. Merry * address. 2810991554f2SKenneth D. Merry * 2811991554f2SKenneth D. Merry * The parent handle method below is a little more reliable, and 2812991554f2SKenneth D. Merry * the other benefit is that it works for devices other than SES 2813991554f2SKenneth D. Merry * devices. So you can send a SMP request to a da(4) device and it 2814991554f2SKenneth D. Merry * will get routed to the expander that device is attached to. 2815991554f2SKenneth D. Merry * (Assuming the da(4) device doesn't contain an SMP target...) 2816991554f2SKenneth D. Merry */ 2817991554f2SKenneth D. Merry #if 0 2818991554f2SKenneth D. Merry if (sasaddr == 0) 2819991554f2SKenneth D. Merry sasaddr = xpt_path_sas_addr(ccb->ccb_h.path); 2820991554f2SKenneth D. Merry #endif 2821991554f2SKenneth D. Merry 2822991554f2SKenneth D. Merry /* 2823991554f2SKenneth D. Merry * If we still don't have a SAS address for the expander, look for 2824991554f2SKenneth D. Merry * the parent device of this device, which is probably the expander. 2825991554f2SKenneth D. Merry */ 2826991554f2SKenneth D. Merry if (sasaddr == 0) { 2827991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 2828991554f2SKenneth D. Merry struct mprsas_target *parent_target; 2829991554f2SKenneth D. Merry #endif 2830991554f2SKenneth D. Merry 2831991554f2SKenneth D. Merry if (targ->parent_handle == 0x0) { 2832991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 2833991554f2SKenneth D. Merry "a valid parent handle!\n", __func__, targ->handle); 2834991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2835991554f2SKenneth D. Merry goto bailout; 2836991554f2SKenneth D. Merry } 2837991554f2SKenneth D. Merry #ifdef OLD_MPR_PROBE 2838991554f2SKenneth D. Merry parent_target = mprsas_find_target_by_handle(sassc, 0, 2839991554f2SKenneth D. Merry targ->parent_handle); 2840991554f2SKenneth D. Merry 2841991554f2SKenneth D. Merry if (parent_target == NULL) { 2842991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d does not have " 2843991554f2SKenneth D. Merry "a valid parent target!\n", __func__, targ->handle); 2844991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2845991554f2SKenneth D. Merry goto bailout; 2846991554f2SKenneth D. Merry } 2847991554f2SKenneth D. Merry 2848991554f2SKenneth D. Merry if ((parent_target->devinfo & 2849991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2850991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 2851991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 2852991554f2SKenneth D. Merry targ->handle, parent_target->handle); 2853991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2854991554f2SKenneth D. Merry goto bailout; 2855991554f2SKenneth D. Merry 2856991554f2SKenneth D. Merry } 2857991554f2SKenneth D. Merry 2858991554f2SKenneth D. Merry sasaddr = parent_target->sasaddr; 2859991554f2SKenneth D. Merry #else /* OLD_MPR_PROBE */ 2860991554f2SKenneth D. Merry if ((targ->parent_devinfo & 2861991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) { 2862991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent %d " 2863991554f2SKenneth D. Merry "does not have an SMP target!\n", __func__, 2864991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 2865991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2866991554f2SKenneth D. Merry goto bailout; 2867991554f2SKenneth D. Merry 2868991554f2SKenneth D. Merry } 2869991554f2SKenneth D. Merry if (targ->parent_sasaddr == 0x0) { 2870991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: handle %d parent handle " 2871991554f2SKenneth D. Merry "%d does not have a valid SAS address!\n", __func__, 2872991554f2SKenneth D. Merry targ->handle, targ->parent_handle); 2873991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2874991554f2SKenneth D. Merry goto bailout; 2875991554f2SKenneth D. Merry } 2876991554f2SKenneth D. Merry 2877991554f2SKenneth D. Merry sasaddr = targ->parent_sasaddr; 2878991554f2SKenneth D. Merry #endif /* OLD_MPR_PROBE */ 2879991554f2SKenneth D. Merry 2880991554f2SKenneth D. Merry } 2881991554f2SKenneth D. Merry 2882991554f2SKenneth D. Merry if (sasaddr == 0) { 2883991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "%s: unable to find SAS address for " 2884991554f2SKenneth D. Merry "handle %d\n", __func__, targ->handle); 2885991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_DEV_NOT_THERE; 2886991554f2SKenneth D. Merry goto bailout; 2887991554f2SKenneth D. Merry } 2888991554f2SKenneth D. Merry mprsas_send_smpcmd(sassc, ccb, sasaddr); 2889991554f2SKenneth D. Merry 2890991554f2SKenneth D. Merry return; 2891991554f2SKenneth D. Merry 2892991554f2SKenneth D. Merry bailout: 2893991554f2SKenneth D. Merry xpt_done(ccb); 2894991554f2SKenneth D. Merry 2895991554f2SKenneth D. Merry } 2896991554f2SKenneth D. Merry #endif //__FreeBSD_version >= 900026 2897991554f2SKenneth D. Merry 2898991554f2SKenneth D. Merry static void 2899991554f2SKenneth D. Merry mprsas_action_resetdev(struct mprsas_softc *sassc, union ccb *ccb) 2900991554f2SKenneth D. Merry { 2901991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2902991554f2SKenneth D. Merry struct mpr_softc *sc; 2903991554f2SKenneth D. Merry struct mpr_command *tm; 2904991554f2SKenneth D. Merry struct mprsas_target *targ; 2905991554f2SKenneth D. Merry 2906991554f2SKenneth D. Merry MPR_FUNCTRACE(sassc->sc); 2907991554f2SKenneth D. Merry mtx_assert(&sassc->sc->mpr_mtx, MA_OWNED); 2908991554f2SKenneth D. Merry 2909991554f2SKenneth D. Merry KASSERT(ccb->ccb_h.target_id < sassc->maxtargets, 2910991554f2SKenneth D. Merry ("Target %d out of bounds in XPT_RESET_DEV\n", 2911991554f2SKenneth D. Merry ccb->ccb_h.target_id)); 2912991554f2SKenneth D. Merry sc = sassc->sc; 2913991554f2SKenneth D. Merry tm = mpr_alloc_command(sc); 2914991554f2SKenneth D. Merry if (tm == NULL) { 2915991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, 2916991554f2SKenneth D. Merry "command alloc failure in mprsas_action_resetdev\n"); 2917991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_RESRC_UNAVAIL; 2918991554f2SKenneth D. Merry xpt_done(ccb); 2919991554f2SKenneth D. Merry return; 2920991554f2SKenneth D. Merry } 2921991554f2SKenneth D. Merry 2922991554f2SKenneth D. Merry targ = &sassc->targets[ccb->ccb_h.target_id]; 2923991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2924991554f2SKenneth D. Merry req->DevHandle = htole16(targ->handle); 2925991554f2SKenneth D. Merry req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; 2926991554f2SKenneth D. Merry req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; 2927991554f2SKenneth D. Merry 2928991554f2SKenneth D. Merry /* SAS Hard Link Reset / SATA Link Reset */ 2929991554f2SKenneth D. Merry req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; 2930991554f2SKenneth D. Merry 2931991554f2SKenneth D. Merry tm->cm_data = NULL; 2932991554f2SKenneth D. Merry tm->cm_desc.HighPriority.RequestFlags = 2933991554f2SKenneth D. Merry MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; 2934991554f2SKenneth D. Merry tm->cm_complete = mprsas_resetdev_complete; 2935991554f2SKenneth D. Merry tm->cm_complete_data = ccb; 2936991554f2SKenneth D. Merry tm->cm_targ = targ; 2937991554f2SKenneth D. Merry mpr_map_command(sc, tm); 2938991554f2SKenneth D. Merry } 2939991554f2SKenneth D. Merry 2940991554f2SKenneth D. Merry static void 2941991554f2SKenneth D. Merry mprsas_resetdev_complete(struct mpr_softc *sc, struct mpr_command *tm) 2942991554f2SKenneth D. Merry { 2943991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REPLY *resp; 2944991554f2SKenneth D. Merry union ccb *ccb; 2945991554f2SKenneth D. Merry 2946991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 2947991554f2SKenneth D. Merry mtx_assert(&sc->mpr_mtx, MA_OWNED); 2948991554f2SKenneth D. Merry 2949991554f2SKenneth D. Merry resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)tm->cm_reply; 2950991554f2SKenneth D. Merry ccb = tm->cm_complete_data; 2951991554f2SKenneth D. Merry 2952991554f2SKenneth D. Merry /* 2953991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 2954991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 2955991554f2SKenneth D. Merry * task management commands don't have S/G lists. 2956991554f2SKenneth D. Merry */ 2957991554f2SKenneth D. Merry if ((tm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 2958991554f2SKenneth D. Merry MPI2_SCSI_TASK_MANAGE_REQUEST *req; 2959991554f2SKenneth D. Merry 2960991554f2SKenneth D. Merry req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)tm->cm_req; 2961991554f2SKenneth D. Merry 2962991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for reset of " 2963991554f2SKenneth D. Merry "handle %#04x! This should not happen!\n", __func__, 2964991554f2SKenneth D. Merry tm->cm_flags, req->DevHandle); 2965991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2966991554f2SKenneth D. Merry goto bailout; 2967991554f2SKenneth D. Merry } 2968991554f2SKenneth D. Merry 2969991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 2970991554f2SKenneth D. Merry "%s: IOCStatus = 0x%x ResponseCode = 0x%x\n", __func__, 2971991554f2SKenneth D. Merry le16toh(resp->IOCStatus), le32toh(resp->ResponseCode)); 2972991554f2SKenneth D. Merry 2973991554f2SKenneth D. Merry if (le32toh(resp->ResponseCode) == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) { 2974991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP; 2975991554f2SKenneth D. Merry mprsas_announce_reset(sc, AC_SENT_BDR, tm->cm_targ->tid, 2976991554f2SKenneth D. Merry CAM_LUN_WILDCARD); 2977991554f2SKenneth D. Merry } 2978991554f2SKenneth D. Merry else 2979991554f2SKenneth D. Merry ccb->ccb_h.status = CAM_REQ_CMP_ERR; 2980991554f2SKenneth D. Merry 2981991554f2SKenneth D. Merry bailout: 2982991554f2SKenneth D. Merry 2983991554f2SKenneth D. Merry mprsas_free_tm(sc, tm); 2984991554f2SKenneth D. Merry xpt_done(ccb); 2985991554f2SKenneth D. Merry } 2986991554f2SKenneth D. Merry 2987991554f2SKenneth D. Merry static void 2988991554f2SKenneth D. Merry mprsas_poll(struct cam_sim *sim) 2989991554f2SKenneth D. Merry { 2990991554f2SKenneth D. Merry struct mprsas_softc *sassc; 2991991554f2SKenneth D. Merry 2992991554f2SKenneth D. Merry sassc = cam_sim_softc(sim); 2993991554f2SKenneth D. Merry 2994991554f2SKenneth D. Merry if (sassc->sc->mpr_debug & MPR_TRACE) { 2995991554f2SKenneth D. Merry /* frequent debug messages during a panic just slow 2996991554f2SKenneth D. Merry * everything down too much. 2997991554f2SKenneth D. Merry */ 2998991554f2SKenneth D. Merry mpr_printf(sassc->sc, "%s clearing MPR_TRACE\n", __func__); 2999991554f2SKenneth D. Merry sassc->sc->mpr_debug &= ~MPR_TRACE; 3000991554f2SKenneth D. Merry } 3001991554f2SKenneth D. Merry 3002991554f2SKenneth D. Merry mpr_intr_locked(sassc->sc); 3003991554f2SKenneth D. Merry } 3004991554f2SKenneth D. Merry 3005991554f2SKenneth D. Merry static void 3006991554f2SKenneth D. Merry mprsas_async(void *callback_arg, uint32_t code, struct cam_path *path, 3007991554f2SKenneth D. Merry void *arg) 3008991554f2SKenneth D. Merry { 3009991554f2SKenneth D. Merry struct mpr_softc *sc; 3010991554f2SKenneth D. Merry 3011991554f2SKenneth D. Merry sc = (struct mpr_softc *)callback_arg; 3012991554f2SKenneth D. Merry 3013991554f2SKenneth D. Merry switch (code) { 3014991554f2SKenneth D. Merry #if (__FreeBSD_version >= 1000006) || \ 3015991554f2SKenneth D. Merry ((__FreeBSD_version >= 901503) && (__FreeBSD_version < 1000000)) 3016991554f2SKenneth D. Merry case AC_ADVINFO_CHANGED: { 3017991554f2SKenneth D. Merry struct mprsas_target *target; 3018991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3019991554f2SKenneth D. Merry struct scsi_read_capacity_data_long rcap_buf; 3020991554f2SKenneth D. Merry struct ccb_dev_advinfo cdai; 3021991554f2SKenneth D. Merry struct mprsas_lun *lun; 3022991554f2SKenneth D. Merry lun_id_t lunid; 3023991554f2SKenneth D. Merry int found_lun; 3024991554f2SKenneth D. Merry uintptr_t buftype; 3025991554f2SKenneth D. Merry 3026991554f2SKenneth D. Merry buftype = (uintptr_t)arg; 3027991554f2SKenneth D. Merry 3028991554f2SKenneth D. Merry found_lun = 0; 3029991554f2SKenneth D. Merry sassc = sc->sassc; 3030991554f2SKenneth D. Merry 3031991554f2SKenneth D. Merry /* 3032991554f2SKenneth D. Merry * We're only interested in read capacity data changes. 3033991554f2SKenneth D. Merry */ 3034991554f2SKenneth D. Merry if (buftype != CDAI_TYPE_RCAPLONG) 3035991554f2SKenneth D. Merry break; 3036991554f2SKenneth D. Merry 3037991554f2SKenneth D. Merry /* 303807aa4de1SKenneth D. Merry * See the comment in mpr_attach_sas() for a detailed 303907aa4de1SKenneth D. Merry * explanation. In these versions of FreeBSD we register 304007aa4de1SKenneth D. Merry * for all events and filter out the events that don't 304107aa4de1SKenneth D. Merry * apply to us. 304207aa4de1SKenneth D. Merry */ 304307aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 304407aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 304507aa4de1SKenneth D. Merry if (xpt_path_path_id(path) != sassc->sim->path_id) 304607aa4de1SKenneth D. Merry break; 304707aa4de1SKenneth D. Merry #endif 304807aa4de1SKenneth D. Merry 304907aa4de1SKenneth D. Merry /* 3050991554f2SKenneth D. Merry * We should have a handle for this, but check to make sure. 3051991554f2SKenneth D. Merry */ 3052991554f2SKenneth D. Merry KASSERT(xpt_path_target_id(path) < sassc->maxtargets, 3053991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_async\n", 3054991554f2SKenneth D. Merry xpt_path_target_id(path))); 3055991554f2SKenneth D. Merry target = &sassc->targets[xpt_path_target_id(path)]; 3056991554f2SKenneth D. Merry if (target->handle == 0) 3057991554f2SKenneth D. Merry break; 3058991554f2SKenneth D. Merry 3059991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3060991554f2SKenneth D. Merry 3061991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3062991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3063991554f2SKenneth D. Merry found_lun = 1; 3064991554f2SKenneth D. Merry break; 3065991554f2SKenneth D. Merry } 3066991554f2SKenneth D. Merry } 3067991554f2SKenneth D. Merry 3068991554f2SKenneth D. Merry if (found_lun == 0) { 3069991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3070991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3071991554f2SKenneth D. Merry if (lun == NULL) { 3072991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc " 3073991554f2SKenneth D. Merry "LUN for EEDP support.\n"); 3074991554f2SKenneth D. Merry break; 3075991554f2SKenneth D. Merry } 3076991554f2SKenneth D. Merry lun->lun_id = lunid; 3077991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3078991554f2SKenneth D. Merry } 3079991554f2SKenneth D. Merry 3080991554f2SKenneth D. Merry bzero(&rcap_buf, sizeof(rcap_buf)); 3081991554f2SKenneth D. Merry xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 3082991554f2SKenneth D. Merry cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 3083991554f2SKenneth D. Merry cdai.ccb_h.flags = CAM_DIR_IN; 3084991554f2SKenneth D. Merry cdai.buftype = CDAI_TYPE_RCAPLONG; 3085*e8577fb4SKenneth D. Merry #if __FreeBSD_version >= 1100061 3086*e8577fb4SKenneth D. Merry cdai.flags = CDAI_FLAG_NONE; 3087*e8577fb4SKenneth D. Merry #else 3088991554f2SKenneth D. Merry cdai.flags = 0; 3089*e8577fb4SKenneth D. Merry #endif 3090991554f2SKenneth D. Merry cdai.bufsiz = sizeof(rcap_buf); 3091991554f2SKenneth D. Merry cdai.buf = (uint8_t *)&rcap_buf; 3092991554f2SKenneth D. Merry xpt_action((union ccb *)&cdai); 3093991554f2SKenneth D. Merry if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 3094991554f2SKenneth D. Merry cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 3095991554f2SKenneth D. Merry 3096991554f2SKenneth D. Merry if (((cdai.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) 3097991554f2SKenneth D. Merry && (rcap_buf.prot & SRC16_PROT_EN)) { 3098991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3099991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf.length); 3100991554f2SKenneth D. Merry } else { 3101991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3102991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3103991554f2SKenneth D. Merry } 3104991554f2SKenneth D. Merry break; 3105991554f2SKenneth D. Merry } 3106991554f2SKenneth D. Merry #endif 3107991554f2SKenneth D. Merry case AC_FOUND_DEVICE: { 3108991554f2SKenneth D. Merry struct ccb_getdev *cgd; 3109991554f2SKenneth D. Merry 311007aa4de1SKenneth D. Merry /* 311107aa4de1SKenneth D. Merry * See the comment in mpr_attach_sas() for a detailed 311207aa4de1SKenneth D. Merry * explanation. In these versions of FreeBSD we register 311307aa4de1SKenneth D. Merry * for all events and filter out the events that don't 311407aa4de1SKenneth D. Merry * apply to us. 311507aa4de1SKenneth D. Merry */ 311607aa4de1SKenneth D. Merry #if (__FreeBSD_version < 1000703) || \ 311707aa4de1SKenneth D. Merry ((__FreeBSD_version >= 1100000) && (__FreeBSD_version < 1100002)) 311807aa4de1SKenneth D. Merry if (xpt_path_path_id(path) != sc->sassc->sim->path_id) 311907aa4de1SKenneth D. Merry break; 312007aa4de1SKenneth D. Merry #endif 312107aa4de1SKenneth D. Merry 3122991554f2SKenneth D. Merry cgd = arg; 3123991554f2SKenneth D. Merry mprsas_prepare_ssu(sc, path, cgd); 312407aa4de1SKenneth D. Merry 3125991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3126991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3127991554f2SKenneth D. Merry mprsas_check_eedp(sc, path, cgd); 3128991554f2SKenneth D. Merry #endif 3129991554f2SKenneth D. Merry break; 3130991554f2SKenneth D. Merry } 3131991554f2SKenneth D. Merry default: 3132991554f2SKenneth D. Merry break; 3133991554f2SKenneth D. Merry } 3134991554f2SKenneth D. Merry } 3135991554f2SKenneth D. Merry 3136991554f2SKenneth D. Merry static void 3137991554f2SKenneth D. Merry mprsas_prepare_ssu(struct mpr_softc *sc, struct cam_path *path, 3138991554f2SKenneth D. Merry struct ccb_getdev *cgd) 3139991554f2SKenneth D. Merry { 3140991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 3141991554f2SKenneth D. Merry path_id_t pathid; 3142991554f2SKenneth D. Merry target_id_t targetid; 3143991554f2SKenneth D. Merry lun_id_t lunid; 3144991554f2SKenneth D. Merry struct mprsas_target *target; 3145991554f2SKenneth D. Merry struct mprsas_lun *lun; 3146991554f2SKenneth D. Merry uint8_t found_lun; 3147991554f2SKenneth D. Merry 3148991554f2SKenneth D. Merry sassc = sc->sassc; 3149991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 3150991554f2SKenneth D. Merry targetid = xpt_path_target_id(path); 3151991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3152991554f2SKenneth D. Merry 3153991554f2SKenneth D. Merry KASSERT(targetid < sassc->maxtargets, 3154991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_prepare_ssu\n", targetid)); 3155991554f2SKenneth D. Merry target = &sassc->targets[targetid]; 3156991554f2SKenneth D. Merry if (target->handle == 0x0) 3157991554f2SKenneth D. Merry return; 3158991554f2SKenneth D. Merry 3159991554f2SKenneth D. Merry /* 3160991554f2SKenneth D. Merry * If LUN is already in list, don't create a new one. 3161991554f2SKenneth D. Merry */ 3162991554f2SKenneth D. Merry found_lun = FALSE; 3163991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3164991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3165991554f2SKenneth D. Merry found_lun = TRUE; 3166991554f2SKenneth D. Merry break; 3167991554f2SKenneth D. Merry } 3168991554f2SKenneth D. Merry } 3169991554f2SKenneth D. Merry if (!found_lun) { 3170991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3171991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3172991554f2SKenneth D. Merry if (lun == NULL) { 3173991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " 3174991554f2SKenneth D. Merry "preparing SSU.\n"); 3175991554f2SKenneth D. Merry return; 3176991554f2SKenneth D. Merry } 3177991554f2SKenneth D. Merry lun->lun_id = lunid; 3178991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3179991554f2SKenneth D. Merry } 3180991554f2SKenneth D. Merry 3181991554f2SKenneth D. Merry /* 3182991554f2SKenneth D. Merry * If this is a SATA direct-access end device, mark it so that a SCSI 3183991554f2SKenneth D. Merry * StartStopUnit command will be sent to it when the driver is being 3184991554f2SKenneth D. Merry * shutdown. 3185991554f2SKenneth D. Merry */ 3186991554f2SKenneth D. Merry if (((cgd->inq_data.device & 0x1F) == T_DIRECT) && 3187991554f2SKenneth D. Merry (target->devinfo & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && 3188991554f2SKenneth D. Merry ((target->devinfo & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == 3189991554f2SKenneth D. Merry MPI2_SAS_DEVICE_INFO_END_DEVICE)) { 3190991554f2SKenneth D. Merry lun->stop_at_shutdown = TRUE; 3191991554f2SKenneth D. Merry } 3192991554f2SKenneth D. Merry } 3193991554f2SKenneth D. Merry 3194991554f2SKenneth D. Merry #if (__FreeBSD_version < 901503) || \ 3195991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) 3196991554f2SKenneth D. Merry static void 3197991554f2SKenneth D. Merry mprsas_check_eedp(struct mpr_softc *sc, struct cam_path *path, 3198991554f2SKenneth D. Merry struct ccb_getdev *cgd) 3199991554f2SKenneth D. Merry { 3200991554f2SKenneth D. Merry struct mprsas_softc *sassc = sc->sassc; 3201991554f2SKenneth D. Merry struct ccb_scsiio *csio; 3202991554f2SKenneth D. Merry struct scsi_read_capacity_16 *scsi_cmd; 3203991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3204991554f2SKenneth D. Merry path_id_t pathid; 3205991554f2SKenneth D. Merry target_id_t targetid; 3206991554f2SKenneth D. Merry lun_id_t lunid; 3207991554f2SKenneth D. Merry union ccb *ccb; 3208991554f2SKenneth D. Merry struct cam_path *local_path; 3209991554f2SKenneth D. Merry struct mprsas_target *target; 3210991554f2SKenneth D. Merry struct mprsas_lun *lun; 3211991554f2SKenneth D. Merry uint8_t found_lun; 3212991554f2SKenneth D. Merry char path_str[64]; 3213991554f2SKenneth D. Merry 3214991554f2SKenneth D. Merry sassc = sc->sassc; 3215991554f2SKenneth D. Merry pathid = cam_sim_path(sassc->sim); 3216991554f2SKenneth D. Merry targetid = xpt_path_target_id(path); 3217991554f2SKenneth D. Merry lunid = xpt_path_lun_id(path); 3218991554f2SKenneth D. Merry 3219991554f2SKenneth D. Merry KASSERT(targetid < sassc->maxtargets, 3220991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_check_eedp\n", targetid)); 3221991554f2SKenneth D. Merry target = &sassc->targets[targetid]; 3222991554f2SKenneth D. Merry if (target->handle == 0x0) 3223991554f2SKenneth D. Merry return; 3224991554f2SKenneth D. Merry 3225991554f2SKenneth D. Merry /* 3226991554f2SKenneth D. Merry * Determine if the device is EEDP capable. 3227991554f2SKenneth D. Merry * 3228991554f2SKenneth D. Merry * If this flag is set in the inquiry data, the device supports 3229991554f2SKenneth D. Merry * protection information, and must support the 16 byte read capacity 3230991554f2SKenneth D. Merry * command, otherwise continue without sending read cap 16 3231991554f2SKenneth D. Merry */ 3232991554f2SKenneth D. Merry if ((cgd->inq_data.spc3_flags & SPC3_SID_PROTECT) == 0) 3233991554f2SKenneth D. Merry return; 3234991554f2SKenneth D. Merry 3235991554f2SKenneth D. Merry /* 3236991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command. This info is used to determine if 3237991554f2SKenneth D. Merry * the LUN is formatted for EEDP support. 3238991554f2SKenneth D. Merry */ 3239991554f2SKenneth D. Merry ccb = xpt_alloc_ccb_nowait(); 3240991554f2SKenneth D. Merry if (ccb == NULL) { 3241991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc CCB for EEDP " 3242991554f2SKenneth D. Merry "support.\n"); 3243991554f2SKenneth D. Merry return; 3244991554f2SKenneth D. Merry } 3245991554f2SKenneth D. Merry 3246991554f2SKenneth D. Merry if (xpt_create_path(&local_path, xpt_periph, pathid, targetid, lunid) 3247991554f2SKenneth D. Merry != CAM_REQ_CMP) { 3248991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to create path for EEDP " 3249991554f2SKenneth D. Merry "support\n"); 3250991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3251991554f2SKenneth D. Merry return; 3252991554f2SKenneth D. Merry } 3253991554f2SKenneth D. Merry 3254991554f2SKenneth D. Merry /* 3255991554f2SKenneth D. Merry * If LUN is already in list, don't create a new one. 3256991554f2SKenneth D. Merry */ 3257991554f2SKenneth D. Merry found_lun = FALSE; 3258991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3259991554f2SKenneth D. Merry if (lun->lun_id == lunid) { 3260991554f2SKenneth D. Merry found_lun = TRUE; 3261991554f2SKenneth D. Merry break; 3262991554f2SKenneth D. Merry } 3263991554f2SKenneth D. Merry } 3264991554f2SKenneth D. Merry if (!found_lun) { 3265991554f2SKenneth D. Merry lun = malloc(sizeof(struct mprsas_lun), M_MPR, 3266991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3267991554f2SKenneth D. Merry if (lun == NULL) { 3268991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "Unable to alloc LUN for " 3269991554f2SKenneth D. Merry "EEDP support.\n"); 3270991554f2SKenneth D. Merry xpt_free_path(local_path); 3271991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3272991554f2SKenneth D. Merry return; 3273991554f2SKenneth D. Merry } 3274991554f2SKenneth D. Merry lun->lun_id = lunid; 3275991554f2SKenneth D. Merry SLIST_INSERT_HEAD(&target->luns, lun, lun_link); 3276991554f2SKenneth D. Merry } 3277991554f2SKenneth D. Merry 3278991554f2SKenneth D. Merry xpt_path_string(local_path, path_str, sizeof(path_str)); 3279991554f2SKenneth D. Merry mpr_dprint(sc, MPR_INFO, "Sending read cap: path %s handle %d\n", 3280991554f2SKenneth D. Merry path_str, target->handle); 3281991554f2SKenneth D. Merry 3282991554f2SKenneth D. Merry /* 3283991554f2SKenneth D. Merry * Issue a READ CAPACITY 16 command for the LUN. The 3284991554f2SKenneth D. Merry * mprsas_read_cap_done function will load the read cap info into the 3285991554f2SKenneth D. Merry * LUN struct. 3286991554f2SKenneth D. Merry */ 3287991554f2SKenneth D. Merry rcap_buf = malloc(sizeof(struct scsi_read_capacity_eedp), M_MPR, 3288991554f2SKenneth D. Merry M_NOWAIT | M_ZERO); 3289991554f2SKenneth D. Merry if (rcap_buf == NULL) { 3290991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Unable to alloc read capacity " 3291991554f2SKenneth D. Merry "buffer for EEDP support.\n"); 3292991554f2SKenneth D. Merry xpt_free_path(ccb->ccb_h.path); 3293991554f2SKenneth D. Merry xpt_free_ccb(ccb); 3294991554f2SKenneth D. Merry return; 3295991554f2SKenneth D. Merry } 3296991554f2SKenneth D. Merry xpt_setup_ccb(&ccb->ccb_h, local_path, CAM_PRIORITY_XPT); 3297991554f2SKenneth D. Merry csio = &ccb->csio; 3298991554f2SKenneth D. Merry csio->ccb_h.func_code = XPT_SCSI_IO; 3299991554f2SKenneth D. Merry csio->ccb_h.flags = CAM_DIR_IN; 3300991554f2SKenneth D. Merry csio->ccb_h.retry_count = 4; 3301991554f2SKenneth D. Merry csio->ccb_h.cbfcnp = mprsas_read_cap_done; 3302991554f2SKenneth D. Merry csio->ccb_h.timeout = 60000; 3303991554f2SKenneth D. Merry csio->data_ptr = (uint8_t *)rcap_buf; 3304991554f2SKenneth D. Merry csio->dxfer_len = sizeof(struct scsi_read_capacity_eedp); 3305991554f2SKenneth D. Merry csio->sense_len = MPR_SENSE_LEN; 3306991554f2SKenneth D. Merry csio->cdb_len = sizeof(*scsi_cmd); 3307991554f2SKenneth D. Merry csio->tag_action = MSG_SIMPLE_Q_TAG; 3308991554f2SKenneth D. Merry 3309991554f2SKenneth D. Merry scsi_cmd = (struct scsi_read_capacity_16 *)&csio->cdb_io.cdb_bytes; 3310991554f2SKenneth D. Merry bzero(scsi_cmd, sizeof(*scsi_cmd)); 3311991554f2SKenneth D. Merry scsi_cmd->opcode = 0x9E; 3312991554f2SKenneth D. Merry scsi_cmd->service_action = SRC16_SERVICE_ACTION; 3313991554f2SKenneth D. Merry ((uint8_t *)scsi_cmd)[13] = sizeof(struct scsi_read_capacity_eedp); 3314991554f2SKenneth D. Merry 3315991554f2SKenneth D. Merry ccb->ccb_h.ppriv_ptr1 = sassc; 3316991554f2SKenneth D. Merry xpt_action(ccb); 3317991554f2SKenneth D. Merry } 3318991554f2SKenneth D. Merry 3319991554f2SKenneth D. Merry static void 3320991554f2SKenneth D. Merry mprsas_read_cap_done(struct cam_periph *periph, union ccb *done_ccb) 3321991554f2SKenneth D. Merry { 3322991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3323991554f2SKenneth D. Merry struct mprsas_target *target; 3324991554f2SKenneth D. Merry struct mprsas_lun *lun; 3325991554f2SKenneth D. Merry struct scsi_read_capacity_eedp *rcap_buf; 3326991554f2SKenneth D. Merry 3327991554f2SKenneth D. Merry if (done_ccb == NULL) 3328991554f2SKenneth D. Merry return; 3329991554f2SKenneth D. Merry 3330991554f2SKenneth D. Merry /* Driver need to release devq, it Scsi command is 3331991554f2SKenneth D. Merry * generated by driver internally. 3332991554f2SKenneth D. Merry * Currently there is a single place where driver 3333991554f2SKenneth D. Merry * calls scsi command internally. In future if driver 3334991554f2SKenneth D. Merry * calls more scsi command internally, it needs to release 3335991554f2SKenneth D. Merry * devq internally, since those command will not go back to 3336991554f2SKenneth D. Merry * cam_periph. 3337991554f2SKenneth D. Merry */ 3338991554f2SKenneth D. Merry if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) ) { 3339991554f2SKenneth D. Merry done_ccb->ccb_h.status &= ~CAM_DEV_QFRZN; 3340991554f2SKenneth D. Merry xpt_release_devq(done_ccb->ccb_h.path, 3341991554f2SKenneth D. Merry /*count*/ 1, /*run_queue*/TRUE); 3342991554f2SKenneth D. Merry } 3343991554f2SKenneth D. Merry 3344991554f2SKenneth D. Merry rcap_buf = (struct scsi_read_capacity_eedp *)done_ccb->csio.data_ptr; 3345991554f2SKenneth D. Merry 3346991554f2SKenneth D. Merry /* 3347991554f2SKenneth D. Merry * Get the LUN ID for the path and look it up in the LUN list for the 3348991554f2SKenneth D. Merry * target. 3349991554f2SKenneth D. Merry */ 3350991554f2SKenneth D. Merry sassc = (struct mprsas_softc *)done_ccb->ccb_h.ppriv_ptr1; 3351991554f2SKenneth D. Merry KASSERT(done_ccb->ccb_h.target_id < sassc->maxtargets, 3352991554f2SKenneth D. Merry ("Target %d out of bounds in mprsas_read_cap_done\n", 3353991554f2SKenneth D. Merry done_ccb->ccb_h.target_id)); 3354991554f2SKenneth D. Merry target = &sassc->targets[done_ccb->ccb_h.target_id]; 3355991554f2SKenneth D. Merry SLIST_FOREACH(lun, &target->luns, lun_link) { 3356991554f2SKenneth D. Merry if (lun->lun_id != done_ccb->ccb_h.target_lun) 3357991554f2SKenneth D. Merry continue; 3358991554f2SKenneth D. Merry 3359991554f2SKenneth D. Merry /* 3360991554f2SKenneth D. Merry * Got the LUN in the target's LUN list. Fill it in with EEDP 3361991554f2SKenneth D. Merry * info. If the READ CAP 16 command had some SCSI error (common 3362991554f2SKenneth D. Merry * if command is not supported), mark the lun as not supporting 3363991554f2SKenneth D. Merry * EEDP and set the block size to 0. 3364991554f2SKenneth D. Merry */ 3365991554f2SKenneth D. Merry if (((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) 3366991554f2SKenneth D. Merry || (done_ccb->csio.scsi_status != SCSI_STATUS_OK)) { 3367991554f2SKenneth D. Merry lun->eedp_formatted = FALSE; 3368991554f2SKenneth D. Merry lun->eedp_block_size = 0; 3369991554f2SKenneth D. Merry break; 3370991554f2SKenneth D. Merry } 3371991554f2SKenneth D. Merry 3372991554f2SKenneth D. Merry if (rcap_buf->protect & 0x01) { 3373991554f2SKenneth D. Merry mpr_dprint(sassc->sc, MPR_INFO, "LUN %d for " 3374991554f2SKenneth D. Merry "target ID %d is formatted for EEDP " 3375991554f2SKenneth D. Merry "support.\n", done_ccb->ccb_h.target_lun, 3376991554f2SKenneth D. Merry done_ccb->ccb_h.target_id); 3377991554f2SKenneth D. Merry lun->eedp_formatted = TRUE; 3378991554f2SKenneth D. Merry lun->eedp_block_size = scsi_4btoul(rcap_buf->length); 3379991554f2SKenneth D. Merry } 3380991554f2SKenneth D. Merry break; 3381991554f2SKenneth D. Merry } 3382991554f2SKenneth D. Merry 3383991554f2SKenneth D. Merry // Finished with this CCB and path. 3384991554f2SKenneth D. Merry free(rcap_buf, M_MPR); 3385991554f2SKenneth D. Merry xpt_free_path(done_ccb->ccb_h.path); 3386991554f2SKenneth D. Merry xpt_free_ccb(done_ccb); 3387991554f2SKenneth D. Merry } 3388991554f2SKenneth D. Merry #endif /* (__FreeBSD_version < 901503) || \ 3389991554f2SKenneth D. Merry ((__FreeBSD_version >= 1000000) && (__FreeBSD_version < 1000006)) */ 3390991554f2SKenneth D. Merry 3391991554f2SKenneth D. Merry int 3392991554f2SKenneth D. Merry mprsas_startup(struct mpr_softc *sc) 3393991554f2SKenneth D. Merry { 3394991554f2SKenneth D. Merry /* 3395991554f2SKenneth D. Merry * Send the port enable message and set the wait_for_port_enable flag. 3396991554f2SKenneth D. Merry * This flag helps to keep the simq frozen until all discovery events 3397991554f2SKenneth D. Merry * are processed. 3398991554f2SKenneth D. Merry */ 3399991554f2SKenneth D. Merry sc->wait_for_port_enable = 1; 3400991554f2SKenneth D. Merry mprsas_send_portenable(sc); 3401991554f2SKenneth D. Merry return (0); 3402991554f2SKenneth D. Merry } 3403991554f2SKenneth D. Merry 3404991554f2SKenneth D. Merry static int 3405991554f2SKenneth D. Merry mprsas_send_portenable(struct mpr_softc *sc) 3406991554f2SKenneth D. Merry { 3407991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REQUEST *request; 3408991554f2SKenneth D. Merry struct mpr_command *cm; 3409991554f2SKenneth D. Merry 3410991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3411991554f2SKenneth D. Merry 3412991554f2SKenneth D. Merry if ((cm = mpr_alloc_command(sc)) == NULL) 3413991554f2SKenneth D. Merry return (EBUSY); 3414991554f2SKenneth D. Merry request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req; 3415991554f2SKenneth D. Merry request->Function = MPI2_FUNCTION_PORT_ENABLE; 3416991554f2SKenneth D. Merry request->MsgFlags = 0; 3417991554f2SKenneth D. Merry request->VP_ID = 0; 3418991554f2SKenneth D. Merry cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; 3419991554f2SKenneth D. Merry cm->cm_complete = mprsas_portenable_complete; 3420991554f2SKenneth D. Merry cm->cm_data = NULL; 3421991554f2SKenneth D. Merry cm->cm_sge = NULL; 3422991554f2SKenneth D. Merry 3423991554f2SKenneth D. Merry mpr_map_command(sc, cm); 3424991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, 3425991554f2SKenneth D. Merry "mpr_send_portenable finished cm %p req %p complete %p\n", 3426991554f2SKenneth D. Merry cm, cm->cm_req, cm->cm_complete); 3427991554f2SKenneth D. Merry return (0); 3428991554f2SKenneth D. Merry } 3429991554f2SKenneth D. Merry 3430991554f2SKenneth D. Merry static void 3431991554f2SKenneth D. Merry mprsas_portenable_complete(struct mpr_softc *sc, struct mpr_command *cm) 3432991554f2SKenneth D. Merry { 3433991554f2SKenneth D. Merry MPI2_PORT_ENABLE_REPLY *reply; 3434991554f2SKenneth D. Merry struct mprsas_softc *sassc; 3435991554f2SKenneth D. Merry 3436991554f2SKenneth D. Merry MPR_FUNCTRACE(sc); 3437991554f2SKenneth D. Merry sassc = sc->sassc; 3438991554f2SKenneth D. Merry 3439991554f2SKenneth D. Merry /* 3440991554f2SKenneth D. Merry * Currently there should be no way we can hit this case. It only 3441991554f2SKenneth D. Merry * happens when we have a failure to allocate chain frames, and 3442991554f2SKenneth D. Merry * port enable commands don't have S/G lists. 3443991554f2SKenneth D. Merry */ 3444991554f2SKenneth D. Merry if ((cm->cm_flags & MPR_CM_FLAGS_ERROR_MASK) != 0) { 3445991554f2SKenneth D. Merry mpr_dprint(sc, MPR_ERROR, "%s: cm_flags = %#x for port enable! " 3446991554f2SKenneth D. Merry "This should not happen!\n", __func__, cm->cm_flags); 3447991554f2SKenneth D. Merry } 3448991554f2SKenneth D. Merry 3449991554f2SKenneth D. Merry reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply; 3450991554f2SKenneth D. Merry if (reply == NULL) 3451991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable NULL reply\n"); 3452991554f2SKenneth D. Merry else if (le16toh(reply->IOCStatus & MPI2_IOCSTATUS_MASK) != 3453991554f2SKenneth D. Merry MPI2_IOCSTATUS_SUCCESS) 3454991554f2SKenneth D. Merry mpr_dprint(sc, MPR_FAULT, "Portenable failed\n"); 3455991554f2SKenneth D. Merry 3456991554f2SKenneth D. Merry mpr_free_command(sc, cm); 3457991554f2SKenneth D. Merry if (sc->mpr_ich.ich_arg != NULL) { 3458991554f2SKenneth D. Merry mpr_dprint(sc, MPR_XINFO, "disestablish config intrhook\n"); 3459991554f2SKenneth D. Merry config_intrhook_disestablish(&sc->mpr_ich); 3460991554f2SKenneth D. Merry sc->mpr_ich.ich_arg = NULL; 3461991554f2SKenneth D. Merry } 3462991554f2SKenneth D. Merry 3463991554f2SKenneth D. Merry /* 3464991554f2SKenneth D. Merry * Done waiting for port enable to complete. Decrement the refcount. 3465991554f2SKenneth D. Merry * If refcount is 0, discovery is complete and a rescan of the bus can 3466991554f2SKenneth D. Merry * take place. 3467991554f2SKenneth D. Merry */ 3468991554f2SKenneth D. Merry sc->wait_for_port_enable = 0; 3469991554f2SKenneth D. Merry sc->port_enable_complete = 1; 3470991554f2SKenneth D. Merry wakeup(&sc->port_enable_complete); 3471991554f2SKenneth D. Merry mprsas_startup_decrement(sassc); 3472991554f2SKenneth D. Merry } 3473991554f2SKenneth D. Merry 3474991554f2SKenneth D. Merry int 3475991554f2SKenneth D. Merry mprsas_check_id(struct mprsas_softc *sassc, int id) 3476991554f2SKenneth D. Merry { 3477991554f2SKenneth D. Merry struct mpr_softc *sc = sassc->sc; 3478991554f2SKenneth D. Merry char *ids; 3479991554f2SKenneth D. Merry char *name; 3480991554f2SKenneth D. Merry 3481991554f2SKenneth D. Merry ids = &sc->exclude_ids[0]; 3482991554f2SKenneth D. Merry while((name = strsep(&ids, ",")) != NULL) { 3483991554f2SKenneth D. Merry if (name[0] == '\0') 3484991554f2SKenneth D. Merry continue; 3485991554f2SKenneth D. Merry if (strtol(name, NULL, 0) == (long)id) 3486991554f2SKenneth D. Merry return (1); 3487991554f2SKenneth D. Merry } 3488991554f2SKenneth D. Merry 3489991554f2SKenneth D. Merry return (0); 3490991554f2SKenneth D. Merry } 3491