diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2008-04-03 16:13:18 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-07 13:19:13 -0400 |
commit | 0971de7f56f809f40edae6fd372745e429e970e9 (patch) | |
tree | 8ae6829060081a81e62193db81278f6aa5365e08 /drivers/scsi/qla2xxx | |
parent | c6952483b070ec8a4f2450d1116be908fe59edcc (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.h | 22 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 5 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 73 |
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. */ | ||
2119 | enum qla_work_type { | ||
2120 | QLA_EVT_AEN, | ||
2121 | }; | ||
2122 | |||
2123 | |||
2124 | struct 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 | ||
68 | extern int qla2x00_loop_reset(scsi_qla_host_t *); | 68 | extern int qla2x00_loop_reset(scsi_qla_host_t *); |
69 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); | 69 | extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); |
70 | extern 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 | ||
2201 | struct qla_work_evt * | ||
2202 | qla2x00_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 | |||
2218 | int | ||
2219 | qla2x00_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 | |||
2232 | int | ||
2233 | qla2x00_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 | |||
2247 | static void | ||
2248 | qla2x00_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 " |