summaryrefslogtreecommitdiff
path: root/drivers/scsi/pm8001/pm8001_sas.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-14 08:58:51 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-14 08:58:51 -0800
commitaa5ad10f6cca6d42f3fef6cb862e03b220ea19a6 (patch)
tree80da5833dccec9d952c8458c98c65864fca1186a /drivers/scsi/pm8001/pm8001_sas.c
parente2ca6ba6ba0152361aa4fcbf6067db71b2c7a770 (diff)
parent4e80eef45ad775a54fb06a66bf8267a154781ce5 (diff)
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "Updates to the usual drivers (target, ufs, smartpqi, lpfc). There are some core changes, mostly around reworking some of our user context assumptions in device put and moving some code around. The remaining updates are bug fixes and minor changes" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (138 commits) scsi: sg: Fix get_user() in call sg_scsi_ioctl() scsi: megaraid_sas: Fix some spelling mistakes in comment scsi: core: Use SCSI_SCAN_INITIAL in do_scsi_scan_host() scsi: core: Use SCSI_SCAN_RESCAN in __scsi_add_device() scsi: ufs: ufs-mediatek: Remove unnecessary return code scsi: ufs: core: Fix the polling implementation scsi: libsas: Do not export sas_ata_wait_after_reset() scsi: hisi_sas: Fix SATA devices missing issue during I_T nexus reset scsi: libsas: Add smp_ata_check_ready_type() scsi: Revert "scsi: hisi_sas: Don't send bcast events from HW during nexus HA reset" scsi: Revert "scsi: hisi_sas: Drain bcast events in hisi_sas_rescan_topology()" scsi: ufs: ufs-mediatek: Modify the return value scsi: ufs: ufs-mediatek: Remove unneeded code scsi: device_handler: alua: Call scsi_device_put() from non-atomic context scsi: device_handler: alua: Revert "Move a scsi_device_put() call out of alua_check_vpd()" scsi: snic: Fix possible UAF in snic_tgt_create() scsi: qla2xxx: Initialize vha->unknown_atio_[list, work] for NPIV hosts scsi: qla2xxx: Remove duplicate of vha->iocb_work initialization scsi: fcoe: Fix transport not deattached when fcoe_if_init() fails scsi: sd: Use 16-byte SYNCHRONIZE CACHE on ZBC devices ...
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_sas.c')
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c54
1 files changed, 24 insertions, 30 deletions
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 8e3f2f9ddaac..e5673c774f66 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -65,9 +65,12 @@ static int pm8001_find_tag(struct sas_task *task, u32 *tag)
*/
void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag)
{
- void *bitmap = pm8001_ha->tags;
+ void *bitmap = pm8001_ha->rsvd_tags;
unsigned long flags;
+ if (tag >= PM8001_RESERVE_SLOT)
+ return;
+
spin_lock_irqsave(&pm8001_ha->bitmap_lock, flags);
__clear_bit(tag, bitmap);
spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags);
@@ -80,29 +83,24 @@ void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag)
*/
int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out)
{
- void *bitmap = pm8001_ha->tags;
+ void *bitmap = pm8001_ha->rsvd_tags;
unsigned long flags;
unsigned int tag;
spin_lock_irqsave(&pm8001_ha->bitmap_lock, flags);
- tag = find_first_zero_bit(bitmap, pm8001_ha->tags_num);
- if (tag >= pm8001_ha->tags_num) {
+ tag = find_first_zero_bit(bitmap, PM8001_RESERVE_SLOT);
+ if (tag >= PM8001_RESERVE_SLOT) {
spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags);
return -SAS_QUEUE_FULL;
}
__set_bit(tag, bitmap);
spin_unlock_irqrestore(&pm8001_ha->bitmap_lock, flags);
+
+ /* reserved tags are in the lower region of the tagset */
*tag_out = tag;
return 0;
}
-void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha)
-{
- int i;
- for (i = 0; i < pm8001_ha->tags_num; ++i)
- pm8001_tag_free(pm8001_ha, i);
-}
-
/**
* pm8001_mem_alloc - allocate memory for pm8001.
* @pdev: pci device.
@@ -645,22 +643,16 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
pm8001_device->dcompletion = &completion;
if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
int phy_id;
- struct ex_phy *phy;
- for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys;
- phy_id++) {
- phy = &parent_dev->ex_dev.ex_phy[phy_id];
- if (SAS_ADDR(phy->attached_sas_addr)
- == SAS_ADDR(dev->sas_addr)) {
- pm8001_device->attached_phy = phy_id;
- break;
- }
- }
- if (phy_id == parent_dev->ex_dev.num_phys) {
+
+ phy_id = sas_find_attached_phy_id(&parent_dev->ex_dev, dev);
+ if (phy_id < 0) {
pm8001_dbg(pm8001_ha, FAIL,
"Error: no attached dev:%016llx at ex:%016llx.\n",
SAS_ADDR(dev->sas_addr),
SAS_ADDR(parent_dev->sas_addr));
- res = -1;
+ res = phy_id;
+ } else {
+ pm8001_device->attached_phy = phy_id;
}
} else {
if (dev->dev_type == SAS_SATA_DEV) {
@@ -687,12 +679,6 @@ int pm8001_dev_found(struct domain_device *dev)
return pm8001_dev_found_notify(dev);
}
-void pm8001_task_done(struct sas_task *task)
-{
- del_timer(&task->slow_task->timer);
- complete(&task->slow_task->completion);
-}
-
#define PM8001_TASK_TIMEOUT 20
/**
@@ -983,6 +969,7 @@ int pm8001_query_task(struct sas_task *task)
/* mandatory SAM-3, still need free task/ccb info, abort the specified task */
int pm8001_abort_task(struct sas_task *task)
{
+ struct pm8001_ccb_info *ccb = task->lldd_task;
unsigned long flags;
u32 tag;
struct domain_device *dev ;
@@ -992,7 +979,7 @@ int pm8001_abort_task(struct sas_task *task)
u32 phy_id, port_id;
struct sas_task_slow slow_task;
- if (unlikely(!task || !task->lldd_task || !task->dev))
+ if (!task->lldd_task || !task->dev)
return TMF_RESP_FUNC_FAILED;
dev = task->dev;
@@ -1113,6 +1100,13 @@ int pm8001_abort_task(struct sas_task *task)
pm8001_dev, DS_OPERATIONAL);
wait_for_completion(&completion);
} else {
+ /*
+ * Ensure that if we see a completion for the ccb
+ * associated with the task which we are trying to
+ * abort then we should not touch the sas_task as it
+ * may race with libsas freeing it when return here.
+ */
+ ccb->task = NULL;
ret = sas_execute_internal_abort_single(dev, tag, 0, NULL);
}
rc = TMF_RESP_FUNC_COMPLETE;