summaryrefslogtreecommitdiff
path: root/drivers/s390/scsi/zfcp_qdio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/scsi/zfcp_qdio.c')
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c369
1 files changed, 188 insertions, 181 deletions
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index e0a215309df0..6c5228b627fc 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -3,7 +3,7 @@
*
* Setup and helper functions to access QDIO.
*
- * Copyright IBM Corporation 2002, 2008
+ * Copyright IBM Corporation 2002, 2009
*/
#define KMSG_COMPONENT "zfcp"
@@ -34,29 +34,10 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx)
return &q->sbal[sbal_idx]->element[sbale_idx];
}
-/**
- * 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)
+static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
{
- 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]);
- }
-}
+ struct zfcp_adapter *adapter = qdio->adapter;
-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 +56,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);
-}
-
-static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
- unsigned long req_id, int sbal_idx)
-{
- 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);
+ wake_up(&qdio->req_q_wq);
}
-static void zfcp_qdio_resp_put_back(struct zfcp_adapter *adapter, int processed)
+static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, 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;
@@ -162,14 +118,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,39 +134,27 @@ 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_resp_put_back(qdio, 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
+ * @qdio: pointer to struct zfcp_qdio
+ * @q_rec: pointer to struct zfcp_queue_rec
* Returns: pointer to qdio_buffer_element (SBALE) structure
*/
-struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *req)
+struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_qdio *qdio,
+ struct zfcp_queue_req *q_req)
{
- return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last, 0);
+ return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0);
}
/**
@@ -219,74 +162,80 @@ struct qdio_buffer_element *zfcp_qdio_sbale_req(struct zfcp_fsf_req *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)
+struct qdio_buffer_element *zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio,
+ struct zfcp_queue_req *q_req)
{
- return zfcp_qdio_sbale(&req->adapter->req_q, req->sbal_last,
- req->sbale_curr);
+ return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last,
+ q_req->sbale_curr);
}
-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_queue_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_queue_req *q_req,
+ unsigned long sbtype)
{
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 = zfcp_qdio_sbale_curr(qdio, q_req);
sbale->flags |= 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_queue_req *q_req,
+ unsigned int sbtype)
{
- 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_LAST_SBALE_PER_SBAL)
+ return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
+ 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_queue_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,
+static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
+ struct zfcp_queue_req *q_req,
unsigned int sbtype, void *start_addr,
unsigned int total_length)
{
@@ -297,10 +246,10 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
/* split segment up */
for (addr = start_addr, remaining = total_length; remaining > 0;
addr += length, remaining -= length) {
- sbale = zfcp_qdio_sbale_next(fsf_req, sbtype);
+ sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
if (!sbale) {
- atomic_inc(&fsf_req->adapter->qdio_outb_full);
- zfcp_qdio_undo_sbals(fsf_req);
+ atomic_inc(&qdio->req_q_full);
+ zfcp_qdio_undo_sbals(qdio, q_req);
return -EINVAL;
}
@@ -322,29 +271,31 @@ static int zfcp_qdio_fill_sbals(struct zfcp_fsf_req *fsf_req,
* @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,
- struct scatterlist *sg, int max_sbals)
+int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio,
+ struct zfcp_queue_req *q_req,
+ unsigned long sbtype, struct scatterlist *sg,
+ int max_sbals)
{
struct qdio_buffer_element *sbale;
int retval, 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 = zfcp_qdio_sbale_req(qdio, q_req);
sbale->flags |= sbtype;
for (; sg; sg = sg_next(sg)) {
- retval = zfcp_qdio_fill_sbals(fsf_req, sbtype, sg_virt(sg),
- sg->length);
+ retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
+ sg_virt(sg), sg->length);
if (retval < 0)
return retval;
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 +303,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_queue_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_queue_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 +331,69 @@ 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->flags = QDIO_INBOUND_0COPY_SBALS |
+ QDIO_OUTBOUND_0COPY_SBALS | QDIO_USE_OUTBOUND_PCIS;
+ 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 +404,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;
+}
+