aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h18
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c6
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c85
4 files changed, 111 insertions, 0 deletions
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index ec48dc30b9a..f91808ce572 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -301,7 +301,21 @@ struct ql4_tuple_ddb {
#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
#define DF_FO_MASKED 3
+enum qla4_work_type {
+ QLA4_EVENT_AEN,
+};
+struct qla4_work_evt {
+ struct list_head list;
+ enum qla4_work_type type;
+ union {
+ struct {
+ enum iscsi_host_event_code code;
+ uint32_t data_size;
+ uint8_t data[0];
+ } aen;
+ } u;
+};
struct ql82xx_hw_data {
/* Offsets for flash/nvram access (set to ~0 if not used). */
@@ -672,6 +686,10 @@ struct scsi_qla_host {
uint16_t sec_ddb_idx;
int is_reset;
uint16_t temperature;
+
+ /* event work list */
+ struct list_head work_list;
+ spinlock_t work_lock;
};
struct ql4_task_data {
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index d0dd4b33020..34cf851978e 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -181,6 +181,8 @@ int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
struct ddb_entry *ddb_entry, uint32_t state);
void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset);
+int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code,
+ uint32_t data_size, uint8_t *data);
/* BSG Functions */
int qla4xxx_bsg_request(struct bsg_job *bsg_job);
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 95828862eea..954fe84be57 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -576,6 +576,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);
+ qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP,
+ sizeof(mbox_sts),
+ (uint8_t *) mbox_sts);
break;
case MBOX_ASTS_LINK_DOWN:
@@ -584,6 +587,9 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);
+ qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN,
+ sizeof(mbox_sts),
+ (uint8_t *) mbox_sts);
break;
case MBOX_ASTS_HEARTBEAT:
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 2cd20775836..d423f7afbbd 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -2282,6 +2282,10 @@ static void qla4xxx_timer(struct scsi_qla_host *ha)
}
}
+ /* Process any deferred work. */
+ if (!list_empty(&ha->work_list))
+ start_dpc++;
+
/* Wakeup the dpc routine for this adapter, if needed. */
if (start_dpc ||
test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
@@ -2847,6 +2851,81 @@ void qla4xxx_wake_dpc(struct scsi_qla_host *ha)
queue_work(ha->dpc_thread, &ha->dpc_work);
}
+static struct qla4_work_evt *
+qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size,
+ enum qla4_work_type type)
+{
+ struct qla4_work_evt *e;
+ uint32_t size = sizeof(struct qla4_work_evt) + data_size;
+
+ e = kzalloc(size, GFP_ATOMIC);
+ if (!e)
+ return NULL;
+
+ INIT_LIST_HEAD(&e->list);
+ e->type = type;
+ return e;
+}
+
+static void qla4xxx_post_work(struct scsi_qla_host *ha,
+ struct qla4_work_evt *e)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->work_lock, flags);
+ list_add_tail(&e->list, &ha->work_list);
+ spin_unlock_irqrestore(&ha->work_lock, flags);
+ qla4xxx_wake_dpc(ha);
+}
+
+int qla4xxx_post_aen_work(struct scsi_qla_host *ha,
+ enum iscsi_host_event_code aen_code,
+ uint32_t data_size, uint8_t *data)
+{
+ struct qla4_work_evt *e;
+
+ e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN);
+ if (!e)
+ return QLA_ERROR;
+
+ e->u.aen.code = aen_code;
+ e->u.aen.data_size = data_size;
+ memcpy(e->u.aen.data, data, data_size);
+
+ qla4xxx_post_work(ha, e);
+
+ return QLA_SUCCESS;
+}
+
+void qla4xxx_do_work(struct scsi_qla_host *ha)
+{
+ struct qla4_work_evt *e, *tmp;
+ unsigned long flags;
+ LIST_HEAD(work);
+
+ spin_lock_irqsave(&ha->work_lock, flags);
+ list_splice_init(&ha->work_list, &work);
+ spin_unlock_irqrestore(&ha->work_lock, flags);
+
+ list_for_each_entry_safe(e, tmp, &work, list) {
+ list_del_init(&e->list);
+
+ switch (e->type) {
+ case QLA4_EVENT_AEN:
+ iscsi_post_host_event(ha->host_no,
+ &qla4xxx_iscsi_transport,
+ e->u.aen.code,
+ e->u.aen.data_size,
+ e->u.aen.data);
+ break;
+ default:
+ ql4_printk(KERN_WARNING, ha, "event type: 0x%x not "
+ "supported", e->type);
+ }
+ kfree(e);
+ }
+}
+
/**
* qla4xxx_do_dpc - dpc routine
* @data: in our case pointer to adapter structure
@@ -2878,6 +2957,9 @@ static void qla4xxx_do_dpc(struct work_struct *work)
return;
}
+ /* post events to application */
+ qla4xxx_do_work(ha);
+
if (is_qla8022(ha)) {
if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) {
qla4_8xxx_idc_lock(ha);
@@ -4450,6 +4532,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
spin_lock_init(&ha->hardware_lock);
+ /* Initialize work list */
+ INIT_LIST_HEAD(&ha->work_list);
+
/* Allocate dma buffers */
if (qla4xxx_mem_alloc(ha)) {
ql4_printk(KERN_WARNING, ha,