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.
This commit is contained in:
Alexander Motin 2014-10-08 07:48:36 +00:00
parent c38aa2537b
commit 8a41675372
7 changed files with 54 additions and 11 deletions

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -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) {

View File

@ -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},

View File

@ -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);

View File

@ -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