diff --git a/sys/dev/mpi3mr/mpi3mr_cam.c b/sys/dev/mpi3mr/mpi3mr_cam.c --- a/sys/dev/mpi3mr/mpi3mr_cam.c +++ b/sys/dev/mpi3mr/mpi3mr_cam.c @@ -86,6 +86,8 @@ #define smp_processor_id() PCPU_GET(cpuid) +static void +mpi3mr_enqueue_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm); static int mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm); void @@ -123,13 +125,22 @@ sc = cm->sc; scsiio_req = (Mpi3SCSIIORequest_t *) &cm->io_request; + /* + * When there's any error in mapping, we just abort and fail the + * request. There's no other state we need to deal with at this level. + * The only failures that should be passed in are fatal. EINPROGRESS + * is never passed here (it defers the callback to when the mapping + * completes). + */ if (error) { cm->error_code = error; - device_printf(sc->mpi3mr_dev, "%s: error=%d\n",__func__, error); + device_printf(sc->mpi3mr_dev, "%s: mapping error=%d\n",__func__, error); if (error == EFBIG) { - cm->ccb->ccb_h.status = CAM_REQ_TOO_BIG; - return; + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_TOO_BIG); + } else { + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); } + return; } if (cm->data_dir == MPI3MR_READ) @@ -152,21 +163,29 @@ sg_local = (U8 *)&scsiio_req->SGL; - if (!scsiio_req->DataLength) { + if (scsiio_req->DataLength == 0) { mpi3mr_build_zero_len_sge(sg_local); - return; + goto enqueue; } sges_left = nsegs; + // XXX busdma is supposed to ensure these can't happen. These checks + // would be better as asserts. For now, fail safe. The nsegs == 0 + // case only happens when error != 0. nsegs < 0 is a bug in busdma. + // nsegs > the max is a busdma bug since we asked it not to do that. if (sges_left < 0) { printf("scsi_dma_map failed: request for %d bytes!\n", scsiio_req->DataLength); + cm->error_code = EINVAL; + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); return; } if (sges_left > MPI3MR_SG_DEPTH) { printf("scsi_dma_map returned unsupported sge count %d!\n", sges_left); + cm->error_code = EINVAL; + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); return; } @@ -218,10 +237,21 @@ i++; } +enqueue: + /* + * Now that we've created the sgls, we send the request to the device. + * Unlike in Linux, dmaload isn't guaranteed to load every time, but + * this function is always called when the resources are available, so + * we can send the request to hardware here always. mpi3mr_map_request + * knows about this quirk and will only take evasive action when an + * error other than EINPROGRESS is returned from dmaload. + */ + mpi3mr_enqueue_request(sc, cm); + return; } -int +static int mpi3mr_map_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm) { u_int32_t retcode = 0; @@ -232,18 +262,16 @@ retcode = bus_dmamap_load_ccb(sc->buffer_dmat, cm->dmamap, cm->ccb, mpi3mr_prepare_sgls, cm, 0); mtx_unlock(&sc->io_lock); - if (retcode) + if (retcode != 0 && retcode != EINPROGRESS) device_printf(sc->mpi3mr_dev, "bus_dmamap_load(): retcode = %d\n", retcode); - if (retcode == EINPROGRESS) { - device_printf(sc->mpi3mr_dev, "request load in progress\n"); - xpt_freeze_simq(sc->cam_sc->sim, 1); - } } - if (cm->error_code) + + if (cm->error_code) { /* ccb status set in mpi3mr_prepare_sgls */ return cm->error_code; - if (retcode) - mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); + } + if (retcode != 0 && retcode != EINPROGRESS) + mpi3mr_set_ccbstatus(cm->ccb, CAM_REQ_INVALID); return (retcode); } @@ -912,12 +940,7 @@ struct mpi3mr_cmd *cm; uint8_t scsi_opcode, queue_idx; uint32_t mpi_control; - struct mpi3mr_op_req_queue *opreqq = NULL; - U32 data_len_blks = 0; - U32 tracked_io_sz = 0; - U32 ioc_pend_data_len = 0, tg_pend_data_len = 0; - struct mpi3mr_throttle_group_info *tg = NULL; - static int ratelimit; + int error; sc = cam_sc->sc; mtx_assert(&sc->mpi3mr_mtx, MA_OWNED); @@ -1137,17 +1160,30 @@ } /* Prepare SGEs */ - if (mpi3mr_map_request(sc, cm)) { + error = mpi3mr_map_request(sc, cm); + if (error != 0 && error != EINPROGRESS) { mpi3mr_release_command(cm); xpt_done(ccb); printf("func: %s line: %d Build SGLs failed\n", __func__, __LINE__); return; } - - opreqq = &sc->op_req_q[queue_idx]; +} + +static void +mpi3mr_enqueue_request(struct mpi3mr_softc *sc, struct mpi3mr_cmd *cm) +{ + static int ratelimit; + struct mpi3mr_op_req_queue *opreqq = &sc->op_req_q[cm->req_qidx]; + struct mpi3mr_throttle_group_info *tg = NULL; + uint32_t data_len_blks = 0; + uint32_t tracked_io_sz = 0; + uint32_t ioc_pend_data_len = 0, tg_pend_data_len = 0; + struct mpi3mr_target *targ = cm->targ; + union ccb *ccb = cm->ccb; + Mpi3SCSIIORequest_t *req = (Mpi3SCSIIORequest_t *)&cm->io_request; if (sc->iot_enable) { - data_len_blks = csio->dxfer_len >> 9; + data_len_blks = ccb->csio.dxfer_len >> 9; if ((data_len_blks >= sc->io_throttle_data_length) && targ->io_throttle_enabled) { @@ -1208,10 +1244,9 @@ if (targ->io_divert) { req->MsgFlags |= MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; - mpi_control |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING; + req->Flags = htole32(le32toh(req->Flags) | MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING); } } - req->Flags = htole32(mpi_control); if (mpi3mr_submit_io(sc, opreqq, (U8 *)&cm->io_request)) {