diff options
Diffstat (limited to 'drivers/s390/scsi')
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 39 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.h | 2 |
2 files changed, 41 insertions, 0 deletions
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a8a514074084..9fc045ddf66d 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -131,6 +131,33 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); } +static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet) +{ + struct zfcp_qdio *qdio = from_tasklet(qdio, tasklet, irq_tasklet); + struct ccw_device *cdev = qdio->adapter->ccw_device; + unsigned int start, error; + int completed; + + /* Check the Response Queue, and kick off the Request Queue tasklet: */ + completed = qdio_get_next_buffers(cdev, 0, &start, &error); + if (completed < 0) + return; + if (completed > 0) + zfcp_qdio_int_resp(cdev, error, 0, start, completed, + (unsigned long) qdio); + + if (qdio_start_irq(cdev)) + /* More work pending: */ + tasklet_schedule(&qdio->irq_tasklet); +} + +static void zfcp_qdio_poll(struct ccw_device *cdev, unsigned long data) +{ + struct zfcp_qdio *qdio = (struct zfcp_qdio *) data; + + tasklet_schedule(&qdio->irq_tasklet); +} + static struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { @@ -332,6 +359,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) wake_up(&qdio->req_q_wq); + tasklet_disable(&qdio->irq_tasklet); + qdio_stop_irq(adapter->ccw_device); qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); /* cleanup used outbound sbals */ @@ -387,6 +416,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) init_data.no_output_qs = 1; init_data.input_handler = zfcp_qdio_int_resp; init_data.output_handler = zfcp_qdio_int_req; + init_data.irq_poll = zfcp_qdio_poll; init_data.int_parm = (unsigned long) qdio; init_data.input_sbal_addr_array = input_sbals; init_data.output_sbal_addr_array = output_sbals; @@ -433,6 +463,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + /* Enable processing for QDIO interrupts: */ + tasklet_enable(&qdio->irq_tasklet); + /* This results in a qdio_start_irq(): */ + tasklet_schedule(&qdio->irq_tasklet); + zfcp_qdio_shost_update(adapter, qdio); return 0; @@ -450,6 +485,8 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio) if (!qdio) return; + tasklet_kill(&qdio->irq_tasklet); + if (qdio->adapter->ccw_device) qdio_free(qdio->adapter->ccw_device); @@ -475,6 +512,8 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) spin_lock_init(&qdio->req_q_lock); spin_lock_init(&qdio->stat_lock); + tasklet_setup(&qdio->irq_tasklet, zfcp_qdio_irq_tasklet); + tasklet_disable(&qdio->irq_tasklet); adapter->qdio = qdio; return 0; diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 6b43d6b254be..9c1f310db155 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -10,6 +10,7 @@ #ifndef ZFCP_QDIO_H #define ZFCP_QDIO_H +#include <linux/interrupt.h> #include <asm/qdio.h> #define ZFCP_QDIO_SBALE_LEN PAGE_SIZE @@ -44,6 +45,7 @@ struct zfcp_qdio { u64 req_q_util; atomic_t req_q_full; wait_queue_head_t req_q_wq; + struct tasklet_struct irq_tasklet; struct zfcp_adapter *adapter; u16 max_sbale_per_sbal; u16 max_sbale_per_req; |