aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2008-04-03 16:13:18 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-07 13:19:13 -0400
commit0971de7f56f809f40edae6fd372745e429e970e9 (patch)
tree8ae6829060081a81e62193db81278f6aa5365e08 /drivers/scsi/qla2xxx
parentc6952483b070ec8a4f2450d1116be908fe59edcc (diff)
[SCSI] qla2xxx: Add FC-transport Asynchronous Event Notification support.
Supported events include LIP, LIP reset, RSCN, link up, and link down. To support AEN (and additional forthcoming features), we also introduce a simple deferred-work construct to manage events which require a non-atomic sleeping-capable context. This work-list is processed as part of the driver's standard DPC routine. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h22
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c73
4 files changed, 102 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index f70c78b6f364..35c730a3f0da 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -2115,6 +2115,26 @@ struct qla_msix_entry {
2115 2115
2116#define WATCH_INTERVAL 1 /* number of seconds */ 2116#define WATCH_INTERVAL 1 /* number of seconds */
2117 2117
2118/* Work events. */
2119enum qla_work_type {
2120 QLA_EVT_AEN,
2121};
2122
2123
2124struct qla_work_evt {
2125 struct list_head list;
2126 enum qla_work_type type;
2127 u32 flags;
2128#define QLA_EVT_FLAG_FREE 0x1
2129
2130 union {
2131 struct {
2132 enum fc_host_event_code code;
2133 u32 data;
2134 } aen;
2135 } u;
2136};
2137
2118/* 2138/*
2119 * Linux Host Adapter structure 2139 * Linux Host Adapter structure
2120 */ 2140 */
@@ -2354,6 +2374,8 @@ typedef struct scsi_qla_host {
2354 uint32_t login_retry_count; 2374 uint32_t login_retry_count;
2355 int max_q_depth; 2375 int max_q_depth;
2356 2376
2377 struct list_head work_list;
2378
2357 /* Fibre Channel Device List. */ 2379 /* Fibre Channel Device List. */
2358 struct list_head fcports; 2380 struct list_head fcports;
2359 2381
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 97625d49a43c..ee52f3e51cc6 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -67,6 +67,8 @@ extern int num_hosts;
67 67
68extern int qla2x00_loop_reset(scsi_qla_host_t *); 68extern int qla2x00_loop_reset(scsi_qla_host_t *);
69extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); 69extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
70extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
71 fc_host_event_code, u32);
70 72
71/* 73/*
72 * Global Functions in qla_mid.c source file. 74 * Global Functions in qla_mid.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 4e9f41034466..e9d8a79dd6a4 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -408,6 +408,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
408 set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); 408 set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
409 409
410 ha->flags.management_server_logged_in = 0; 410 ha->flags.management_server_logged_in = 0;
411 qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]);
411 break; 412 break;
412 413
413 case MBA_LOOP_UP: /* Loop Up Event */ 414 case MBA_LOOP_UP: /* Loop Up Event */
@@ -427,6 +428,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
427 link_speed); 428 link_speed);
428 429
429 ha->flags.management_server_logged_in = 0; 430 ha->flags.management_server_logged_in = 0;
431 qla2x00_post_aen_work(ha, FCH_EVT_LINKUP, ha->link_data_rate);
430 break; 432 break;
431 433
432 case MBA_LOOP_DOWN: /* Loop Down Event */ 434 case MBA_LOOP_DOWN: /* Loop Down Event */
@@ -450,6 +452,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
450 ha->link_data_rate = PORT_SPEED_UNKNOWN; 452 ha->link_data_rate = PORT_SPEED_UNKNOWN;
451 if (ql2xfdmienable) 453 if (ql2xfdmienable)
452 set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); 454 set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
455 qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0);
453 break; 456 break;
454 457
455 case MBA_LIP_RESET: /* LIP reset occurred */ 458 case MBA_LIP_RESET: /* LIP reset occurred */
@@ -473,6 +476,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
473 476
474 ha->operating_mode = LOOP; 477 ha->operating_mode = LOOP;
475 ha->flags.management_server_logged_in = 0; 478 ha->flags.management_server_logged_in = 0;
479 qla2x00_post_aen_work(ha, FCH_EVT_LIPRESET, mb[1]);
476 break; 480 break;
477 481
478 case MBA_POINT_TO_POINT: /* Point-to-Point */ 482 case MBA_POINT_TO_POINT: /* Point-to-Point */
@@ -610,6 +614,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
610 614
611 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); 615 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
612 set_bit(RSCN_UPDATE, &ha->dpc_flags); 616 set_bit(RSCN_UPDATE, &ha->dpc_flags);
617 qla2x00_post_aen_work(ha, FCH_EVT_RSCN, rscn_entry);
613 break; 618 break;
614 619
615 /* case MBA_RIO_RESPONSE: */ 620 /* case MBA_RIO_RESPONSE: */
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 661a1596679d..eb77067533ab 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -1704,6 +1704,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
1704 INIT_LIST_HEAD(&ha->list); 1704 INIT_LIST_HEAD(&ha->list);
1705 INIT_LIST_HEAD(&ha->fcports); 1705 INIT_LIST_HEAD(&ha->fcports);
1706 INIT_LIST_HEAD(&ha->vp_list); 1706 INIT_LIST_HEAD(&ha->vp_list);
1707 INIT_LIST_HEAD(&ha->work_list);
1707 1708
1708 set_bit(0, (unsigned long *) ha->vp_idx_map); 1709 set_bit(0, (unsigned long *) ha->vp_idx_map);
1709 1710
@@ -2197,6 +2198,76 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
2197 kfree(ha->nvram); 2198 kfree(ha->nvram);
2198} 2199}
2199 2200
2201struct qla_work_evt *
2202qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
2203 int locked)
2204{
2205 struct qla_work_evt *e;
2206
2207 e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
2208 GFP_KERNEL);
2209 if (!e)
2210 return NULL;
2211
2212 INIT_LIST_HEAD(&e->list);
2213 e->type = type;
2214 e->flags = QLA_EVT_FLAG_FREE;
2215 return e;
2216}
2217
2218int
2219qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
2220{
2221 unsigned long flags;
2222
2223 if (!locked)
2224 spin_lock_irqsave(&ha->hardware_lock, flags);
2225 list_add_tail(&e->list, &ha->work_list);
2226 qla2xxx_wake_dpc(ha);
2227 if (!locked)
2228 spin_unlock_irqrestore(&ha->hardware_lock, flags);
2229 return QLA_SUCCESS;
2230}
2231
2232int
2233qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code,
2234 u32 data)
2235{
2236 struct qla_work_evt *e;
2237
2238 e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1);
2239 if (!e)
2240 return QLA_FUNCTION_FAILED;
2241
2242 e->u.aen.code = code;
2243 e->u.aen.data = data;
2244 return qla2x00_post_work(ha, e, 1);
2245}
2246
2247static void
2248qla2x00_do_work(struct scsi_qla_host *ha)
2249{
2250 struct qla_work_evt *e;
2251
2252 spin_lock_irq(&ha->hardware_lock);
2253 while (!list_empty(&ha->work_list)) {
2254 e = list_entry(ha->work_list.next, struct qla_work_evt, list);
2255 list_del_init(&e->list);
2256 spin_unlock_irq(&ha->hardware_lock);
2257
2258 switch (e->type) {
2259 case QLA_EVT_AEN:
2260 fc_host_post_event(ha->host, fc_get_event_number(),
2261 e->u.aen.code, e->u.aen.data);
2262 break;
2263 }
2264 if (e->flags & QLA_EVT_FLAG_FREE)
2265 kfree(e);
2266 spin_lock_irq(&ha->hardware_lock);
2267 }
2268 spin_unlock_irq(&ha->hardware_lock);
2269}
2270
2200/************************************************************************** 2271/**************************************************************************
2201* qla2x00_do_dpc 2272* qla2x00_do_dpc
2202* This kernel thread is a task that is schedule by the interrupt handler 2273* This kernel thread is a task that is schedule by the interrupt handler
@@ -2248,6 +2319,8 @@ qla2x00_do_dpc(void *data)
2248 continue; 2319 continue;
2249 } 2320 }
2250 2321
2322 qla2x00_do_work(ha);
2323
2251 if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { 2324 if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
2252 2325
2253 DEBUG(printk("scsi(%ld): dpc: sched " 2326 DEBUG(printk("scsi(%ld): dpc: sched "