Skip to content

Commit

Permalink
[SCSI] qla2xxx: Add FC-transport Asynchronous Event Notification supp…
Browse files Browse the repository at this point in the history
…ort.

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>
  • Loading branch information
Andrew Vasquez authored and James Bottomley committed Apr 7, 2008
1 parent c695248 commit 0971de7
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 0 deletions.
22 changes: 22 additions & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -2115,6 +2115,26 @@ struct qla_msix_entry {

#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
*/
Expand Down Expand Up @@ -2354,6 +2374,8 @@ typedef struct scsi_qla_host {
uint32_t login_retry_count;
int max_q_depth;

struct list_head work_list;

/* Fibre Channel Device List. */
struct list_head fcports;

Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/qla2xxx/qla_gbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ extern int num_hosts;

extern int qla2x00_loop_reset(scsi_qla_host_t *);
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.
Expand Down
5 changes: 5 additions & 0 deletions drivers/scsi/qla2xxx/qla_isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);

ha->flags.management_server_logged_in = 0;
qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]);
break;

case MBA_LOOP_UP: /* Loop Up Event */
Expand All @@ -427,6 +428,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
link_speed);

ha->flags.management_server_logged_in = 0;
qla2x00_post_aen_work(ha, FCH_EVT_LINKUP, ha->link_data_rate);
break;

case MBA_LOOP_DOWN: /* Loop Down Event */
Expand All @@ -450,6 +452,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0);
break;

case MBA_LIP_RESET: /* LIP reset occurred */
Expand All @@ -473,6 +476,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)

ha->operating_mode = LOOP;
ha->flags.management_server_logged_in = 0;
qla2x00_post_aen_work(ha, FCH_EVT_LIPRESET, mb[1]);
break;

case MBA_POINT_TO_POINT: /* Point-to-Point */
Expand Down Expand Up @@ -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(RSCN_UPDATE, &ha->dpc_flags);
qla2x00_post_aen_work(ha, FCH_EVT_RSCN, rscn_entry);
break;

/* case MBA_RIO_RESPONSE: */
Expand Down
73 changes: 73 additions & 0 deletions drivers/scsi/qla2xxx/qla_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->fcports);
INIT_LIST_HEAD(&ha->vp_list);
INIT_LIST_HEAD(&ha->work_list);

set_bit(0, (unsigned long *) ha->vp_idx_map);

Expand Down Expand Up @@ -2197,6 +2198,76 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
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
* This kernel thread is a task that is schedule by the interrupt handler
Expand Down Expand Up @@ -2248,6 +2319,8 @@ qla2x00_do_dpc(void *data)
continue;
}

qla2x00_do_work(ha);

if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {

DEBUG(printk("scsi(%ld): dpc: sched "
Expand Down

0 comments on commit 0971de7

Please sign in to comment.