[SCSI] zfcp: Move sbale handling to zfcp_qdio files
[safe/jmp/linux-2.6] / drivers / s390 / scsi / zfcp_qdio.c
index e0a2153..98d54a9 100644 (file)
@@ -3,13 +3,15 @@
  *
  * Setup and helper functions to access QDIO.
  *
- * Copyright IBM Corporation 2002, 2008
+ * Copyright IBM Corporation 2002, 2010
  */
 
 #define KMSG_COMPONENT "zfcp"
 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 
+#include <linux/slab.h>
 #include "zfcp_ext.h"
+#include "zfcp_qdio.h"
 
 #define QBUFF_PER_PAGE         (PAGE_SIZE / sizeof(struct qdio_buffer))
 
@@ -28,35 +30,10 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
        return 0;
 }
 
-static struct qdio_buffer_element *
-zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
 {
-       return &q->sbal[sbal_idx]->element[sbale_idx];
-}
+       struct zfcp_adapter *adapter = qdio->adapter;
 
-/**
- * zfcp_qdio_free - free memory used by request- and resposne queue
- * @adapter: pointer to the zfcp_adapter structure
- */
-void zfcp_qdio_free(struct zfcp_adapter *adapter)
-{
-       struct qdio_buffer **sbal_req, **sbal_resp;
-       int p;
-
-       if (adapter->ccw_device)
-               qdio_free(adapter->ccw_device);
-
-       sbal_req = adapter->req_q.sbal;
-       sbal_resp = adapter->resp_q.sbal;
-
-       for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
-               free_page((unsigned long) sbal_req[p]);
-               free_page((unsigned long) sbal_resp[p]);
-       }
-}
-
-static void zfcp_qdio_handler_error(struct zfcp_adapter *adapter, char *id)
-{
        dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
 
        zfcp_erp_adapter_reopen(adapter,
@@ -75,72 +52,47 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
 }
 
 /* this needs to be called prior to updating the queue fill level */
-static void zfcp_qdio_account(struct zfcp_adapter *adapter)
+static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
 {
-       ktime_t now;
-       s64 span;
+       unsigned long long now, span;
        int free, used;
 
-       spin_lock(&adapter->qdio_stat_lock);
-       now = ktime_get();
-       span = ktime_us_delta(now, adapter->req_q_time);
-       free = max(0, atomic_read(&adapter->req_q.count));
+       spin_lock(&qdio->stat_lock);
+       now = get_clock_monotonic();
+       span = (now - qdio->req_q_time) >> 12;
+       free = atomic_read(&qdio->req_q.count);
        used = QDIO_MAX_BUFFERS_PER_Q - free;
-       adapter->req_q_util += used * span;
-       adapter->req_q_time = now;
-       spin_unlock(&adapter->qdio_stat_lock);
+       qdio->req_q_util += used * span;
+       qdio->req_q_time = now;
+       spin_unlock(&qdio->stat_lock);
 }
 
 static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err,
                              int queue_no, int first, int count,
                              unsigned long parm)
 {
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm;
-       struct zfcp_qdio_queue *queue = &adapter->req_q;
+       struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
+       struct zfcp_qdio_queue *queue = &qdio->req_q;
 
        if (unlikely(qdio_err)) {
-               zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count);
-               zfcp_qdio_handler_error(adapter, "qdireq1");
+               zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
+                                       count);
+               zfcp_qdio_handler_error(qdio, "qdireq1");
                return;
        }
 
        /* cleanup all SBALs being program-owned now */
        zfcp_qdio_zero_sbals(queue->sbal, first, count);
 
-       zfcp_qdio_account(adapter);
+       zfcp_qdio_account(qdio);
        atomic_add(count, &queue->count);
-       wake_up(&adapter->request_wq);
+       wake_up(&qdio->req_q_wq);
 }
 
-static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
-                                 unsigned long req_id, int sbal_idx)
+static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
 {
-       struct zfcp_fsf_req *fsf_req;
-       unsigned long flags;
-
-       spin_lock_irqsave(&adapter->req_list_lock, flags);
-       fsf_req = zfcp_reqlist_find(adapter, req_id);
-
-       if (!fsf_req)
-               /*
-                * Unknown request means that we have potentially memory
-                * corruption and must stop the machine immediatly.
-                */
-               panic("error: unknown request id (%lx) on adapter %s.\n",
-                     req_id, dev_name(&adapter->ccw_device->dev));
-
-       zfcp_reqlist_remove(adapter, fsf_req);
-       spin_unlock_irqrestore(&adapter->req_list_lock, flags);
-
-       fsf_req->sbal_response = sbal_idx;
-       fsf_req->qdio_inb_usage = atomic_read(&adapter->resp_q.count);
-       zfcp_fsf_req_complete(fsf_req);
-}
-
-static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed)
-{
-       struct zfcp_qdio_queue *queue = &adapter->resp_q;
-       struct ccw_device *cdev = adapter->ccw_device;
+       struct zfcp_qdio_queue *queue = &qdio->resp_q;
+       struct ccw_device *cdev = qdio->adapter->ccw_device;
        u8 count, start = queue->first;
        unsigned int retval;
 
@@ -150,7 +102,7 @@ static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed)
 
        if (unlikely(retval)) {
                atomic_set(&queue->count, count);
-               /* FIXME: Recover this with an adapter reopen? */
+               zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
        } else {
                queue->first += count;
                queue->first %= QDIO_MAX_BUFFERS_PER_Q;
@@ -162,14 +114,13 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
                               int queue_no, int first, int count,
                               unsigned long parm)
 {
-       struct zfcp_adapter *adapter = (struct zfcp_adapter *) parm;
-       struct zfcp_qdio_queue *queue = &adapter->resp_q;
-       struct qdio_buffer_element *sbale;
-       int sbal_idx, sbale_idx, sbal_no;
+       struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
+       int sbal_idx, sbal_no;
 
        if (unlikely(qdio_err)) {
-               zfcp_hba_dbf_event_qdio(adapter, qdio_err, first, count);
-               zfcp_qdio_handler_error(adapter, "qdires1");
+               zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
+                                       count);
+               zfcp_qdio_handler_error(qdio, "qdires1");
                return;
        }
 
@@ -179,172 +130,117 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
         */
        for (sbal_no = 0; sbal_no < count; sbal_no++) {
                sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
-
                /* go through all SBALEs of SBAL */
-               for (sbale_idx = 0; sbale_idx < QDIO_MAX_ELEMENTS_PER_BUFFER;
-                    sbale_idx++) {
-                       sbale = zfcp_qdio_sbale(queue, sbal_idx, sbale_idx);
-                       zfcp_qdio_reqid_check(adapter,
-                                             (unsigned long) sbale->addr,
-                                             sbal_idx);
-                       if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY))
-                               break;
-               };
-
-               if (unlikely(!(sbale->flags & SBAL_FLAGS_LAST_ENTRY)))
-                       dev_warn(&adapter->ccw_device->dev,
-                                "A QDIO protocol error occurred, "
-                                "operations continue\n");
+               zfcp_fsf_reqid_check(qdio, sbal_idx);
        }
 
        /*
         * put range of SBALs back to response queue
         * (including SBALs which have already been free before)
         */
-       zfcp_qdio_resp_put_back(adapter, count);
-}
-
-/**
- * zfcp_qdio_sbale_req - return ptr to SBALE of req_q for a struct zfcp_fsf_req
- * @fsf_req: pointer to struct fsf_req
- * Returns: pointer to qdio_buffer_element (SBALE) structure
- */
-struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
-{
-       return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0);
-}
-
-/**
- * zfcp_qdio_sbale_curr - return curr SBALE on req_q for a struct zfcp_fsf_req
- * @fsf_req: pointer to struct fsf_req
- * Returns: pointer to qdio_buffer_element (SBALE) structure
- */
-struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_fsf_req *req)
-{
-       return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last,
-                              req->sbale_curr);
+       zfcp_qdio_resp_put_back(qdio, count);
 }
 
-static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
+static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
+                                struct zfcp_qdio_req *q_req, int max_sbals)
 {
-       int count = atomic_read(&fsf_req->adapter->req_q.count);
+       int count = atomic_read(&qdio->req_q.count);
        count = min(count, max_sbals);
-       fsf_req->sbal_limit = (fsf_req->sbal_first + count - 1)
+       q_req->sbal_limit = (q_req->sbal_first + count - 1)
                                        % QDIO_MAX_BUFFERS_PER_Q;
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
        struct qdio_buffer_element *sbale;
 
        /* set last entry flag in current SBALE of current SBAL */
-       sbale = zfcp_qdio_sbale_curr(fsf_req);
+       sbale = zfcp_qdio_sbale_curr(qdio, q_req);
        sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
 
        /* don't exceed last allowed SBAL */
-       if (fsf_req->sbal_last == fsf_req->sbal_limit)
+       if (q_req->sbal_last == q_req->sbal_limit)
                return NULL;
 
        /* set chaining flag in first SBALE of current SBAL */
-       sbale = zfcp_qdio_sbale_req(fsf_req);
+       sbale = zfcp_qdio_sbale_req(qdio, q_req);
        sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
 
        /* calculate index of next SBAL */
-       fsf_req->sbal_last++;
-       fsf_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
+       q_req->sbal_last++;
+       q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
 
        /* keep this requests number of SBALs up-to-date */
-       fsf_req->sbal_number++;
+       q_req->sbal_number++;
 
        /* start at first SBALE of new SBAL */
-       fsf_req->sbale_curr = 0;
+       q_req->sbale_curr = 0;
 
        /* set storage-block type for new SBAL */
-       sbale = zfcp_qdio_sbale_curr(fsf_req);
-       sbale->flags |= sbtype;
+       sbale = zfcp_qdio_sbale_curr(qdio, q_req);
+       sbale->flags |= q_req->sbtype;
 
        return sbale;
 }
 
 static struct qdio_buffer_element *
-zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
+zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-       if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
-               return zfcp_qdio_sbal_chain(fsf_req, sbtype);
-       fsf_req->sbale_curr++;
-       return zfcp_qdio_sbale_curr(fsf_req);
+       if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL)
+               return zfcp_qdio_sbal_chain(qdio, q_req);
+       q_req->sbale_curr++;
+       return zfcp_qdio_sbale_curr(qdio, q_req);
 }
 
-static void zfcp_qdio_undo_sbals(struct zfcp_fsf_req *fsf_req)
+static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
+                                struct zfcp_qdio_req *q_req)
 {
-       struct qdio_buffer **sbal = fsf_req->adapter->req_q.sbal;
-       int first = fsf_req->sbal_first;
-       int last = fsf_req->sbal_last;
+       struct qdio_buffer **sbal = qdio->req_q.sbal;
+       int first = q_req->sbal_first;
+       int last = q_req->sbal_last;
        int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) %
                QDIO_MAX_BUFFERS_PER_Q + 1;
        zfcp_qdio_zero_sbals(sbal, first, count);
 }
 
-static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
-                               unsigned int sbtype, void *start_addr,
-                               unsigned int total_length)
-{
-       struct qdio_buffer_element *sbale;
-       unsigned long remaining, length;
-       void *addr;
-
-       /* split segment up */
-       for (addr = start_addr, remaining = total_length; remaining > 0;
-            addr += length, remaining -= length) {
-               sbale = zfcp_qdio_sbale_next(fsf_req, sbtype);
-               if (!sbale) {
-                       atomic_inc(&fsf_req->adapter->qdio_outb_full);
-                       zfcp_qdio_undo_sbals(fsf_req);
-                       return -EINVAL;
-               }
-
-               /* new piece must not exceed next page boundary */
-               length = min(remaining,
-                            (PAGE_SIZE - ((unsigned long)addr &
-                                          (PAGE_SIZE - 1))));
-               sbale->addr = addr;
-               sbale->length = length;
-       }
-       return 0;
-}
-
 /**
  * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_qdio_req
  * @sg: scatter-gather list
  * @max_sbals: upper bound for number of SBALs to be used
  * Returns: number of bytes, or error (negativ)
  */
-int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
+int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
                            struct scatterlist *sg, int max_sbals)
 {
        struct qdio_buffer_element *sbale;
-       int retval, bytes = 0;
+       int bytes = 0;
 
        /* figure out last allowed SBAL */
-       zfcp_qdio_sbal_limit(fsf_req, max_sbals);
+       zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
 
        /* set storage-block type for this request */
-       sbale = zfcp_qdio_sbale_req(fsf_req);
-       sbale->flags |= sbtype;
+       sbale = zfcp_qdio_sbale_req(qdio, q_req);
+       sbale->flags |= q_req->sbtype;
 
        for (; sg; sg = sg_next(sg)) {
-               retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg),
-                                             sg->length);
-               if (retval < 0)
-                       return retval;
+               sbale = zfcp_qdio_sbale_next(qdio, q_req);
+               if (!sbale) {
+                       atomic_inc(&qdio->req_q_full);
+                       zfcp_qdio_undo_sbals(qdio, q_req);
+                       return -EINVAL;
+               }
+
+               sbale->addr = sg_virt(sg);
+               sbale->length = sg->length;
+
                bytes += sg->length;
        }
 
        /* assume that no other SBALEs are to follow in the same SBAL */
-       sbale = zfcp_qdio_sbale_curr(fsf_req);
+       sbale = zfcp_qdio_sbale_curr(qdio, q_req);
        sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
 
        return bytes;
@@ -352,21 +248,22 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
 
 /**
  * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
- * @fsf_req: pointer to struct zfcp_fsf_req
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_req: pointer to struct zfcp_qdio_req
  * Returns: 0 on success, error otherwise
  */
-int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
+int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
 {
-       struct zfcp_adapter *adapter = fsf_req->adapter;
-       struct zfcp_qdio_queue *req_q = &adapter->req_q;
-       int first = fsf_req->sbal_first;
-       int count = fsf_req->sbal_number;
+       struct zfcp_qdio_queue *req_q = &qdio->req_q;
+       int first = q_req->sbal_first;
+       int count = q_req->sbal_number;
        int retval;
        unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
 
-       zfcp_qdio_account(adapter);
+       zfcp_qdio_account(qdio);
 
-       retval = do_QDIO(adapter->ccw_device, qdio_flags, 0, first, count);
+       retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
+                        count);
        if (unlikely(retval)) {
                zfcp_qdio_zero_sbals(req_q->sbal, first, count);
                return retval;
@@ -379,63 +276,67 @@ int zfcp_qdio_send(struct zfcp_fsf_req *fsf_req)
        return 0;
 }
 
+
+static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
+                                     struct zfcp_qdio *qdio)
+{
+
+       id->cdev = qdio->adapter->ccw_device;
+       id->q_format = QDIO_ZFCP_QFMT;
+       memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
+       ASCEBC(id->adapter_name, 8);
+       id->qib_param_field_format = 0;
+       id->qib_param_field = NULL;
+       id->input_slib_elements = NULL;
+       id->output_slib_elements = NULL;
+       id->no_input_qs = 1;
+       id->no_output_qs = 1;
+       id->input_handler = zfcp_qdio_int_resp;
+       id->output_handler = zfcp_qdio_int_req;
+       id->int_parm = (unsigned long) qdio;
+       id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal);
+       id->output_sbal_addr_array = (void **) (qdio->req_q.sbal);
+
+}
 /**
  * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data
  * @adapter: pointer to struct zfcp_adapter
  * Returns: -ENOMEM on memory allocation error or return value from
  *          qdio_allocate
  */
-int zfcp_qdio_allocate(struct zfcp_adapter *adapter)
+static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
 {
-       struct qdio_initialize *init_data;
+       struct qdio_initialize init_data;
 
-       if (zfcp_qdio_buffers_enqueue(adapter->req_q.sbal) ||
-                  zfcp_qdio_buffers_enqueue(adapter->resp_q.sbal))
+       if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
+           zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
                return -ENOMEM;
 
-       init_data = &adapter->qdio_init_data;
-
-       init_data->cdev = adapter->ccw_device;
-       init_data->q_format = QDIO_ZFCP_QFMT;
-       memcpy(init_data->adapter_name, dev_name(&adapter->ccw_device->dev), 8);
-       ASCEBC(init_data->adapter_name, 8);
-       init_data->qib_param_field_format = 0;
-       init_data->qib_param_field = NULL;
-       init_data->input_slib_elements = NULL;
-       init_data->output_slib_elements = NULL;
-       init_data->no_input_qs = 1;
-       init_data->no_output_qs = 1;
-       init_data->input_handler = zfcp_qdio_int_resp;
-       init_data->output_handler = zfcp_qdio_int_req;
-       init_data->int_parm = (unsigned long) adapter;
-       init_data->flags = QDIO_INBOUND_0COPY_SBALS |
-                       QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
-       init_data->input_sbal_addr_array =
-                       (void **) (adapter->resp_q.sbal);
-       init_data->output_sbal_addr_array =
-                       (void **) (adapter->req_q.sbal);
-
-       return qdio_allocate(init_data);
+       zfcp_qdio_setup_init_data(&init_data, qdio);
+
+       return qdio_allocate(&init_data);
 }
 
 /**
  * zfcp_close_qdio - close qdio queues for an adapter
+ * @qdio: pointer to structure zfcp_qdio
  */
-void zfcp_qdio_close(struct zfcp_adapter *adapter)
+void zfcp_qdio_close(struct zfcp_qdio *qdio)
 {
        struct zfcp_qdio_queue *req_q;
        int first, count;
 
-       if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
+       if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
                return;
 
        /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
-       req_q = &adapter->req_q;
-       spin_lock_bh(&adapter->req_q_lock);
-       atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
-       spin_unlock_bh(&adapter->req_q_lock);
+       req_q = &qdio->req_q;
+       spin_lock_bh(&qdio->req_q_lock);
+       atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
+       spin_unlock_bh(&qdio->req_q_lock);
 
-       qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
+       qdio_shutdown(qdio->adapter->ccw_device,
+                     QDIO_FLAG_CLEANUP_USING_CLEAR);
 
        /* cleanup used outbound sbals */
        count = atomic_read(&req_q->count);
@@ -446,50 +347,99 @@ void zfcp_qdio_close(struct zfcp_adapter *adapter)
        }
        req_q->first = 0;
        atomic_set(&req_q->count, 0);
-       adapter->resp_q.first = 0;
-       atomic_set(&adapter->resp_q.count, 0);
+       qdio->resp_q.first = 0;
+       atomic_set(&qdio->resp_q.count, 0);
 }
 
 /**
  * zfcp_qdio_open - prepare and initialize response queue
- * @adapter: pointer to struct zfcp_adapter
+ * @qdio: pointer to struct zfcp_qdio
  * Returns: 0 on success, otherwise -EIO
  */
-int zfcp_qdio_open(struct zfcp_adapter *adapter)
+int zfcp_qdio_open(struct zfcp_qdio *qdio)
 {
        struct qdio_buffer_element *sbale;
+       struct qdio_initialize init_data;
+       struct ccw_device *cdev = qdio->adapter->ccw_device;
        int cc;
 
-       if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
+       if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
                return -EIO;
 
-       if (qdio_establish(&adapter->qdio_init_data))
+       zfcp_qdio_setup_init_data(&init_data, qdio);
+
+       if (qdio_establish(&init_data))
                goto failed_establish;
 
-       if (qdio_activate(adapter->ccw_device))
+       if (qdio_activate(cdev))
                goto failed_qdio;
 
        for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
-               sbale = &(adapter->resp_q.sbal[cc]->element[0]);
+               sbale = &(qdio->resp_q.sbal[cc]->element[0]);
                sbale->length = 0;
                sbale->flags = SBAL_FLAGS_LAST_ENTRY;
                sbale->addr = NULL;
        }
 
-       if (do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_INPUT, 0, 0,
+       if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
                     QDIO_MAX_BUFFERS_PER_Q))
                goto failed_qdio;
 
        /* set index of first avalable SBALS / number of available SBALS */
-       adapter->req_q.first = 0;
-       atomic_set(&adapter->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
+       qdio->req_q.first = 0;
+       atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
 
        return 0;
 
 failed_qdio:
-       qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
+       qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
 failed_establish:
-       dev_err(&adapter->ccw_device->dev,
+       dev_err(&cdev->dev,
                "Setting up the QDIO connection to the FCP adapter failed\n");
        return -EIO;
 }
+
+void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
+{
+       struct qdio_buffer **sbal_req, **sbal_resp;
+       int p;
+
+       if (!qdio)
+               return;
+
+       if (qdio->adapter->ccw_device)
+               qdio_free(qdio->adapter->ccw_device);
+
+       sbal_req = qdio->req_q.sbal;
+       sbal_resp = qdio->resp_q.sbal;
+
+       for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) {
+               free_page((unsigned long) sbal_req[p]);
+               free_page((unsigned long) sbal_resp[p]);
+       }
+
+       kfree(qdio);
+}
+
+int zfcp_qdio_setup(struct zfcp_adapter *adapter)
+{
+       struct zfcp_qdio *qdio;
+
+       qdio = kzalloc(sizeof(struct zfcp_qdio), GFP_KERNEL);
+       if (!qdio)
+               return -ENOMEM;
+
+       qdio->adapter = adapter;
+
+       if (zfcp_qdio_allocate(qdio)) {
+               zfcp_qdio_destroy(qdio);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&qdio->req_q_lock);
+       spin_lock_init(&qdio->stat_lock);
+
+       adapter->qdio = qdio;
+       return 0;
+}
+