mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 00:10:09 +00:00
scsi: pm8001: Fix tag values handling
[ Upstream commit 7fb23a785b
]
The function pm8001_tag_alloc() determines free tags using the function
find_first_zero_bit() which can return 0 when the first bit of the bitmap
being inspected is 0. As such, tag 0 is a valid tag value that should not
be dismissed as invalid. Fix the functions pm8001_work_fn(),
mpi_sata_completion(), pm8001_mpi_task_abort_resp() and
pm8001_open_reject_retry() to not dismiss 0 tags as invalid.
The value 0xffffffff is used for invalid tags for unused ccb information
structures. Add the macro definition PM8001_INVALID_TAG to define this
value.
Link: https://lore.kernel.org/r/20220220031810.738362-20-damien.lemoal@opensource.wdc.com
Reviewed-by: Jack Wang <jinpu.wang@ionos.com>
Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
377da5df07
commit
73b37c122d
5 changed files with 28 additions and 47 deletions
|
@ -1522,7 +1522,6 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
case IO_XFER_ERROR_BREAK:
|
case IO_XFER_ERROR_BREAK:
|
||||||
{ /* This one stashes the sas_task instead */
|
{ /* This one stashes the sas_task instead */
|
||||||
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
||||||
u32 tag;
|
|
||||||
struct pm8001_ccb_info *ccb;
|
struct pm8001_ccb_info *ccb;
|
||||||
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
||||||
unsigned long flags, flags1;
|
unsigned long flags, flags1;
|
||||||
|
@ -1544,8 +1543,8 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
/* Search for a possible ccb that matches the task */
|
/* Search for a possible ccb that matches the task */
|
||||||
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
||||||
ccb = &pm8001_ha->ccb_info[i];
|
ccb = &pm8001_ha->ccb_info[i];
|
||||||
tag = ccb->ccb_tag;
|
if ((ccb->ccb_tag != PM8001_INVALID_TAG) &&
|
||||||
if ((tag != 0xFFFFFFFF) && (ccb->task == t))
|
(ccb->task == t))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!ccb) {
|
if (!ccb) {
|
||||||
|
@ -1567,11 +1566,11 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||||
pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
|
pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
|
||||||
t, pw->handler, ts->resp, ts->stat);
|
t, pw->handler, ts->resp, ts->stat);
|
||||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
pm8001_ccb_task_free(pm8001_ha, t, ccb, ccb->ccb_tag);
|
||||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||||
} else {
|
} else {
|
||||||
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
spin_unlock_irqrestore(&t->task_state_lock, flags1);
|
||||||
pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
|
pm8001_ccb_task_free(pm8001_ha, t, ccb, ccb->ccb_tag);
|
||||||
mb();/* in order to force CPU ordering */
|
mb();/* in order to force CPU ordering */
|
||||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||||
t->task_done(t);
|
t->task_done(t);
|
||||||
|
@ -1580,7 +1579,6 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
case IO_XFER_OPEN_RETRY_TIMEOUT:
|
case IO_XFER_OPEN_RETRY_TIMEOUT:
|
||||||
{ /* This one stashes the sas_task instead */
|
{ /* This one stashes the sas_task instead */
|
||||||
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
struct sas_task *t = (struct sas_task *)pm8001_dev;
|
||||||
u32 tag;
|
|
||||||
struct pm8001_ccb_info *ccb;
|
struct pm8001_ccb_info *ccb;
|
||||||
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
|
||||||
unsigned long flags, flags1;
|
unsigned long flags, flags1;
|
||||||
|
@ -1614,8 +1612,8 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
/* Search for a possible ccb that matches the task */
|
/* Search for a possible ccb that matches the task */
|
||||||
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
||||||
ccb = &pm8001_ha->ccb_info[i];
|
ccb = &pm8001_ha->ccb_info[i];
|
||||||
tag = ccb->ccb_tag;
|
if ((ccb->ccb_tag != PM8001_INVALID_TAG) &&
|
||||||
if ((tag != 0xFFFFFFFF) && (ccb->task == t))
|
(ccb->task == t))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!ccb) {
|
if (!ccb) {
|
||||||
|
@ -1686,19 +1684,13 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
struct task_status_struct *ts;
|
struct task_status_struct *ts;
|
||||||
struct sas_task *task;
|
struct sas_task *task;
|
||||||
int i;
|
int i;
|
||||||
u32 tag, device_id;
|
u32 device_id;
|
||||||
|
|
||||||
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
|
||||||
ccb = &pm8001_ha->ccb_info[i];
|
ccb = &pm8001_ha->ccb_info[i];
|
||||||
task = ccb->task;
|
task = ccb->task;
|
||||||
ts = &task->task_status;
|
ts = &task->task_status;
|
||||||
tag = ccb->ccb_tag;
|
|
||||||
/* check if tag is NULL */
|
|
||||||
if (!tag) {
|
|
||||||
pm8001_dbg(pm8001_ha, FAIL,
|
|
||||||
"tag Null\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (task != NULL) {
|
if (task != NULL) {
|
||||||
dev = task->dev;
|
dev = task->dev;
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
|
@ -1707,10 +1699,11 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/*complete sas task and update to top layer */
|
/*complete sas task and update to top layer */
|
||||||
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
|
pm8001_ccb_task_free(pm8001_ha, task, ccb,
|
||||||
|
ccb->ccb_tag);
|
||||||
ts->resp = SAS_TASK_COMPLETE;
|
ts->resp = SAS_TASK_COMPLETE;
|
||||||
task->task_done(task);
|
task->task_done(task);
|
||||||
} else if (tag != 0xFFFFFFFF) {
|
} else if (ccb->ccb_tag != PM8001_INVALID_TAG) {
|
||||||
/* complete the internal commands/non-sas task */
|
/* complete the internal commands/non-sas task */
|
||||||
pm8001_dev = ccb->device;
|
pm8001_dev = ccb->device;
|
||||||
if (pm8001_dev->dcompletion) {
|
if (pm8001_dev->dcompletion) {
|
||||||
|
@ -1718,7 +1711,7 @@ void pm8001_work_fn(struct work_struct *work)
|
||||||
pm8001_dev->dcompletion = NULL;
|
pm8001_dev->dcompletion = NULL;
|
||||||
}
|
}
|
||||||
complete(pm8001_ha->nvmd_completion);
|
complete(pm8001_ha->nvmd_completion);
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, ccb->ccb_tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Deregister all the device ids */
|
/* Deregister all the device ids */
|
||||||
|
@ -2316,11 +2309,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
param = le32_to_cpu(psataPayload->param);
|
param = le32_to_cpu(psataPayload->param);
|
||||||
tag = le32_to_cpu(psataPayload->tag);
|
tag = le32_to_cpu(psataPayload->tag);
|
||||||
|
|
||||||
if (!tag) {
|
|
||||||
pm8001_dbg(pm8001_ha, FAIL, "tag null\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ccb = &pm8001_ha->ccb_info[tag];
|
ccb = &pm8001_ha->ccb_info[tag];
|
||||||
t = ccb->task;
|
t = ccb->task;
|
||||||
pm8001_dev = ccb->device;
|
pm8001_dev = ccb->device;
|
||||||
|
@ -3056,7 +3044,7 @@ void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha,
|
||||||
device_id, pds, nds, status);
|
device_id, pds, nds, status);
|
||||||
complete(pm8001_dev->setds_completion);
|
complete(pm8001_dev->setds_completion);
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3074,7 +3062,7 @@ void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
dlen_status);
|
dlen_status);
|
||||||
}
|
}
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3101,7 +3089,7 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
* freed by requesting path anywhere.
|
* freed by requesting path anywhere.
|
||||||
*/
|
*/
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3147,7 +3135,7 @@ pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
complete(pm8001_ha->nvmd_completion);
|
complete(pm8001_ha->nvmd_completion);
|
||||||
pm8001_dbg(pm8001_ha, MSG, "Get nvmd data complete!\n");
|
pm8001_dbg(pm8001_ha, MSG, "Get nvmd data complete!\n");
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3560,7 +3548,7 @@ int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
}
|
}
|
||||||
complete(pm8001_dev->dcompletion);
|
complete(pm8001_dev->dcompletion);
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, htag);
|
pm8001_tag_free(pm8001_ha, htag);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3632,7 +3620,7 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
|
||||||
}
|
}
|
||||||
kfree(ccb->fw_control_context);
|
kfree(ccb->fw_control_context);
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_tag_free(pm8001_ha, tag);
|
pm8001_tag_free(pm8001_ha, tag);
|
||||||
complete(pm8001_ha->nvmd_completion);
|
complete(pm8001_ha->nvmd_completion);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3668,10 +3656,6 @@ int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
|
||||||
|
|
||||||
status = le32_to_cpu(pPayload->status);
|
status = le32_to_cpu(pPayload->status);
|
||||||
tag = le32_to_cpu(pPayload->tag);
|
tag = le32_to_cpu(pPayload->tag);
|
||||||
if (!tag) {
|
|
||||||
pm8001_dbg(pm8001_ha, FAIL, " TAG NULL. RETURNING !!!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
scp = le32_to_cpu(pPayload->scp);
|
scp = le32_to_cpu(pPayload->scp);
|
||||||
ccb = &pm8001_ha->ccb_info[tag];
|
ccb = &pm8001_ha->ccb_info[tag];
|
||||||
|
|
|
@ -1216,10 +1216,11 @@ pm8001_init_ccb_tag(struct pm8001_hba_info *pm8001_ha, struct Scsi_Host *shost,
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
pm8001_ha->ccb_info[i].task = NULL;
|
pm8001_ha->ccb_info[i].task = NULL;
|
||||||
pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff;
|
pm8001_ha->ccb_info[i].ccb_tag = PM8001_INVALID_TAG;
|
||||||
pm8001_ha->ccb_info[i].device = NULL;
|
pm8001_ha->ccb_info[i].device = NULL;
|
||||||
++pm8001_ha->tags_num;
|
++pm8001_ha->tags_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_out_noccb:
|
err_out_noccb:
|
||||||
|
|
|
@ -567,7 +567,7 @@ void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
|
||||||
|
|
||||||
task->lldd_task = NULL;
|
task->lldd_task = NULL;
|
||||||
ccb->task = NULL;
|
ccb->task = NULL;
|
||||||
ccb->ccb_tag = 0xFFFFFFFF;
|
ccb->ccb_tag = PM8001_INVALID_TAG;
|
||||||
ccb->open_retry = 0;
|
ccb->open_retry = 0;
|
||||||
pm8001_tag_free(pm8001_ha, ccb_idx);
|
pm8001_tag_free(pm8001_ha, ccb_idx);
|
||||||
}
|
}
|
||||||
|
@ -952,9 +952,11 @@ void pm8001_open_reject_retry(
|
||||||
struct task_status_struct *ts;
|
struct task_status_struct *ts;
|
||||||
struct pm8001_device *pm8001_dev;
|
struct pm8001_device *pm8001_dev;
|
||||||
unsigned long flags1;
|
unsigned long flags1;
|
||||||
u32 tag;
|
|
||||||
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i];
|
struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i];
|
||||||
|
|
||||||
|
if (ccb->ccb_tag == PM8001_INVALID_TAG)
|
||||||
|
continue;
|
||||||
|
|
||||||
pm8001_dev = ccb->device;
|
pm8001_dev = ccb->device;
|
||||||
if (!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED))
|
if (!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED))
|
||||||
continue;
|
continue;
|
||||||
|
@ -966,9 +968,6 @@ void pm8001_open_reject_retry(
|
||||||
continue;
|
continue;
|
||||||
} else if (pm8001_dev != device_to_close)
|
} else if (pm8001_dev != device_to_close)
|
||||||
continue;
|
continue;
|
||||||
tag = ccb->ccb_tag;
|
|
||||||
if (!tag || (tag == 0xFFFFFFFF))
|
|
||||||
continue;
|
|
||||||
task = ccb->task;
|
task = ccb->task;
|
||||||
if (!task || !task->task_done)
|
if (!task || !task->task_done)
|
||||||
continue;
|
continue;
|
||||||
|
@ -989,11 +988,11 @@ void pm8001_open_reject_retry(
|
||||||
& SAS_TASK_STATE_ABORTED))) {
|
& SAS_TASK_STATE_ABORTED))) {
|
||||||
spin_unlock_irqrestore(&task->task_state_lock,
|
spin_unlock_irqrestore(&task->task_state_lock,
|
||||||
flags1);
|
flags1);
|
||||||
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
|
pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb->ccb_tag);
|
||||||
} else {
|
} else {
|
||||||
spin_unlock_irqrestore(&task->task_state_lock,
|
spin_unlock_irqrestore(&task->task_state_lock,
|
||||||
flags1);
|
flags1);
|
||||||
pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
|
pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb->ccb_tag);
|
||||||
mb();/* in order to force CPU ordering */
|
mb();/* in order to force CPU ordering */
|
||||||
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
|
||||||
task->task_done(task);
|
task->task_done(task);
|
||||||
|
|
|
@ -738,6 +738,8 @@ void pm8001_free_dev(struct pm8001_device *pm8001_dev);
|
||||||
/* ctl shared API */
|
/* ctl shared API */
|
||||||
extern const struct attribute_group *pm8001_host_groups[];
|
extern const struct attribute_group *pm8001_host_groups[];
|
||||||
|
|
||||||
|
#define PM8001_INVALID_TAG ((u32)-1)
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
|
pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
|
||||||
struct sas_task *task, struct pm8001_ccb_info *ccb,
|
struct sas_task *task, struct pm8001_ccb_info *ccb,
|
||||||
|
|
|
@ -2404,11 +2404,6 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
|
||||||
param = le32_to_cpu(psataPayload->param);
|
param = le32_to_cpu(psataPayload->param);
|
||||||
tag = le32_to_cpu(psataPayload->tag);
|
tag = le32_to_cpu(psataPayload->tag);
|
||||||
|
|
||||||
if (!tag) {
|
|
||||||
pm8001_dbg(pm8001_ha, FAIL, "tag null\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ccb = &pm8001_ha->ccb_info[tag];
|
ccb = &pm8001_ha->ccb_info[tag];
|
||||||
t = ccb->task;
|
t = ccb->task;
|
||||||
pm8001_dev = ccb->device;
|
pm8001_dev = ccb->device;
|
||||||
|
|
Loading…
Reference in a new issue