summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-10-08 07:48:36 +0000
committermav <mav@FreeBSD.org>2014-10-08 07:48:36 +0000
commit7bd2d46a11dd655647cc8a0922f6414b1ffad635 (patch)
tree573f3d03af1b5cc3e69f86416c9e06d04e6c2088
parent3a2fd4b2473c379a563488eee36c1c1eade342a2 (diff)
downloadFreeBSD-src-7bd2d46a11dd655647cc8a0922f6414b1ffad635.zip
FreeBSD-src-7bd2d46a11dd655647cc8a0922f6414b1ffad635.tar.gz
Add support for WRITE ATOMIC (16) command and report SBC-4 compliance.
Atomic writes are only supported for ZVOLs in "dev" mode. In other cases atomicity can not be guarantied and so the command is blocked.
-rw-r--r--sys/cam/ctl/ctl.c41
-rw-r--r--sys/cam/ctl/ctl_backend.h3
-rw-r--r--sys/cam/ctl/ctl_backend_block.c3
-rw-r--r--sys/cam/ctl/ctl_backend_ramdisk.c1
-rw-r--r--sys/cam/ctl/ctl_cmd_table.c7
-rw-r--r--sys/cam/ctl/scsi_ctl.c1
-rw-r--r--sys/cam/scsi/scsi_all.h9
7 files changed, 54 insertions, 11 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index eaba507..28f07b0 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -9126,6 +9126,31 @@ ctl_read_write(struct ctl_scsiio *ctsio)
num_blocks = scsi_4btoul(cdb->length);
break;
}
+ case WRITE_ATOMIC_16: {
+ struct scsi_rw_16 *cdb;
+
+ if (lun->be_lun->atomicblock == 0) {
+ ctl_set_invalid_opcode(ctsio);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+
+ cdb = (struct scsi_rw_16 *)ctsio->cdb;
+ if (cdb->byte2 & SRW12_FUA)
+ flags |= CTL_LLF_FUA;
+ if (cdb->byte2 & SRW12_DPO)
+ flags |= CTL_LLF_DPO;
+ lba = scsi_8btou64(cdb->addr);
+ num_blocks = scsi_4btoul(cdb->length);
+ if (num_blocks > lun->be_lun->atomicblock) {
+ ctl_set_invalid_field(ctsio, /*sks_valid*/ 1,
+ /*command*/ 1, /*field*/ 12, /*bit_valid*/ 0,
+ /*bit*/ 0);
+ ctl_done((union ctl_io *)ctsio);
+ return (CTL_RETVAL_COMPLETE);
+ }
+ break;
+ }
case WRITE_VERIFY_16: {
struct scsi_write_verify_16 *cdb;
@@ -10299,6 +10324,10 @@ ctl_inquiry_evpd_block_limits(struct ctl_scsiio *ctsio, int alloc_len)
bl_ptr->unmap_grain_align);
}
}
+ scsi_ulto4b(lun->be_lun->atomicblock,
+ bl_ptr->max_atomic_transfer_length);
+ scsi_ulto4b(0, bl_ptr->atomic_alignment);
+ scsi_ulto4b(0, bl_ptr->atomic_transfer_length_granularity);
}
scsi_u64to8b(UINT64_MAX, bl_ptr->max_write_same_length);
@@ -10694,13 +10723,13 @@ ctl_inquiry_std(struct ctl_scsiio *ctsio)
}
if (lun == NULL) {
- /* SBC-3 (no version claimed) */
- scsi_ulto2b(0x04C0, inq_ptr->version4);
+ /* SBC-4 (no version claimed) */
+ scsi_ulto2b(0x0600, inq_ptr->version4);
} else {
switch (lun->be_lun->lun_type) {
case T_DIRECT:
- /* SBC-3 (no version claimed) */
- scsi_ulto2b(0x04C0, inq_ptr->version4);
+ /* SBC-4 (no version claimed) */
+ scsi_ulto2b(0x0600, inq_ptr->version4);
break;
case T_PROCESSOR:
default:
@@ -10818,7 +10847,8 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len)
break;
}
case READ_16:
- case WRITE_16: {
+ case WRITE_16:
+ case WRITE_ATOMIC_16: {
struct scsi_rw_16 *cdb;
cdb = (struct scsi_rw_16 *)io->scsiio.cdb;
@@ -10832,7 +10862,6 @@ ctl_get_lba_len(union ctl_io *io, uint64_t *lba, uint64_t *len)
cdb = (struct scsi_write_verify_16 *)io->scsiio.cdb;
-
*lba = scsi_8btou64(cdb->addr);
*len = scsi_4btoul(cdb->length);
break;
diff --git a/sys/cam/ctl/ctl_backend.h b/sys/cam/ctl/ctl_backend.h
index c2066c5..d8e78ab 100644
--- a/sys/cam/ctl/ctl_backend.h
+++ b/sys/cam/ctl/ctl_backend.h
@@ -144,6 +144,8 @@ typedef void (*be_lun_config_t)(void *be_lun,
*
* pblockoff is the lowest LBA on the LUN aligned ot physical sector.
*
+ * atomicblock is the number of blocks that can be written atomically.
+ *
* req_lun_id is the requested LUN ID. CTL only pays attention to this
* field if the CTL_LUN_FLAG_ID_REQ flag is set. If the requested LUN ID is
* not available, the LUN addition will fail. If a particular LUN ID isn't
@@ -188,6 +190,7 @@ struct ctl_be_lun {
uint32_t blocksize; /* passed to CTL */
uint16_t pblockexp; /* passed to CTL */
uint16_t pblockoff; /* passed to CTL */
+ uint32_t atomicblock; /* passed to CTL */
uint32_t req_lun_id; /* passed to CTL */
uint32_t lun_id; /* returned from CTL */
uint8_t serial_num[CTL_SN_LEN]; /* passed to CTL */
diff --git a/sys/cam/ctl/ctl_backend_block.c b/sys/cam/ctl/ctl_backend_block.c
index 0ae8ecb..eb16474 100644
--- a/sys/cam/ctl/ctl_backend_block.c
+++ b/sys/cam/ctl/ctl_backend_block.c
@@ -2003,6 +2003,9 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY;
if (unmap)
be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_UNMAP;
+ if (be_lun->dispatch == ctl_be_block_dispatch_zvol)
+ be_lun->ctl_be_lun.atomicblock = CTLBLK_MAX_IO_SIZE /
+ be_lun->blocksize;
be_lun->ctl_be_lun.be_lun = be_lun;
be_lun->ctl_be_lun.blocksize = be_lun->blocksize;
be_lun->ctl_be_lun.pblockexp = be_lun->pblockexp;
diff --git a/sys/cam/ctl/ctl_backend_ramdisk.c b/sys/cam/ctl/ctl_backend_ramdisk.c
index 6613e8e..5f45035 100644
--- a/sys/cam/ctl/ctl_backend_ramdisk.c
+++ b/sys/cam/ctl/ctl_backend_ramdisk.c
@@ -595,6 +595,7 @@ ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY;
if (unmap)
be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_UNMAP;
+ be_lun->ctl_be_lun.atomicblock = UINT32_MAX;
be_lun->ctl_be_lun.be_lun = be_lun;
if (params->flags & CTL_LUN_FLAG_ID_REQ) {
diff --git a/sys/cam/ctl/ctl_cmd_table.c b/sys/cam/ctl/ctl_cmd_table.c
index eb1b0ee..e2323a2 100644
--- a/sys/cam/ctl/ctl_cmd_table.c
+++ b/sys/cam/ctl/ctl_cmd_table.c
@@ -1117,8 +1117,11 @@ const struct ctl_cmd_entry ctl_cmd_table[256] =
/* 9B */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
-/* 9C */
-{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
+/* 9C WRITE ATOMIC (16) */
+{ctl_read_write, CTL_SERIDX_WRITE, CTL_CMD_FLAG_OK_ON_SLUN| CTL_FLAG_DATA_OUT,
+ CTL_LUN_PAT_WRITE | CTL_LUN_PAT_RANGE,
+ 16, {0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0, 0, 0xff, 0xff, 0, 0x07}},
/* 9D */
{NULL, CTL_SERIDX_INVLD, CTL_CMD_FLAG_NONE, CTL_LUN_PAT_NONE},
diff --git a/sys/cam/ctl/scsi_ctl.c b/sys/cam/ctl/scsi_ctl.c
index 3529683..9347ed1 100644
--- a/sys/cam/ctl/scsi_ctl.c
+++ b/sys/cam/ctl/scsi_ctl.c
@@ -1115,6 +1115,7 @@ ctlfe_adjust_cdb(struct ccb_accept_tio *atio, uint32_t offset)
}
case READ_16:
case WRITE_16:
+ case WRITE_ATOMIC_16:
{
struct scsi_rw_16 *cdb = (struct scsi_rw_16 *)cmdbyt;
lba = scsi_8btou64(cdb->addr);
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 8eb58fe..fbb131e 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -1720,6 +1720,7 @@ struct ata_pass_16 {
#define VERIFY_16 0x8F
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93
+#define WRITE_ATOMIC_16 0x9C
#define SERVICE_ACTION_IN 0x9E
#define REPORT_LUNS 0xA0
#define ATA_PASS_12 0xA1
@@ -2437,8 +2438,7 @@ struct scsi_vpd_logical_block_prov
};
/*
- * Block Limits VDP Page based on
- * T10/1799-D Revision 31
+ * Block Limits VDP Page based on SBC-4 Revision 2
*/
struct scsi_vpd_block_limits
{
@@ -2459,7 +2459,10 @@ struct scsi_vpd_block_limits
u_int8_t opt_unmap_grain[4];
u_int8_t unmap_grain_align[4];
u_int8_t max_write_same_length[8];
- u_int8_t reserved2[20];
+ u_int8_t max_atomic_transfer_length[4];
+ u_int8_t atomic_alignment[4];
+ u_int8_t atomic_transfer_length_granularity[4];
+ u_int8_t reserved2[8];
};
struct scsi_read_capacity
OpenPOWER on IntegriCloud