Skip to content

Commit 8b2f5ff

Browse files
swapnilnagleNicholas Bellinger
authored andcommitted
qla2xxx: cleanup cmd in qla workqueue before processing TMR
Since cmds go into qla_tgt_wq and TMRs don't, it's possible that TMR like TASK_ABORT can be queued over the cmd for which it was meant. To avoid this race, use a per-port list to keep track of cmds that are enqueued to qla_tgt_wq but not yet processed. When a TMR arrives, iterate through this list and remove any cmds that match the TMR. This patch supports TASK_ABORT and LUN_RESET. Cc: <stable@vger.kernel.org> # v3.18+ Signed-off-by: Swapnil Nagle <swapnil.nagle@purestorage.com> Signed-off-by: Alexei Potashnik <alexei@purestorage.com> Acked-by: Quinn Tran <quinn.tran@qlogic.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
1 parent b2032fd commit 8b2f5ff

File tree

6 files changed

+140
-13
lines changed

6 files changed

+140
-13
lines changed

drivers/scsi/qla2xxx/qla_dbg.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
* | | | 0xd101-0xd1fe |
6969
* | | | 0xd214-0xd2fe |
7070
* | Target Mode | 0xe079 | |
71-
* | Target Mode Management | 0xf080 | 0xf002 |
71+
* | Target Mode Management | 0xf083 | 0xf002 |
7272
* | | | 0xf046-0xf049 |
7373
* | Target Mode Task Management | 0x1000b | |
7474
* ----------------------------------------------------------------------

drivers/scsi/qla2xxx/qla_def.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3579,6 +3579,11 @@ typedef struct scsi_qla_host {
35793579
uint16_t fcoe_fcf_idx;
35803580
uint8_t fcoe_vn_port_mac[6];
35813581

3582+
/* list of commands waiting on workqueue */
3583+
struct list_head qla_cmd_list;
3584+
struct list_head qla_sess_op_cmd_list;
3585+
spinlock_t cmd_list_lock;
3586+
35823587
uint32_t vp_abort_cnt;
35833588

35843589
struct fc_vport *fc_vport; /* holds fc_vport * for each vport */

drivers/scsi/qla2xxx/qla_os.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3764,8 +3764,11 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
37643764
INIT_LIST_HEAD(&vha->vp_fcports);
37653765
INIT_LIST_HEAD(&vha->work_list);
37663766
INIT_LIST_HEAD(&vha->list);
3767+
INIT_LIST_HEAD(&vha->qla_cmd_list);
3768+
INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list);
37673769

37683770
spin_lock_init(&vha->work_lock);
3771+
spin_lock_init(&vha->cmd_list_lock);
37693772

37703773
sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no);
37713774
ql_dbg(ql_dbg_init, vha, 0x0041,

drivers/scsi/qla2xxx/qla_target.c

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,6 +1170,70 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha,
11701170
FCP_TMF_CMPL, true);
11711171
}
11721172

1173+
static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag)
1174+
{
1175+
struct qla_tgt_sess_op *op;
1176+
struct qla_tgt_cmd *cmd;
1177+
1178+
spin_lock(&vha->cmd_list_lock);
1179+
1180+
list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
1181+
if (tag == op->atio.u.isp24.exchange_addr) {
1182+
op->aborted = true;
1183+
spin_unlock(&vha->cmd_list_lock);
1184+
return 1;
1185+
}
1186+
}
1187+
1188+
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
1189+
if (tag == cmd->atio.u.isp24.exchange_addr) {
1190+
cmd->state = QLA_TGT_STATE_ABORTED;
1191+
spin_unlock(&vha->cmd_list_lock);
1192+
return 1;
1193+
}
1194+
}
1195+
1196+
spin_unlock(&vha->cmd_list_lock);
1197+
return 0;
1198+
}
1199+
1200+
/* drop cmds for the given lun
1201+
* XXX only looks for cmds on the port through which lun reset was recieved
1202+
* XXX does not go through the list of other port (which may have cmds
1203+
* for the same lun)
1204+
*/
1205+
static void abort_cmds_for_lun(struct scsi_qla_host *vha,
1206+
uint32_t lun, uint8_t *s_id)
1207+
{
1208+
struct qla_tgt_sess_op *op;
1209+
struct qla_tgt_cmd *cmd;
1210+
uint32_t key;
1211+
1212+
key = sid_to_key(s_id);
1213+
spin_lock(&vha->cmd_list_lock);
1214+
list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) {
1215+
uint32_t op_key;
1216+
uint32_t op_lun;
1217+
1218+
op_key = sid_to_key(op->atio.u.isp24.fcp_hdr.s_id);
1219+
op_lun = scsilun_to_int(
1220+
(struct scsi_lun *)&op->atio.u.isp24.fcp_cmnd.lun);
1221+
if (op_key == key && op_lun == lun)
1222+
op->aborted = true;
1223+
}
1224+
list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) {
1225+
uint32_t cmd_key;
1226+
uint32_t cmd_lun;
1227+
1228+
cmd_key = sid_to_key(cmd->atio.u.isp24.fcp_hdr.s_id);
1229+
cmd_lun = scsilun_to_int(
1230+
(struct scsi_lun *)&cmd->atio.u.isp24.fcp_cmnd.lun);
1231+
if (cmd_key == key && cmd_lun == lun)
1232+
cmd->state = QLA_TGT_STATE_ABORTED;
1233+
}
1234+
spin_unlock(&vha->cmd_list_lock);
1235+
}
1236+
11731237
/* ha->hardware_lock supposed to be held on entry */
11741238
static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
11751239
struct abts_recv_from_24xx *abts, struct qla_tgt_sess *sess)
@@ -1194,8 +1258,19 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha,
11941258
}
11951259
spin_unlock(&se_sess->sess_cmd_lock);
11961260

1197-
if (!found_lun)
1198-
return -ENOENT;
1261+
/* cmd not in LIO lists, look in qla list */
1262+
if (!found_lun) {
1263+
if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) {
1264+
/* send TASK_ABORT response immediately */
1265+
qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_CMPL, false);
1266+
return 0;
1267+
} else {
1268+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf081,
1269+
"unable to find cmd in driver or LIO for tag 0x%x\n",
1270+
abts->exchange_addr_to_abort);
1271+
return -ENOENT;
1272+
}
1273+
}
11991274

12001275
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f,
12011276
"qla_target(%d): task abort (tag=%d)\n",
@@ -3264,6 +3339,13 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
32643339
if (tgt->tgt_stop)
32653340
goto out_term;
32663341

3342+
if (cmd->state == QLA_TGT_STATE_ABORTED) {
3343+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf082,
3344+
"cmd with tag %u is aborted\n",
3345+
cmd->atio.u.isp24.exchange_addr);
3346+
goto out_term;
3347+
}
3348+
32673349
cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
32683350
cmd->se_cmd.tag = atio->u.isp24.exchange_addr;
32693351
cmd->unpacked_lun = scsilun_to_int(
@@ -3317,6 +3399,12 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
33173399
static void qlt_do_work(struct work_struct *work)
33183400
{
33193401
struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
3402+
scsi_qla_host_t *vha = cmd->vha;
3403+
unsigned long flags;
3404+
3405+
spin_lock_irqsave(&vha->cmd_list_lock, flags);
3406+
list_del(&cmd->cmd_list);
3407+
spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
33203408

33213409
__qlt_do_work(cmd);
33223410
}
@@ -3368,14 +3456,25 @@ static void qlt_create_sess_from_atio(struct work_struct *work)
33683456
unsigned long flags;
33693457
uint8_t *s_id = op->atio.u.isp24.fcp_hdr.s_id;
33703458

3459+
spin_lock_irqsave(&vha->cmd_list_lock, flags);
3460+
list_del(&op->cmd_list);
3461+
spin_unlock_irqrestore(&vha->cmd_list_lock, flags);
3462+
3463+
if (op->aborted) {
3464+
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf083,
3465+
"sess_op with tag %u is aborted\n",
3466+
op->atio.u.isp24.exchange_addr);
3467+
goto out_term;
3468+
}
3469+
33713470
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf022,
3372-
"qla_target(%d): Unable to find wwn login"
3373-
" (s_id %x:%x:%x), trying to create it manually\n",
3374-
vha->vp_idx, s_id[0], s_id[1], s_id[2]);
3471+
"qla_target(%d): Unable to find wwn login"
3472+
" (s_id %x:%x:%x), trying to create it manually\n",
3473+
vha->vp_idx, s_id[0], s_id[1], s_id[2]);
33753474

33763475
if (op->atio.u.raw.entry_count > 1) {
33773476
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf023,
3378-
"Dropping multy entry atio %p\n", &op->atio);
3477+
"Dropping multy entry atio %p\n", &op->atio);
33793478
goto out_term;
33803479
}
33813480

@@ -3440,6 +3539,11 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
34403539

34413540
memcpy(&op->atio, atio, sizeof(*atio));
34423541
op->vha = vha;
3542+
3543+
spin_lock(&vha->cmd_list_lock);
3544+
list_add_tail(&op->cmd_list, &vha->qla_sess_op_cmd_list);
3545+
spin_unlock(&vha->cmd_list_lock);
3546+
34433547
INIT_WORK(&op->work, qlt_create_sess_from_atio);
34443548
queue_work(qla_tgt_wq, &op->work);
34453549
return 0;
@@ -3459,6 +3563,11 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
34593563

34603564
cmd->cmd_in_wq = 1;
34613565
cmd->cmd_flags |= BIT_0;
3566+
3567+
spin_lock(&vha->cmd_list_lock);
3568+
list_add_tail(&cmd->cmd_list, &vha->qla_cmd_list);
3569+
spin_unlock(&vha->cmd_list_lock);
3570+
34623571
INIT_WORK(&cmd->work, qlt_do_work);
34633572
queue_work(qla_tgt_wq, &cmd->work);
34643573
return 0;
@@ -3472,6 +3581,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
34723581
struct scsi_qla_host *vha = sess->vha;
34733582
struct qla_hw_data *ha = vha->hw;
34743583
struct qla_tgt_mgmt_cmd *mcmd;
3584+
struct atio_from_isp *a = (struct atio_from_isp *)iocb;
34753585
int res;
34763586
uint8_t tmr_func;
34773587

@@ -3512,6 +3622,7 @@ static int qlt_issue_task_mgmt(struct qla_tgt_sess *sess, uint32_t lun,
35123622
ql_dbg(ql_dbg_tgt_tmr, vha, 0x10002,
35133623
"qla_target(%d): LUN_RESET received\n", sess->vha->vp_idx);
35143624
tmr_func = TMR_LUN_RESET;
3625+
abort_cmds_for_lun(vha, lun, a->u.isp24.fcp_hdr.s_id);
35153626
break;
35163627

35173628
case QLA_TGT_CLEAR_TS:

drivers/scsi/qla2xxx/qla_target.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,8 @@ struct qla_tgt_sess_op {
874874
struct scsi_qla_host *vha;
875875
struct atio_from_isp atio;
876876
struct work_struct work;
877+
struct list_head cmd_list;
878+
bool aborted;
877879
};
878880

879881
/*
@@ -1076,6 +1078,16 @@ static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha)
10761078
ha->host->active_mode |= MODE_INITIATOR;
10771079
}
10781080

1081+
static inline uint32_t sid_to_key(const uint8_t *s_id)
1082+
{
1083+
uint32_t key;
1084+
1085+
key = (((unsigned long)s_id[0] << 16) |
1086+
((unsigned long)s_id[1] << 8) |
1087+
(unsigned long)s_id[2]);
1088+
return key;
1089+
}
1090+
10791091
/*
10801092
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
10811093
*/

drivers/scsi/qla2xxx/tcm_qla2xxx.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,7 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
11481148
return NULL;
11491149
}
11501150

1151-
key = (((unsigned long)s_id[0] << 16) |
1152-
((unsigned long)s_id[1] << 8) |
1153-
(unsigned long)s_id[2]);
1151+
key = sid_to_key(s_id);
11541152
pr_debug("find_sess_by_s_id: 0x%06x\n", key);
11551153

11561154
se_nacl = btree_lookup32(&lport->lport_fcport_map, key);
@@ -1185,9 +1183,7 @@ static void tcm_qla2xxx_set_sess_by_s_id(
11851183
void *slot;
11861184
int rc;
11871185

1188-
key = (((unsigned long)s_id[0] << 16) |
1189-
((unsigned long)s_id[1] << 8) |
1190-
(unsigned long)s_id[2]);
1186+
key = sid_to_key(s_id);
11911187
pr_debug("set_sess_by_s_id: %06x\n", key);
11921188

11931189
slot = btree_lookup32(&lport->lport_fcport_map, key);

0 commit comments

Comments
 (0)