aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2019-07-26 19:14:12 +0000
committerAlexander Motin <mav@FreeBSD.org>2019-07-26 19:14:12 +0000
commited3bf015996599712173e2d600384a52cf5b8854 (patch)
tree0df354b73b1493acd35e857bd0edef226f7cb067 /sys
parentba9b2ede8a46eb7a2848b6683fe3f916e1bcd82d (diff)
downloadsrc-ed3bf015996599712173e2d600384a52cf5b8854.tar.gz
src-ed3bf015996599712173e2d600384a52cf5b8854.zip
Add support for Long LBA mode parameter block descriptor.
It is formally required for SBC Base 2016 feature set. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=350363
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/ctl/ctl.c74
-rw-r--r--sys/cam/scsi/scsi_all.h18
2 files changed, 62 insertions, 30 deletions
diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index dfd777d61e93..3a871c82b183 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -6365,13 +6365,12 @@ int
ctl_mode_sense(struct ctl_scsiio *ctsio)
{
struct ctl_lun *lun = CTL_LUN(ctsio);
- int pc, page_code, dbd, subpage;
- int alloc_len, page_len, header_len, total_len;
- struct scsi_mode_block_descr *block_desc;
+ int pc, page_code, llba, subpage;
+ int alloc_len, page_len, header_len, bd_len, total_len;
+ void *block_desc;
struct ctl_page_index *page_index;
- dbd = 0;
- block_desc = NULL;
+ llba = 0;
CTL_DEBUG_PRINT(("ctl_mode_sense\n"));
@@ -6383,9 +6382,10 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
header_len = sizeof(struct scsi_mode_hdr_6);
if (cdb->byte2 & SMS_DBD)
- dbd = 1;
+ bd_len = 0;
else
- header_len += sizeof(struct scsi_mode_block_descr);
+ bd_len = sizeof(struct scsi_mode_block_descr);
+ header_len += bd_len;
pc = (cdb->page & SMS_PAGE_CTRL_MASK) >> 6;
page_code = cdb->page & SMS_PAGE_CODE;
@@ -6399,11 +6399,18 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
cdb = (struct scsi_mode_sense_10 *)ctsio->cdb;
header_len = sizeof(struct scsi_mode_hdr_10);
+ if (cdb->byte2 & SMS_DBD) {
+ bd_len = 0;
+ } else if (lun->be_lun->lun_type == T_DIRECT) {
+ if (cdb->byte2 & SMS10_LLBAA) {
+ llba = 1;
+ bd_len = sizeof(struct scsi_mode_block_descr_dlong);
+ } else
+ bd_len = sizeof(struct scsi_mode_block_descr_dshort);
+ } else
+ bd_len = sizeof(struct scsi_mode_block_descr);
+ header_len += bd_len;
- if (cdb->byte2 & SMS_DBD)
- dbd = 1;
- else
- header_len += sizeof(struct scsi_mode_block_descr);
pc = (cdb->page & SMS_PAGE_CTRL_MASK) >> 6;
page_code = cdb->page & SMS_PAGE_CODE;
subpage = cdb->subpage;
@@ -6536,12 +6543,8 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
(lun->MODE_CTRL.eca_and_aen & SCP_SWP) != 0)
header->dev_specific |= 0x80; /* WP */
}
- if (dbd)
- header->block_descr_len = 0;
- else
- header->block_descr_len =
- sizeof(struct scsi_mode_block_descr);
- block_desc = (struct scsi_mode_block_descr *)&header[1];
+ header->block_descr_len = bd_len;
+ block_desc = &header[1];
break;
}
case MODE_SENSE_10: {
@@ -6558,12 +6561,10 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
(lun->MODE_CTRL.eca_and_aen & SCP_SWP) != 0)
header->dev_specific |= 0x80; /* WP */
}
- if (dbd)
- scsi_ulto2b(0, header->block_descr_len);
- else
- scsi_ulto2b(sizeof(struct scsi_mode_block_descr),
- header->block_descr_len);
- block_desc = (struct scsi_mode_block_descr *)&header[1];
+ if (llba)
+ header->flags |= SMH_LONGLBA;
+ scsi_ulto2b(bd_len, header->block_descr_len);
+ block_desc = &header[1];
break;
}
default:
@@ -6574,12 +6575,27 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
* If we've got a disk, use its blocksize in the block
* descriptor. Otherwise, just set it to 0.
*/
- if (dbd == 0) {
- if (lun->be_lun->lun_type == T_DIRECT)
- scsi_ulto3b(lun->be_lun->blocksize,
- block_desc->block_len);
- else
- scsi_ulto3b(0, block_desc->block_len);
+ if (bd_len > 0) {
+ if (lun->be_lun->lun_type == T_DIRECT) {
+ if (llba) {
+ struct scsi_mode_block_descr_dlong *bd = block_desc;
+ if (lun->be_lun->maxlba != 0)
+ scsi_u64to8b(lun->be_lun->maxlba + 1,
+ bd->num_blocks);
+ scsi_ulto4b(lun->be_lun->blocksize,
+ bd->block_len);
+ } else {
+ struct scsi_mode_block_descr_dshort *bd = block_desc;
+ if (lun->be_lun->maxlba != 0)
+ scsi_ulto4b(MIN(lun->be_lun->maxlba+1,
+ UINT32_MAX), bd->num_blocks);
+ scsi_ulto3b(lun->be_lun->blocksize,
+ bd->block_len);
+ }
+ } else {
+ struct scsi_mode_block_descr *bd = block_desc;
+ scsi_ulto3b(0, bd->block_len);
+ }
}
switch (page_code) {
diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h
index 5c679049f0a8..b76e48124a0c 100644
--- a/sys/cam/scsi/scsi_all.h
+++ b/sys/cam/scsi/scsi_all.h
@@ -264,7 +264,9 @@ struct scsi_mode_hdr_10
u_int8_t datalen[2];
u_int8_t medium_type;
u_int8_t dev_specific;
- u_int8_t reserved[2];
+ u_int8_t flags;
+#define SMH_LONGLBA 0x01
+ u_int8_t reserved;
u_int8_t block_descr_len[2];
};
@@ -276,6 +278,20 @@ struct scsi_mode_block_descr
u_int8_t block_len[3];
};
+struct scsi_mode_block_descr_dshort
+{
+ u_int8_t num_blocks[4];
+ u_int8_t reserved;
+ u_int8_t block_len[3];
+};
+
+struct scsi_mode_block_descr_dlong
+{
+ u_int8_t num_blocks[8];
+ u_int8_t reserved[4];
+ u_int8_t block_len[4];
+};
+
struct scsi_per_res_in
{
u_int8_t opcode;