diff options
Diffstat (limited to 'sys/cam/ctl/scsi_ctl.c')
-rw-r--r-- | sys/cam/ctl/scsi_ctl.c | 104 |
1 files changed, 51 insertions, 53 deletions
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c index f273958..0ff7b30 100644 --- a/sys/cam/ctl/scsi_ctl.c +++ b/sys/cam/ctl/scsi_ctl.c @@ -721,15 +721,18 @@ ctlfedata(struct ctlfe_lun_softc *softc, union ctl_io *io, idx = cmd_info->cur_transfer_index; off = cmd_info->cur_transfer_off; cmd_info->flags &= ~CTLFE_CMD_PIECEWISE; - if (io->scsiio.kern_sg_entries == 0) { - /* No S/G list. */ + if (io->scsiio.kern_sg_entries == 0) { /* No S/G list. */ + + /* One time shift for SRR offset. */ + off += io->scsiio.ext_data_filled; + io->scsiio.ext_data_filled = 0; + *data_ptr = io->scsiio.kern_data_ptr + off; if (io->scsiio.kern_data_len - off <= bus_softc->maxio) { *dxfer_len = io->scsiio.kern_data_len - off; } else { *dxfer_len = bus_softc->maxio; - cmd_info->cur_transfer_index = -1; - cmd_info->cur_transfer_off = bus_softc->maxio; + cmd_info->cur_transfer_off += bus_softc->maxio; cmd_info->flags |= CTLFE_CMD_PIECEWISE; } *sglist_cnt = 0; @@ -738,9 +741,18 @@ ctlfedata(struct ctlfe_lun_softc *softc, union ctl_io *io, *flags |= CAM_DATA_PADDR; else *flags |= CAM_DATA_VADDR; - } else { - /* S/G list with physical or virtual pointers. */ + } else { /* S/G list with physical or virtual pointers. */ ctl_sglist = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; + + /* One time shift for SRR offset. */ + while (io->scsiio.ext_data_filled >= ctl_sglist[idx].len - off) { + io->scsiio.ext_data_filled -= ctl_sglist[idx].len - off; + idx++; + off = 0; + } + off += io->scsiio.ext_data_filled; + io->scsiio.ext_data_filled = 0; + cam_sglist = cmd_info->cam_sglist; *dxfer_len = 0; for (i = 0; i < io->scsiio.kern_sg_entries - idx; i++) { @@ -818,18 +830,8 @@ ctlfestart(struct cam_periph *periph, union ccb *start_ccb) /* * Datamove call, we need to setup the S/G list. */ - scsi_status = 0; - csio->cdb_len = atio->cdb_len; ctlfedata(softc, io, &flags, &data_ptr, &dxfer_len, &csio->sglist_cnt); - io->scsiio.ext_data_filled += dxfer_len; - if (io->scsiio.ext_data_filled > io->scsiio.kern_total_len) { - xpt_print(periph->path, "%s: tag 0x%04x " - "fill len %u > total %u\n", - __func__, io->scsiio.tag_num, - io->scsiio.ext_data_filled, - io->scsiio.kern_total_len); - } } else { /* * We're done, send status back. @@ -891,8 +893,8 @@ ctlfestart(struct cam_periph *periph, union ccb *start_ccb) data_ptr = NULL; dxfer_len = 0; csio->sglist_cnt = 0; - scsi_status = 0; } + scsi_status = 0; if ((io->io_hdr.flags & CTL_FLAG_STATUS_QUEUED) && (cmd_info->flags & CTLFE_CMD_PIECEWISE) == 0 && ((io->io_hdr.flags & CTL_FLAG_DMA_QUEUED) == 0 || @@ -1246,13 +1248,36 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) | (done_ccb->csio.msg_ptr[6]); } + /* + * If we have an SRR and we're still sending data, we + * should be able to adjust offsets and cycle again. + * It is possible only if offset is from this datamove. + */ + if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) && + srr_off >= io->scsiio.kern_rel_offset && + srr_off < io->scsiio.kern_rel_offset + + io->scsiio.kern_data_len) { + io->scsiio.kern_data_resid = + io->scsiio.kern_rel_offset + + io->scsiio.kern_data_len - srr_off; + io->scsiio.ext_data_filled = srr_off; + io->scsiio.io_hdr.status = CTL_STATUS_NONE; + io->io_hdr.flags |= CTL_FLAG_DMA_QUEUED; + softc->ccbs_freed++; + xpt_release_ccb(done_ccb); + TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h, + periph_links.tqe); + xpt_schedule(periph, /*priority*/ 1); + break; + } + + /* + * If status was being sent, the back end data is now history. + * Hack it up and resubmit a new command with the CDB adjusted. + * If the SIM does the right thing, all of the resid math + * should work. + */ if (srr && (io->io_hdr.flags & CTL_FLAG_DMA_INPROG) == 0) { - /* - * If status was being sent, the back end data is now - * history. Hack it up and resubmit a new command with - * the CDB adjusted. If the SIM does the right thing, - * all of the resid math should work. - */ softc->ccbs_freed++; xpt_release_ccb(done_ccb); if (ctlfe_adjust_cdb(atio, srr_off) == 0) { @@ -1262,22 +1287,6 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) /* * Fall through to doom.... */ - } else if (srr) { - /* - * If we have an srr and we're still sending data, we - * should be able to adjust offsets and cycle again. - */ - io->scsiio.kern_rel_offset = - io->scsiio.ext_data_filled = srr_off; - io->scsiio.ext_data_len = io->scsiio.kern_total_len - - io->scsiio.kern_rel_offset; - softc->ccbs_freed++; - io->scsiio.io_hdr.status = CTL_STATUS_NONE; - xpt_release_ccb(done_ccb); - TAILQ_INSERT_HEAD(&softc->work_queue, &atio->ccb_h, - periph_links.tqe); - xpt_schedule(periph, /*priority*/ 1); - break; } if ((done_ccb->ccb_h.flags & CAM_SEND_STATUS) && @@ -1320,16 +1329,6 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) io->io_hdr.flags &= ~CTL_FLAG_DMA_INPROG; - io->scsiio.ext_data_len += csio->dxfer_len; - if (io->scsiio.ext_data_len > - io->scsiio.kern_total_len) { - xpt_print(periph->path, "%s: tag 0x%04x " - "done len %u > total %u sent %u\n", - __func__, io->scsiio.tag_num, - io->scsiio.ext_data_len, - io->scsiio.kern_total_len, - io->scsiio.ext_data_filled); - } /* * Translate CAM status to CTL status. Success * does not change the overall, ctl_io status. In @@ -1339,6 +1338,7 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) */ switch (done_ccb->ccb_h.status & CAM_STATUS_MASK) { case CAM_REQ_CMP: + io->scsiio.kern_data_resid -= csio->dxfer_len; io->io_hdr.port_status = 0; break; default: @@ -1368,7 +1368,6 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) if ((cmd_info->flags & CTLFE_CMD_PIECEWISE) && (io->io_hdr.port_status == 0)) { ccb_flags flags; - uint8_t scsi_status; uint8_t *data_ptr; uint32_t dxfer_len; @@ -1379,8 +1378,6 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) ctlfedata(softc, io, &flags, &data_ptr, &dxfer_len, &csio->sglist_cnt); - scsi_status = 0; - if (((flags & CAM_SEND_STATUS) == 0) && (dxfer_len == 0)) { printf("%s: tag %04x no status or " @@ -1400,7 +1397,7 @@ ctlfedone(struct cam_periph *periph, union ccb *done_ccb) MSG_SIMPLE_Q_TAG : 0, atio->tag_id, atio->init_id, - scsi_status, + 0, /*data_ptr*/ data_ptr, /*dxfer_len*/ dxfer_len, /*timeout*/ 5 * 1000); @@ -2002,6 +1999,7 @@ ctlfe_datamove(union ctl_io *io) KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Unexpected io_type (%d) in ctlfe_datamove", io->io_hdr.io_type)); + io->scsiio.ext_data_filled = 0; ccb = PRIV_CCB(io); periph = xpt_path_periph(ccb->ccb_h.path); cam_periph_lock(periph); |