summaryrefslogtreecommitdiffstats
path: root/sys/cam/ctl/ctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cam/ctl/ctl.c')
-rw-r--r--sys/cam/ctl/ctl.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 4cbc14f..126c95b85 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -5174,6 +5174,40 @@ ctl_config_write_done(union ctl_io *io)
free(buf, M_CTL);
}
+void
+ctl_config_read_done(union ctl_io *io)
+{
+ uint8_t *buf;
+
+ /*
+ * If there is some error -- we are done, skip data transfer.
+ */
+ if ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0 ||
+ ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE &&
+ (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) {
+ if (io->io_hdr.flags & CTL_FLAG_ALLOCATED)
+ buf = io->scsiio.kern_data_ptr;
+ else
+ buf = NULL;
+ ctl_done(io);
+ if (buf)
+ free(buf, M_CTL);
+ return;
+ }
+
+ /*
+ * If the IO_CONT flag is set, we need to call the supplied
+ * function to continue processing the I/O, instead of completing
+ * the I/O just yet.
+ */
+ if (io->io_hdr.flags & CTL_FLAG_IO_CONT) {
+ io->scsiio.io_cont(io);
+ return;
+ }
+
+ ctl_datamove(io);
+}
+
/*
* SCSI release command.
*/
@@ -7175,6 +7209,66 @@ ctl_read_capacity_16(struct ctl_scsiio *ctsio)
}
int
+ctl_get_lba_status(struct ctl_scsiio *ctsio)
+{
+ struct scsi_get_lba_status *cdb;
+ struct scsi_get_lba_status_data *data;
+ struct ctl_lun *lun;
+ struct ctl_lba_len_flags *lbalen;
+ uint64_t lba;
+ uint32_t alloc_len, total_len;
+ int retval;
+
+ CTL_DEBUG_PRINT(("ctl_get_lba_status\n"));
+
+ lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
+ cdb = (struct scsi_get_lba_status *)ctsio->cdb;
+ lba = scsi_8btou64(cdb->addr);
+ alloc_len = scsi_4btoul(cdb->alloc_len);
+
+ if (lba > lun->be_lun->maxlba) {
+ ctl_set_lba_out_of_range(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ total_len = sizeof(*data) + sizeof(data->descr[0]);
+ ctsio->kern_data_ptr = malloc(total_len, M_CTL, M_WAITOK | M_ZERO);
+ data = (struct scsi_get_lba_status_data *)ctsio->kern_data_ptr;
+
+ if (total_len < alloc_len) {
+ ctsio->residual = alloc_len - total_len;
+ ctsio->kern_data_len = total_len;
+ ctsio->kern_total_len = total_len;
+ } else {
+ ctsio->residual = 0;
+ ctsio->kern_data_len = alloc_len;
+ ctsio->kern_total_len = alloc_len;
+ }
+ ctsio->kern_data_resid = 0;
+ ctsio->kern_rel_offset = 0;
+ ctsio->kern_sg_entries = 0;
+
+ /* Fill dummy data in case backend can't tell anything. */
+ scsi_ulto4b(4 + sizeof(data->descr[0]), data->length);
+ scsi_u64to8b(lba, data->descr[0].addr);
+ scsi_ulto4b(MIN(UINT32_MAX, lun->be_lun->maxlba + 1 - lba),
+ data->descr[0].length);
+ data->descr[0].status = 0; /* Mapped or unknown. */
+
+ ctl_set_success(ctsio);
+ ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
+ ctsio->be_move_done = ctl_config_move_done;
+
+ lbalen = (struct ctl_lba_len_flags *)&ctsio->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
+ lbalen->lba = lba;
+ lbalen->len = total_len;
+ lbalen->flags = 0;
+ retval = lun->backend->config_read((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+}
+
+int
ctl_read_defect(struct ctl_scsiio *ctsio)
{
struct scsi_read_defect_data_10 *ccb10;
@@ -10644,6 +10738,14 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len)
*len = UINT64_MAX;
break;
}
+ case SERVICE_ACTION_IN: { /* GET LBA STATUS */
+ struct scsi_get_lba_status *cdb;
+
+ cdb = (struct scsi_get_lba_status *)io->scsiio.cdb;
+ *lba = scsi_8btou64(cdb->addr);
+ *len = UINT32_MAX;
+ break;
+ }
default:
return (1);
break; /* NOTREACHED */
OpenPOWER on IntegriCloud