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/qla_os.c | |
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/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 73 |
1 files changed, 73 insertions, 0 deletions
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 " |