summaryrefslogtreecommitdiffstats
path: root/sys/cam/ctl/scsi_ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/ctl/scsi_ctl.c')
-rw-r--r--sys/cam/ctl/scsi_ctl.c104
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);
OpenPOWER on IntegriCloud