Rotation rate is sensitive to some applications, typically database need to recognize sdx device is HDD or SSD. This patch implements basic vpd 0xb1, and supports parameter 'rotation_rate', we can update rotation_rate by tgtadm command. Test case 1: T# tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 1 --params rotation_rate=1 I# cat /sys/block/sdb/queue/rotational 0 I# sg_vpd -p 0xb1 /dev/sdb Block device characteristics VPD page (SBC): Non-rotating medium (e.g. solid state) Test case 2: T# tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 1 --params rotation_rate=15000 I# cat /sys/block/sdb/queue/rotational 1 I# sg_vpd -p 0xb1 /dev/sdb Block device characteristics VPD page (SBC): Nominal rotation rate: 15000 rpm All of testing case work well. Signed-off-by: zhenwei pi <pizhenwei@xxxxxxxxxxxxx> --- usr/spc.c | 36 ++++++++++++++++++++++++++++++++++++ usr/tgtd.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/usr/spc.c b/usr/spc.c index 902d5bf..a32eda7 100644 --- a/usr/spc.c +++ b/usr/spc.c @@ -192,6 +192,26 @@ static void update_vpd_83(struct scsi_lu *lu, void *id) data[0] |= NAA_IEEE_REGD_EXTD << 4; } +static void update_vpd_b1(struct scsi_lu *lu, void *id) +{ + struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb1)]; + uint8_t *data = vpd_pg->data; + + if (lu->attrs.rotation_rate) { + data[0] = (lu->attrs.rotation_rate >> 8) & 0xff; + data[1] = lu->attrs.rotation_rate & 0xff; + data[2] = 0; /* PRODUCT TYPE */ + data[3] = 0; /* WABEREQ | WACEREQ | NOMINAL FORM FACTOR */ + data[4] = 0; /* VBULS */ + } else { + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + } +} + static void update_vpd_b2(struct scsi_lu *lu, void *id) { struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb2)]; @@ -1910,6 +1930,7 @@ enum { Opt_mode_page, Opt_path, Opt_bsopts, Opt_bsoflags, Opt_thinprovisioning, + Opt_rotation_rate, Opt_err, }; @@ -1932,6 +1953,7 @@ static match_table_t tokens = { {Opt_bsopts, "bsopts=%s"}, {Opt_bsoflags, "bsoflags=%s"}, {Opt_thinprovisioning, "thin_provisioning=%s"}, + {Opt_rotation_rate, "rotation_rate=%s"}, {Opt_err, NULL}, }; @@ -2030,6 +2052,12 @@ tgtadm_err lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn) lu_vpd[PCODE_OFFSET(0xb0)]->vpd_update(lu, NULL); lu_vpd[PCODE_OFFSET(0xb2)]->vpd_update(lu, NULL); break; + case Opt_rotation_rate: + match_strncpy(buf, &args[0], sizeof(buf)); + attrs->rotation_rate = atoi(buf); + /* update the characteristics vpd page */ + lu_vpd[PCODE_OFFSET(0xb1)]->vpd_update(lu, NULL); + break; case Opt_online: match_strncpy(buf, &args[0], sizeof(buf)); if (atoi(buf)) @@ -2107,6 +2135,14 @@ int spc_lu_init(struct scsi_lu *lu) lu_vpd[pg]->vpd_update = update_vpd_b0; lu_vpd[pg]->vpd_update(lu, NULL); + /* VPD page 0xb1 BLOCK DEVICE CHARACTERISTICS*/ + pg = PCODE_OFFSET(0xb1); + lu_vpd[pg] = alloc_vpd(BDC_VPD_LEN); + if (!lu_vpd[pg]) + return -ENOMEM; + lu_vpd[pg]->vpd_update = update_vpd_b1; + lu_vpd[pg]->vpd_update(lu, NULL); + /* VPD page 0xb2 LOGICAL BLOCK PROVISIONING*/ pg = PCODE_OFFSET(0xb2); lu_vpd[pg] = alloc_vpd(LBP_VPD_LEN); diff --git a/usr/tgtd.h b/usr/tgtd.h index d8b2ac1..cf3ade3 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h @@ -20,6 +20,7 @@ struct concat_buf; #define PRODUCT_ID_LEN 16 #define PRODUCT_REV_LEN 4 #define BLOCK_LIMITS_VPD_LEN 0x3C +#define BDC_VPD_LEN 0x40 #define LBP_VPD_LEN 4 #define PCODE_SHIFT 7 @@ -89,6 +90,7 @@ struct lu_phy_attr { char no_auto_lbppbe; /* Do not update it automatically when the backing file changes */ uint16_t la_lba; /* Lowest aligned LBA */ + uint16_t rotation_rate; /* Block rotation rate */ /* VPD pages 0x80 -> 0xff masked with 0x80*/ struct vpd *lu_vpd[1 << PCODE_SHIFT]; -- 2.11.0