From dd896a6b0a0d3939c1ba070f46bec42cbb7573eb Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Wed, 13 Mar 2024 15:37:40 +0530 Subject: scsi: mpi3mr: Block devices are not removed even when VDs are offlined The driver did not remove the virtual disk that was exposed as hidden and offline after the controller was reset. Drive is removed from OS when firmware sends "device added" event with hidden bit set or access status indicating inability to accept I/Os. Signed-off-by: Ranjan Kumar Signed-off-by: Sathya Prakash Link: https://lore.kernel.org/r/20240313100746.128951-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/scsi/mpi3mr/mpi3mr_os.c') diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 73c831a97d27..bfd32354b662 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1029,7 +1029,7 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data) } /** - * mpi3mr_rfresh_tgtdevs - Refresh target device exposure + * mpi3mr_refresh_tgtdevs - Refresh target device exposure * @mrioc: Adapter instance reference * * This is executed post controller reset to identify any @@ -1039,7 +1039,7 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data) * Return: Nothing. */ -void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) +void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) { struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next; struct mpi3mr_stgt_priv_data *tgt_priv; @@ -1047,8 +1047,8 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) dprint_reset(mrioc, "refresh target devices: check for removals\n"); list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, list) { - if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) && - tgtdev->is_hidden && + if (((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) || + tgtdev->is_hidden) && tgtdev->host_exposed && tgtdev->starget && tgtdev->starget->hostdata) { tgt_priv = tgtdev->starget->hostdata; @@ -2010,7 +2010,7 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, mpi3mr_refresh_sas_ports(mrioc); mpi3mr_refresh_expanders(mrioc); } - mpi3mr_rfresh_tgtdevs(mrioc); + mpi3mr_refresh_tgtdevs(mrioc); ioc_info(mrioc, "scan for non responding and newly added devices after soft reset completed\n"); break; -- cgit v1.2.3-59-g8ed1b From a18f4c58372da9395a059c9105d7df23ab0097d9 Mon Sep 17 00:00:00 2001 From: Ranjan Kumar Date: Wed, 13 Mar 2024 15:37:41 +0530 Subject: scsi: mpi3mr: Set MPI request flags appropriately The 'flags' variable inside an MPI request is a bitfield and should consequently be updated using a bitwise OR operation. Signed-off-by: Ranjan Kumar Signed-off-by: Sathya Prakash Link: https://lore.kernel.org/r/20240313100746.128951-3-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/mpi3mr/mpi3mr_os.c') diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index bfd32354b662..5f975e0db388 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -4895,7 +4895,7 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost, MPI3_SCSIIO_MSGFLAGS_DIVERT_TO_FIRMWARE; scsiio_flags |= MPI3_SCSIIO_FLAGS_DIVERT_REASON_IO_THROTTLING; } - scsiio_req->flags = cpu_to_le32(scsiio_flags); + scsiio_req->flags |= cpu_to_le32(scsiio_flags); if (mpi3mr_op_request_post(mrioc, op_req_q, scmd_priv_data->mpi3mr_scsiio_req)) { -- cgit v1.2.3-59-g8ed1b From 310887f688f76bb3eba589b9c2c1032d2078bb2b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 10 Apr 2024 06:27:59 +0200 Subject: scsi: mpi3mr: Switch to using ->device_configure Switch to the ->device_configure method instead of ->slave_configure and update the block limits on the passed in queue_limits instead of using the per-limit accessors. Note that mpi3mr also updates the limits from an event handler that iterates all SCSI devices. This is also updated to use the queue_limits, but the complete locking of this path probably means it already is completely broken and needs a proper audit. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20240410042759.GA2637@lst.de Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr_os.c | 73 +++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 43 deletions(-) (limited to 'drivers/scsi/mpi3mr/mpi3mr_os.c') diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 5f975e0db388..71f2c62db111 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -986,6 +986,25 @@ static int mpi3mr_change_queue_depth(struct scsi_device *sdev, return retval; } +static void mpi3mr_configure_nvme_dev(struct mpi3mr_tgt_dev *tgt_dev, + struct queue_limits *lim) +{ + u8 pgsz = tgt_dev->dev_spec.pcie_inf.pgsz ? : MPI3MR_DEFAULT_PGSZEXP; + + lim->max_hw_sectors = tgt_dev->dev_spec.pcie_inf.mdts / 512; + lim->virt_boundary_mask = (1 << pgsz) - 1; +} + +static void mpi3mr_configure_tgt_dev(struct mpi3mr_tgt_dev *tgt_dev, + struct queue_limits *lim) +{ + if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_PCIE && + (tgt_dev->dev_spec.pcie_inf.dev_info & + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == + MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) + mpi3mr_configure_nvme_dev(tgt_dev, lim); +} + /** * mpi3mr_update_sdev - Update SCSI device information * @sdev: SCSI device reference @@ -1001,31 +1020,17 @@ static void mpi3mr_update_sdev(struct scsi_device *sdev, void *data) { struct mpi3mr_tgt_dev *tgtdev; + struct queue_limits lim; tgtdev = (struct mpi3mr_tgt_dev *)data; if (!tgtdev) return; mpi3mr_change_queue_depth(sdev, tgtdev->q_depth); - switch (tgtdev->dev_type) { - case MPI3_DEVICE_DEVFORM_PCIE: - /*The block layer hw sector size = 512*/ - if ((tgtdev->dev_spec.pcie_inf.dev_info & - MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == - MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { - blk_queue_max_hw_sectors(sdev->request_queue, - tgtdev->dev_spec.pcie_inf.mdts / 512); - if (tgtdev->dev_spec.pcie_inf.pgsz == 0) - blk_queue_virt_boundary(sdev->request_queue, - ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); - else - blk_queue_virt_boundary(sdev->request_queue, - ((1 << tgtdev->dev_spec.pcie_inf.pgsz) - 1)); - } - break; - default: - break; - } + + lim = queue_limits_start_update(sdev->request_queue); + mpi3mr_configure_tgt_dev(tgtdev, &lim); + WARN_ON_ONCE(queue_limits_commit_update(sdev->request_queue, &lim)); } /** @@ -4393,15 +4398,17 @@ static void mpi3mr_target_destroy(struct scsi_target *starget) } /** - * mpi3mr_slave_configure - Slave configure callback handler + * mpi3mr_device_configure - Slave configure callback handler * @sdev: SCSI device reference + * @lim: queue limits * * Configure queue depth, max hardware sectors and virt boundary * as required * * Return: 0 always. */ -static int mpi3mr_slave_configure(struct scsi_device *sdev) +static int mpi3mr_device_configure(struct scsi_device *sdev, + struct queue_limits *lim) { struct scsi_target *starget; struct Scsi_Host *shost; @@ -4432,28 +4439,8 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev) sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT; blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT); - switch (tgt_dev->dev_type) { - case MPI3_DEVICE_DEVFORM_PCIE: - /*The block layer hw sector size = 512*/ - if ((tgt_dev->dev_spec.pcie_inf.dev_info & - MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) == - MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_NVME_DEVICE) { - blk_queue_max_hw_sectors(sdev->request_queue, - tgt_dev->dev_spec.pcie_inf.mdts / 512); - if (tgt_dev->dev_spec.pcie_inf.pgsz == 0) - blk_queue_virt_boundary(sdev->request_queue, - ((1 << MPI3MR_DEFAULT_PGSZEXP) - 1)); - else - blk_queue_virt_boundary(sdev->request_queue, - ((1 << tgt_dev->dev_spec.pcie_inf.pgsz) - 1)); - } - break; - default: - break; - } - + mpi3mr_configure_tgt_dev(tgt_dev, lim); mpi3mr_tgtdev_put(tgt_dev); - return retval; } @@ -4921,7 +4908,7 @@ static const struct scsi_host_template mpi3mr_driver_template = { .queuecommand = mpi3mr_qcmd, .target_alloc = mpi3mr_target_alloc, .slave_alloc = mpi3mr_slave_alloc, - .slave_configure = mpi3mr_slave_configure, + .device_configure = mpi3mr_device_configure, .target_destroy = mpi3mr_target_destroy, .slave_destroy = mpi3mr_slave_destroy, .scan_finished = mpi3mr_scan_finished, -- cgit v1.2.3-59-g8ed1b From 30efd3823f2c1f8b1a22727247520c75071d339c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 9 Apr 2024 16:37:46 +0200 Subject: scsi: mpi3mr: Switch to using ->device_configure Switch to the ->device_configure method instead of ->slave_configure and update the block limits on the passed in queue_limits instead of using the per-limit accessors. Note that mpi3mr also updates the limits from an event handler that iterates all SCSI devices. This is also updated to use the queue_limits, but the complete locking of this path probably means it already is completely broken and needs a proper audit. Signed-off-by: Christoph Hellwig Link: https://lore.kernel.org/r/20240409143748.980206-22-hch@lst.de Reviewed-by: Damien Le Moal Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/mpi3mr/mpi3mr.h | 1 - drivers/scsi/mpi3mr/mpi3mr_os.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/scsi/mpi3mr/mpi3mr_os.c') diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index d1c93978f28a..f5a1529fa537 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -1352,7 +1352,6 @@ void mpi3mr_wait_for_host_io(struct mpi3mr_ioc *mrioc, u32 timeout); void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc); void mpi3mr_flush_host_io(struct mpi3mr_ioc *mrioc); void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc); -void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc); void mpi3mr_flush_delayed_cmd_lists(struct mpi3mr_ioc *mrioc); void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code); void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc); diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 71f2c62db111..bce639a6cca1 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1043,8 +1043,7 @@ mpi3mr_update_sdev(struct scsi_device *sdev, void *data) * * Return: Nothing. */ - -void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) +static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) { struct mpi3mr_tgt_dev *tgtdev, *tgtdev_next; struct mpi3mr_stgt_priv_data *tgt_priv; -- cgit v1.2.3-59-g8ed1b