[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>
This commit is contained in:
parent
c6952483b0
commit
0971de7f56
@ -2115,6 +2115,26 @@ struct qla_msix_entry {
|
|||||||
|
|
||||||
#define WATCH_INTERVAL 1 /* number of seconds */
|
#define WATCH_INTERVAL 1 /* number of seconds */
|
||||||
|
|
||||||
|
/* Work events. */
|
||||||
|
enum qla_work_type {
|
||||||
|
QLA_EVT_AEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct qla_work_evt {
|
||||||
|
struct list_head list;
|
||||||
|
enum qla_work_type type;
|
||||||
|
u32 flags;
|
||||||
|
#define QLA_EVT_FLAG_FREE 0x1
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
enum fc_host_event_code code;
|
||||||
|
u32 data;
|
||||||
|
} aen;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Linux Host Adapter structure
|
* Linux Host Adapter structure
|
||||||
*/
|
*/
|
||||||
@ -2354,6 +2374,8 @@ typedef struct scsi_qla_host {
|
|||||||
uint32_t login_retry_count;
|
uint32_t login_retry_count;
|
||||||
int max_q_depth;
|
int max_q_depth;
|
||||||
|
|
||||||
|
struct list_head work_list;
|
||||||
|
|
||||||
/* Fibre Channel Device List. */
|
/* Fibre Channel Device List. */
|
||||||
struct list_head fcports;
|
struct list_head fcports;
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ extern int num_hosts;
|
|||||||
|
|
||||||
extern int qla2x00_loop_reset(scsi_qla_host_t *);
|
extern int qla2x00_loop_reset(scsi_qla_host_t *);
|
||||||
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
|
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
|
||||||
|
extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
|
||||||
|
fc_host_event_code, u32);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global Functions in qla_mid.c source file.
|
* Global Functions in qla_mid.c source file.
|
||||||
|
@ -408,6 +408,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||||||
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
|
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
|
||||||
|
|
||||||
ha->flags.management_server_logged_in = 0;
|
ha->flags.management_server_logged_in = 0;
|
||||||
|
qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBA_LOOP_UP: /* Loop Up Event */
|
case MBA_LOOP_UP: /* Loop Up Event */
|
||||||
@ -427,6 +428,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||||||
link_speed);
|
link_speed);
|
||||||
|
|
||||||
ha->flags.management_server_logged_in = 0;
|
ha->flags.management_server_logged_in = 0;
|
||||||
|
qla2x00_post_aen_work(ha, FCH_EVT_LINKUP, ha->link_data_rate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBA_LOOP_DOWN: /* Loop Down Event */
|
case MBA_LOOP_DOWN: /* Loop Down Event */
|
||||||
@ -450,6 +452,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||||||
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
ha->link_data_rate = PORT_SPEED_UNKNOWN;
|
||||||
if (ql2xfdmienable)
|
if (ql2xfdmienable)
|
||||||
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
|
||||||
|
qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBA_LIP_RESET: /* LIP reset occurred */
|
case MBA_LIP_RESET: /* LIP reset occurred */
|
||||||
@ -473,6 +476,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||||||
|
|
||||||
ha->operating_mode = LOOP;
|
ha->operating_mode = LOOP;
|
||||||
ha->flags.management_server_logged_in = 0;
|
ha->flags.management_server_logged_in = 0;
|
||||||
|
qla2x00_post_aen_work(ha, FCH_EVT_LIPRESET, mb[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MBA_POINT_TO_POINT: /* Point-to-Point */
|
case MBA_POINT_TO_POINT: /* Point-to-Point */
|
||||||
@ -610,6 +614,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
|
|||||||
|
|
||||||
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
|
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
|
||||||
set_bit(RSCN_UPDATE, &ha->dpc_flags);
|
set_bit(RSCN_UPDATE, &ha->dpc_flags);
|
||||||
|
qla2x00_post_aen_work(ha, FCH_EVT_RSCN, rscn_entry);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* case MBA_RIO_RESPONSE: */
|
/* case MBA_RIO_RESPONSE: */
|
||||||
|
@ -1704,6 +1704,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||||||
INIT_LIST_HEAD(&ha->list);
|
INIT_LIST_HEAD(&ha->list);
|
||||||
INIT_LIST_HEAD(&ha->fcports);
|
INIT_LIST_HEAD(&ha->fcports);
|
||||||
INIT_LIST_HEAD(&ha->vp_list);
|
INIT_LIST_HEAD(&ha->vp_list);
|
||||||
|
INIT_LIST_HEAD(&ha->work_list);
|
||||||
|
|
||||||
set_bit(0, (unsigned long *) ha->vp_idx_map);
|
set_bit(0, (unsigned long *) ha->vp_idx_map);
|
||||||
|
|
||||||
@ -2197,6 +2198,76 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
|
|||||||
kfree(ha->nvram);
|
kfree(ha->nvram);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct qla_work_evt *
|
||||||
|
qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
|
||||||
|
int locked)
|
||||||
|
{
|
||||||
|
struct qla_work_evt *e;
|
||||||
|
|
||||||
|
e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!e)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&e->list);
|
||||||
|
e->type = type;
|
||||||
|
e->flags = QLA_EVT_FLAG_FREE;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!locked)
|
||||||
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||||
|
list_add_tail(&e->list, &ha->work_list);
|
||||||
|
qla2xxx_wake_dpc(ha);
|
||||||
|
if (!locked)
|
||||||
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
return QLA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code,
|
||||||
|
u32 data)
|
||||||
|
{
|
||||||
|
struct qla_work_evt *e;
|
||||||
|
|
||||||
|
e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1);
|
||||||
|
if (!e)
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
|
||||||
|
e->u.aen.code = code;
|
||||||
|
e->u.aen.data = data;
|
||||||
|
return qla2x00_post_work(ha, e, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla2x00_do_work(struct scsi_qla_host *ha)
|
||||||
|
{
|
||||||
|
struct qla_work_evt *e;
|
||||||
|
|
||||||
|
spin_lock_irq(&ha->hardware_lock);
|
||||||
|
while (!list_empty(&ha->work_list)) {
|
||||||
|
e = list_entry(ha->work_list.next, struct qla_work_evt, list);
|
||||||
|
list_del_init(&e->list);
|
||||||
|
spin_unlock_irq(&ha->hardware_lock);
|
||||||
|
|
||||||
|
switch (e->type) {
|
||||||
|
case QLA_EVT_AEN:
|
||||||
|
fc_host_post_event(ha->host, fc_get_event_number(),
|
||||||
|
e->u.aen.code, e->u.aen.data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (e->flags & QLA_EVT_FLAG_FREE)
|
||||||
|
kfree(e);
|
||||||
|
spin_lock_irq(&ha->hardware_lock);
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&ha->hardware_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* qla2x00_do_dpc
|
* qla2x00_do_dpc
|
||||||
* This kernel thread is a task that is schedule by the interrupt handler
|
* This kernel thread is a task that is schedule by the interrupt handler
|
||||||
@ -2248,6 +2319,8 @@ qla2x00_do_dpc(void *data)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qla2x00_do_work(ha);
|
||||||
|
|
||||||
if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
|
if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
|
||||||
|
|
||||||
DEBUG(printk("scsi(%ld): dpc: sched "
|
DEBUG(printk("scsi(%ld): dpc: sched "
|
||||||
|
Loading…
Reference in New Issue
Block a user