From 8a416753723e6a481607dbe7d5fed622f5a0f8e0 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 8 Oct 2014 07:48:36 +0000 Subject: 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. --- sys/cam/ctl/ctl.c | 41 +++++++++++++++++++++++++++++++++------ sys/cam/ctl/ctl_backend.h | 3 +++ sys/cam/ctl/ctl_backend_block.c | 3 +++ sys/cam/ctl/ctl_backend_ramdisk.c | 1 + sys/cam/ctl/ctl_cmd_table.c | 7 +++++-- sys/cam/ctl/scsi_ctl.c | 1 + 6 files changed, 48 insertions(+), 8 deletions(-) (limited to 'sys/cam/ctl') diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index eaba50788541..28f07b0f9965 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 c2066c527466..d8e78ab477ad 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 0ae8ecb1eb10..eb16474a247b 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 6613e8e8656d..5f45035148d5 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 eb1b0ee41e2f..e2323a2cb342 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 3529683f6208..9347ed13729d 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); -- cgit v1.2.3