diff options
author | mav <mav@FreeBSD.org> | 2014-10-20 07:33:41 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2014-10-20 07:33:41 +0000 |
commit | 29253fce187f2bc4585df13155a351d6f3b17cb3 (patch) | |
tree | dc8aa3e98e17a6080805d79f6658364a2a281740 /sys/cam | |
parent | f7c3270824c4c3876dd5562034af36fe5e6c8326 (diff) | |
download | FreeBSD-src-29253fce187f2bc4585df13155a351d6f3b17cb3.zip FreeBSD-src-29253fce187f2bc4585df13155a351d6f3b17cb3.tar.gz |
MFC r272734:
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.
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/ctl/ctl.c | 41 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_backend.h | 3 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_backend_block.c | 3 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_backend_ramdisk.c | 1 | ||||
-rw-r--r-- | sys/cam/ctl/ctl_cmd_table.c | 7 | ||||
-rw-r--r-- | sys/cam/ctl/scsi_ctl.c | 1 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.h | 9 |
7 files changed, 54 insertions, 11 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c index 95e3944..84e4bb1 100644 --- a/sys/cam/ctl/ctl.c +++ b/sys/cam/ctl/ctl.c @@ -9128,6 +9128,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; @@ -10301,6 +10326,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); @@ -10696,13 +10725,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: @@ -10820,7 +10849,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; @@ -10834,7 +10864,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 086458e..e6d0c0d 100644 --- a/sys/cam/ctl/ctl_backend_block.c +++ b/sys/cam/ctl/ctl_backend_block.c @@ -2006,6 +2006,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 |