Skip to content

Commit e7a8648

Browse files
Ranjan Kumarmartinkpetersen
authored andcommitted
scsi: mpi3mr: WRITE SAME implementation
Enhance driver to divert the WRITE SAME commands that are issued with UNMAP=1 and NDOB=1 and with the transfer length greater than the max WRITE SAME length specified by the firmware for the particular drive to the controller firmware. Reported-by: kernel test robot <[email protected]> Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/ Signed-off-by: Ranjan Kumar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Martin K. Petersen <[email protected]>
1 parent d9adb81 commit e7a8648

File tree

2 files changed

+105
-24
lines changed

2 files changed

+105
-24
lines changed

drivers/scsi/mpi3mr/mpi3mr.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ extern atomic64_t event_counter;
207207
*/
208208
#define MPI3MR_MAX_APP_XFER_SECTORS (2048 + 512)
209209

210+
#define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256
211+
#define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048
212+
210213
/**
211214
* struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe
212215
* Encapsulated commands.
@@ -678,6 +681,7 @@ enum mpi3mr_dev_state {
678681
* @io_unit_port: IO Unit port ID
679682
* @non_stl: Is this device not to be attached with SAS TL
680683
* @io_throttle_enabled: I/O throttling needed or not
684+
* @wslen: Write same max length
681685
* @q_depth: Device specific Queue Depth
682686
* @wwid: World wide ID
683687
* @enclosure_logical_id: Enclosure logical identifier
@@ -700,6 +704,7 @@ struct mpi3mr_tgt_dev {
700704
u8 io_unit_port;
701705
u8 non_stl;
702706
u8 io_throttle_enabled;
707+
u16 wslen;
703708
u16 q_depth;
704709
u64 wwid;
705710
u64 enclosure_logical_id;
@@ -753,6 +758,8 @@ static inline void mpi3mr_tgtdev_put(struct mpi3mr_tgt_dev *s)
753758
* @dev_removed: Device removed in the Firmware
754759
* @dev_removedelay: Device is waiting to be removed in FW
755760
* @dev_type: Device type
761+
* @dev_nvme_dif: Device is NVMe DIF enabled
762+
* @wslen: Write same max length
756763
* @io_throttle_enabled: I/O throttling needed or not
757764
* @io_divert: Flag indicates io divert is on or off for the dev
758765
* @throttle_group: Pointer to throttle group info
@@ -769,6 +776,8 @@ struct mpi3mr_stgt_priv_data {
769776
u8 dev_removed;
770777
u8 dev_removedelay;
771778
u8 dev_type;
779+
u8 dev_nvme_dif;
780+
u16 wslen;
772781
u8 io_throttle_enabled;
773782
u8 io_divert;
774783
struct mpi3mr_throttle_group_info *throttle_group;
@@ -784,12 +793,14 @@ struct mpi3mr_stgt_priv_data {
784793
* @ncq_prio_enable: NCQ priority enable for SATA device
785794
* @pend_count: Counter to track pending I/Os during error
786795
* handling
796+
* @wslen: Write same max length
787797
*/
788798
struct mpi3mr_sdev_priv_data {
789799
struct mpi3mr_stgt_priv_data *tgt_priv_data;
790800
u32 lun_id;
791801
u8 ncq_prio_enable;
792802
u32 pend_count;
803+
u16 wslen;
793804
};
794805

795806
/**

drivers/scsi/mpi3mr/mpi3mr_os.c

Lines changed: 94 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
430430
tgt_priv->io_throttle_enabled = 0;
431431
tgt_priv->io_divert = 0;
432432
tgt_priv->throttle_group = NULL;
433+
tgt_priv->wslen = 0;
433434
if (tgtdev->host_exposed)
434435
atomic_set(&tgt_priv->block_io, 1);
435436
}
@@ -1108,6 +1109,18 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
11081109
tgtdev->io_throttle_enabled =
11091110
(flags & MPI3_DEVICE0_FLAGS_IO_THROTTLING_REQUIRED) ? 1 : 0;
11101111

1112+
switch (flags & MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_MASK) {
1113+
case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_256_LB:
1114+
tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS;
1115+
break;
1116+
case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_2048_LB:
1117+
tgtdev->wslen = MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS;
1118+
break;
1119+
case MPI3_DEVICE0_FLAGS_MAX_WRITE_SAME_NO_LIMIT:
1120+
default:
1121+
tgtdev->wslen = 0;
1122+
break;
1123+
}
11111124

11121125
if (tgtdev->starget && tgtdev->starget->hostdata) {
11131126
scsi_tgt_priv_data = (struct mpi3mr_stgt_priv_data *)
@@ -1119,6 +1132,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
11191132
tgtdev->io_throttle_enabled;
11201133
if (is_added == true)
11211134
atomic_set(&scsi_tgt_priv_data->block_io, 0);
1135+
scsi_tgt_priv_data->wslen = tgtdev->wslen;
11221136
}
11231137

11241138
switch (dev_pg0->access_status) {
@@ -3939,6 +3953,48 @@ void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout)
39393953
mpi3mr_get_fw_pending_ios(mrioc));
39403954
}
39413955

3956+
/**
3957+
* mpi3mr_setup_divert_ws - Setup Divert IO flag for write same
3958+
* @mrioc: Adapter instance reference
3959+
* @scmd: SCSI command reference
3960+
* @scsiio_req: MPI3 SCSI IO request
3961+
* @scsiio_flags: Pointer to MPI3 SCSI IO Flags
3962+
* @wslen: write same max length
3963+
*
3964+
* Gets values of unmap, ndob and number of blocks from write
3965+
* same scsi io and based on these values it sets divert IO flag
3966+
* and reason for diverting IO to firmware.
3967+
*
3968+
* Return: Nothing
3969+
*/
3970+
static inline void mpi3mr_setup_divert_ws(struct mpi3mr_ioc *mrioc,
3971+
struct scsi_cmnd *scmd, struct mpi3_scsi_io_request *scsiio_req,
3972+
u32 *scsiio_flags, u16 wslen)
3973+
{
3974+
u8 unmap = 0, ndob = 0;
3975+
u8 opcode = scmd->cmnd[0];
3976+
u32 num_blocks = 0;
3977+
u16 sa = (scmd->cmnd[8] << 8) | (scmd->cmnd[9]);
3978+
3979+
if (opcode == WRITE_SAME_16) {
3980+
unmap = scmd->cmnd[1] & 0x08;
3981+
ndob = scmd->cmnd[1] & 0x01;
3982+
num_blocks = get_unaligned_be32(scmd->cmnd + 10);
3983+
} else if ((opcode == VARIABLE_LENGTH_CMD) && (sa == WRITE_SAME_32)) {
3984+
unmap = scmd->cmnd[10] & 0x08;
3985+
ndob = scmd->cmnd[10] & 0x01;
3986+
num_blocks = get_unaligned_be32(scmd->cmnd + 28);
3987+
} else
3988+
return;
3989+
3990+
if ((unmap) && (ndob) && (num_blocks > wslen)) {
3991+
scsiio_req->msg_flags |=
3992+
MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE;
3993+
*scsiio_flags |=
3994+
MPI3_SCSIIO_FLAGS_DIVERT_REASON_WRITE_SAME_TOO_LARGE;
3995+
}
3996+
}
3997+
39423998
/**
39433999
* mpi3mr_eh_host_reset - Host reset error handling callback
39444000
* @scmd: SCSI command reference
@@ -4436,7 +4492,6 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
44364492
unsigned long flags;
44374493
int retval = 0;
44384494
struct sas_rphy *rphy = NULL;
4439-
bool update_stgt_priv_data = false;
44404495

44414496
scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
44424497
if (!scsi_tgt_priv_data)
@@ -4445,39 +4500,50 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
44454500
starget->hostdata = scsi_tgt_priv_data;
44464501

44474502
spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
4448-
44494503
if (starget->channel == mrioc->scsi_device_channel) {
44504504
tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
4451-
if (tgt_dev && !tgt_dev->is_hidden)
4452-
update_stgt_priv_data = true;
4453-
else
4505+
if (tgt_dev && !tgt_dev->is_hidden) {
4506+
scsi_tgt_priv_data->starget = starget;
4507+
scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
4508+
scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
4509+
scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
4510+
scsi_tgt_priv_data->tgt_dev = tgt_dev;
4511+
tgt_dev->starget = starget;
4512+
atomic_set(&scsi_tgt_priv_data->block_io, 0);
4513+
retval = 0;
4514+
if ((tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE) &&
4515+
((tgt_dev->dev_spec.pcie_inf.dev_info &
4516+
MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) ==
4517+
MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) &&
4518+
((tgt_dev->dev_spec.pcie_inf.dev_info &
4519+
MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_MASK) !=
4520+
MPI3_DEVICE0_PCIE_DEVICE_INFO_PITYPE_0))
4521+
scsi_tgt_priv_data->dev_nvme_dif = 1;
4522+
scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
4523+
scsi_tgt_priv_data->wslen = tgt_dev->wslen;
4524+
if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
4525+
scsi_tgt_priv_data->throttle_group = tgt_dev->dev_spec.vd_inf.tg;
4526+
} else
44544527
retval = -ENXIO;
44554528
} else if (mrioc->sas_transport_enabled && !starget->channel) {
44564529
rphy = dev_to_rphy(starget->dev.parent);
44574530
tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
44584531
rphy->identify.sas_address, rphy);
44594532
if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl &&
4460-
(tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA))
4461-
update_stgt_priv_data = true;
4462-
else
4533+
(tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA)) {
4534+
scsi_tgt_priv_data->starget = starget;
4535+
scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
4536+
scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
4537+
scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
4538+
scsi_tgt_priv_data->tgt_dev = tgt_dev;
4539+
scsi_tgt_priv_data->io_throttle_enabled = tgt_dev->io_throttle_enabled;
4540+
scsi_tgt_priv_data->wslen = tgt_dev->wslen;
4541+
tgt_dev->starget = starget;
4542+
atomic_set(&scsi_tgt_priv_data->block_io, 0);
4543+
retval = 0;
4544+
} else
44634545
retval = -ENXIO;
44644546
}
4465-
4466-
if (update_stgt_priv_data) {
4467-
scsi_tgt_priv_data->starget = starget;
4468-
scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
4469-
scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
4470-
scsi_tgt_priv_data->dev_type = tgt_dev->dev_type;
4471-
scsi_tgt_priv_data->tgt_dev = tgt_dev;
4472-
tgt_dev->starget = starget;
4473-
atomic_set(&scsi_tgt_priv_data->block_io, 0);
4474-
retval = 0;
4475-
scsi_tgt_priv_data->io_throttle_enabled =
4476-
tgt_dev->io_throttle_enabled;
4477-
if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
4478-
scsi_tgt_priv_data->throttle_group =
4479-
tgt_dev->dev_spec.vd_inf.tg;
4480-
}
44814547
spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
44824548

44834549
return retval;
@@ -4738,6 +4804,10 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
47384804

47394805
mpi3mr_setup_eedp(mrioc, scmd, scsiio_req);
47404806

4807+
if (stgt_priv_data->wslen)
4808+
mpi3mr_setup_divert_ws(mrioc, scmd, scsiio_req, &scsiio_flags,
4809+
stgt_priv_data->wslen);
4810+
47414811
memcpy(scsiio_req->cdb.cdb32, scmd->cmnd, scmd->cmd_len);
47424812
scsiio_req->data_length = cpu_to_le32(scsi_bufflen(scmd));
47434813
scsiio_req->dev_handle = cpu_to_le16(dev_handle);

0 commit comments

Comments
 (0)