Skip to content

Commit 8d26bfc

Browse files
Karan Tilak Kumarmartinkpetersen
authored andcommitted
scsi: fnic: Add support to handle port channel RSCN
Add support to handle port channel RSCN. Port channel RSCN is a Cisco vendor specific RSCN event. It is applicable only to Cisco UCS fabrics. If there's a change in the port channel configuration, an RCSN is sent to fnic. This is used to serially reset the scsi initiator fnics so that there's no all paths down scenario. The affected fnics are added to a list that are reset with a small time gap between them. Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com> Reviewed-by: Arulprabhu Ponnusamy <arulponn@cisco.com> Reviewed-by: Gian Carlo Boffa <gcboffa@cisco.com> Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com> Link: https://lore.kernel.org/r/20241212020312.4786-15-kartilak@cisco.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 7e6886b commit 8d26bfc

File tree

4 files changed

+138
-9
lines changed

4 files changed

+138
-9
lines changed

drivers/scsi/fnic/fdls_disc.c

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4405,6 +4405,9 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr)
44054405
int newports = 0;
44064406
struct fnic_fdls_fabric_s *fdls = &iport->fabric;
44074407
struct fnic *fnic = iport->fnic;
4408+
int rscn_type = NOT_PC_RSCN;
4409+
uint32_t sid = ntoh24(fchdr->fh_s_id);
4410+
unsigned long reset_fnic_list_lock_flags = 0;
44084411
uint16_t rscn_payload_len;
44094412

44104413
atomic64_inc(&iport->iport_stats.num_rscns);
@@ -4427,16 +4430,24 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr)
44274430
|| (rscn_payload_len > 1024)
44284431
|| (rscn->els.rscn_page_len != 4)) {
44294432
num_ports = 0;
4430-
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4433+
if ((rscn_payload_len == 0xFFFF)
4434+
&& (sid == FC_FID_FCTRL)) {
4435+
rscn_type = PC_RSCN;
4436+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4437+
"pcrscn: PCRSCN received. sid: 0x%x payload len: 0x%x",
4438+
sid, rscn_payload_len);
4439+
} else {
4440+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
44314441
"RSCN payload_len: 0x%x page_len: 0x%x",
44324442
rscn_payload_len, rscn->els.rscn_page_len);
4433-
/* if this happens then we need to send ADISC to all the tports. */
4434-
list_for_each_entry_safe(tport, next, &iport->tport_list, links) {
4435-
if (tport->state == FDLS_TGT_STATE_READY)
4436-
tport->flags |= FNIC_FDLS_TPORT_SEND_ADISC;
4437-
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4438-
"RSCN for port id: 0x%x", tport->fcid);
4439-
}
4443+
/* if this happens then we need to send ADISC to all the tports. */
4444+
list_for_each_entry_safe(tport, next, &iport->tport_list, links) {
4445+
if (tport->state == FDLS_TGT_STATE_READY)
4446+
tport->flags |= FNIC_FDLS_TPORT_SEND_ADISC;
4447+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4448+
"RSCN for port id: 0x%x", tport->fcid);
4449+
}
4450+
} /* end else */
44404451
} else {
44414452
num_ports = (rscn_payload_len - 4) / rscn->els.rscn_page_len;
44424453
rscn_port = (struct fc_els_rscn_page *)(rscn + 1);
@@ -4483,10 +4494,37 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr)
44834494
tport->flags |= FNIC_FDLS_TPORT_SEND_ADISC;
44844495
}
44854496

4486-
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4497+
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON &&
4498+
rscn_type == PC_RSCN && fnic->role == FNIC_ROLE_FCP_INITIATOR) {
4499+
4500+
if (fnic->pc_rscn_handling_status == PC_RSCN_HANDLING_IN_PROGRESS) {
4501+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4502+
"PCRSCN handling already in progress. Skip host reset: %d",
4503+
iport->fnic->fnic_num);
4504+
return;
4505+
}
4506+
4507+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
4508+
"Processing PCRSCN. Queuing fnic for host reset: %d",
4509+
iport->fnic->fnic_num);
4510+
fnic->pc_rscn_handling_status = PC_RSCN_HANDLING_IN_PROGRESS;
4511+
4512+
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
4513+
4514+
spin_lock_irqsave(&reset_fnic_list_lock,
4515+
reset_fnic_list_lock_flags);
4516+
list_add_tail(&fnic->links, &reset_fnic_list);
4517+
spin_unlock_irqrestore(&reset_fnic_list_lock,
4518+
reset_fnic_list_lock_flags);
4519+
4520+
queue_work(reset_fnic_work_queue, &reset_fnic_work);
4521+
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
4522+
} else {
4523+
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
44874524
"FDLS process RSCN sending GPN_FT: newports: %d", newports);
44884525
fdls_send_gpn_ft(iport, FDLS_STATE_RSCN_GPN_FT);
44894526
fdls_send_rscn_resp(iport, fchdr);
4527+
}
44904528
}
44914529

44924530
void fnic_fdls_disc_start(struct fnic_iport_s *iport)

drivers/scsi/fnic/fnic.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,33 @@ enum reset_states {
211211
RESET_ERROR
212212
};
213213

214+
enum rscn_type {
215+
NOT_PC_RSCN = 0,
216+
PC_RSCN
217+
};
218+
219+
enum pc_rscn_handling_status {
220+
PC_RSCN_HANDLING_NOT_IN_PROGRESS = 0,
221+
PC_RSCN_HANDLING_IN_PROGRESS
222+
};
223+
224+
enum pc_rscn_handling_feature {
225+
PC_RSCN_HANDLING_FEATURE_OFF = 0,
226+
PC_RSCN_HANDLING_FEATURE_ON
227+
};
228+
214229
extern unsigned int fnic_fdmi_support;
215230
extern unsigned int fnic_log_level;
216231
extern unsigned int io_completions;
217232
extern struct workqueue_struct *fnic_event_queue;
218233

234+
extern unsigned int pc_rscn_handling_feature_flag;
235+
extern spinlock_t reset_fnic_list_lock;
236+
extern struct list_head reset_fnic_list;
237+
extern struct workqueue_struct *reset_fnic_work_queue;
238+
extern struct work_struct reset_fnic_work;
239+
240+
219241
#define FNIC_MAIN_LOGGING 0x01
220242
#define FNIC_FCS_LOGGING 0x02
221243
#define FNIC_SCSI_LOGGING 0x04
@@ -396,6 +418,7 @@ struct fnic {
396418
int link_status;
397419

398420
struct list_head list;
421+
struct list_head links;
399422
struct pci_dev *pdev;
400423
struct vnic_fc_config config;
401424
struct vnic_dev *vdev;
@@ -424,6 +447,7 @@ struct fnic {
424447

425448
char subsys_desc[14];
426449
int subsys_desc_len;
450+
int pc_rscn_handling_status;
427451

428452
/*** FIP related data members -- start ***/
429453
void (*set_vlan)(struct fnic *, u16 vlan);
@@ -508,6 +532,7 @@ void fnic_stats_debugfs_remove(struct fnic *fnic);
508532
int fnic_is_abts_pending(struct fnic *, struct scsi_cmnd *);
509533

510534
void fnic_handle_fip_frame(struct work_struct *work);
535+
void fnic_reset_work_handler(struct work_struct *work);
511536
void fnic_handle_fip_event(struct fnic *fnic);
512537
void fnic_fcoe_reset_vlans(struct fnic *fnic);
513538
extern void fnic_handle_fip_timer(struct timer_list *t);

drivers/scsi/fnic/fnic_fcs.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,3 +1071,39 @@ void fnic_flush_tport_event_list(struct fnic *fnic)
10711071
}
10721072
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
10731073
}
1074+
1075+
void fnic_reset_work_handler(struct work_struct *work)
1076+
{
1077+
struct fnic *cur_fnic, *next_fnic;
1078+
unsigned long reset_fnic_list_lock_flags;
1079+
int host_reset_ret_code;
1080+
1081+
/*
1082+
* This is a single thread. It is per fnic module, not per fnic
1083+
* All the fnics that need to be reset
1084+
* have been serialized via the reset fnic list.
1085+
*/
1086+
spin_lock_irqsave(&reset_fnic_list_lock, reset_fnic_list_lock_flags);
1087+
list_for_each_entry_safe(cur_fnic, next_fnic, &reset_fnic_list, links) {
1088+
list_del(&cur_fnic->links);
1089+
spin_unlock_irqrestore(&reset_fnic_list_lock,
1090+
reset_fnic_list_lock_flags);
1091+
1092+
dev_err(&cur_fnic->pdev->dev, "fnic: <%d>: issuing a host reset\n",
1093+
cur_fnic->fnic_num);
1094+
host_reset_ret_code = fnic_host_reset(cur_fnic->host);
1095+
dev_err(&cur_fnic->pdev->dev,
1096+
"fnic: <%d>: returned from host reset with status: %d\n",
1097+
cur_fnic->fnic_num, host_reset_ret_code);
1098+
1099+
spin_lock_irqsave(&cur_fnic->fnic_lock, cur_fnic->lock_flags);
1100+
cur_fnic->pc_rscn_handling_status =
1101+
PC_RSCN_HANDLING_NOT_IN_PROGRESS;
1102+
spin_unlock_irqrestore(&cur_fnic->fnic_lock, cur_fnic->lock_flags);
1103+
1104+
spin_lock_irqsave(&reset_fnic_list_lock,
1105+
reset_fnic_list_lock_flags);
1106+
}
1107+
spin_unlock_irqrestore(&reset_fnic_list_lock,
1108+
reset_fnic_list_lock_flags);
1109+
}

drivers/scsi/fnic/fnic_main.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ static LIST_HEAD(fnic_list);
4545
static DEFINE_SPINLOCK(fnic_list_lock);
4646
static DEFINE_IDA(fnic_ida);
4747

48+
struct work_struct reset_fnic_work;
49+
LIST_HEAD(reset_fnic_list);
50+
DEFINE_SPINLOCK(reset_fnic_list_lock);
51+
4852
/* Supported devices by fnic module */
4953
static struct pci_device_id fnic_id_table[] = {
5054
{ PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_FNIC) },
@@ -89,6 +93,12 @@ static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
8993
module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
9094
MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
9195

96+
unsigned int pc_rscn_handling_feature_flag = PC_RSCN_HANDLING_FEATURE_ON;
97+
module_param(pc_rscn_handling_feature_flag, uint, 0644);
98+
MODULE_PARM_DESC(pc_rscn_handling_feature_flag,
99+
"PCRSCN handling (0 for none. 1 to handle PCRSCN (default))");
100+
101+
struct workqueue_struct *reset_fnic_work_queue;
92102
struct workqueue_struct *fnic_fip_queue;
93103

94104
static int fnic_slave_alloc(struct scsi_device *sdev)
@@ -1275,6 +1285,19 @@ static int __init fnic_init_module(void)
12751285
goto err_create_fip_workq;
12761286
}
12771287

1288+
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) {
1289+
reset_fnic_work_queue =
1290+
create_singlethread_workqueue("reset_fnic_work_queue");
1291+
if (!reset_fnic_work_queue) {
1292+
pr_err("reset fnic work queue create failed\n");
1293+
err = -ENOMEM;
1294+
goto err_create_reset_fnic_workq;
1295+
}
1296+
spin_lock_init(&reset_fnic_list_lock);
1297+
INIT_LIST_HEAD(&reset_fnic_list);
1298+
INIT_WORK(&reset_fnic_work, fnic_reset_work_handler);
1299+
}
1300+
12781301
fnic_fc_transport = fc_attach_transport(&fnic_fc_functions);
12791302
if (!fnic_fc_transport) {
12801303
printk(KERN_ERR PFX "fc_attach_transport error\n");
@@ -1295,6 +1318,9 @@ static int __init fnic_init_module(void)
12951318
err_fc_transport:
12961319
destroy_workqueue(fnic_fip_queue);
12971320
err_create_fip_workq:
1321+
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)
1322+
destroy_workqueue(reset_fnic_work_queue);
1323+
err_create_reset_fnic_workq:
12981324
destroy_workqueue(fnic_event_queue);
12991325
err_create_fnic_workq:
13001326
kmem_cache_destroy(fdls_frame_elem_cache);
@@ -1317,6 +1343,10 @@ static void __exit fnic_cleanup_module(void)
13171343
{
13181344
pci_unregister_driver(&fnic_driver);
13191345
destroy_workqueue(fnic_event_queue);
1346+
1347+
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)
1348+
destroy_workqueue(reset_fnic_work_queue);
1349+
13201350
if (fnic_fip_queue) {
13211351
flush_workqueue(fnic_fip_queue);
13221352
destroy_workqueue(fnic_fip_queue);

0 commit comments

Comments
 (0)