|
@@ -55,71 +55,46 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt)
|
|
|
static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
|
|
|
{
|
|
|
unsigned long long now, span;
|
|
|
- int free, used;
|
|
|
+ int used;
|
|
|
|
|
|
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;
|
|
|
+ used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free);
|
|
|
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,
|
|
|
+ int queue_no, int idx, int count,
|
|
|
unsigned long parm)
|
|
|
{
|
|
|
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
|
|
|
- struct zfcp_qdio_queue *queue = &qdio->req_q;
|
|
|
|
|
|
if (unlikely(qdio_err)) {
|
|
|
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
|
|
|
- count);
|
|
|
+ zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, 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_zero_sbals(qdio->req_q, idx, count);
|
|
|
|
|
|
zfcp_qdio_account(qdio);
|
|
|
- atomic_add(count, &queue->count);
|
|
|
+ atomic_add(count, &qdio->req_q_free);
|
|
|
wake_up(&qdio->req_q_wq);
|
|
|
}
|
|
|
|
|
|
-static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
|
|
|
-{
|
|
|
- struct zfcp_qdio_queue *queue = &qdio->resp_q;
|
|
|
- struct ccw_device *cdev = qdio->adapter->ccw_device;
|
|
|
- u8 count, start = queue->first;
|
|
|
- unsigned int retval;
|
|
|
-
|
|
|
- count = atomic_read(&queue->count) + processed;
|
|
|
-
|
|
|
- retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
|
|
|
-
|
|
|
- if (unlikely(retval)) {
|
|
|
- atomic_set(&queue->count, count);
|
|
|
- zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
|
|
|
- } else {
|
|
|
- queue->first += count;
|
|
|
- queue->first %= QDIO_MAX_BUFFERS_PER_Q;
|
|
|
- atomic_set(&queue->count, 0);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
|
|
|
- int queue_no, int first, int count,
|
|
|
+ int queue_no, int idx, int count,
|
|
|
unsigned long parm)
|
|
|
{
|
|
|
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
|
|
|
int sbal_idx, sbal_no;
|
|
|
|
|
|
if (unlikely(qdio_err)) {
|
|
|
- zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
|
|
|
- count);
|
|
|
+ zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count);
|
|
|
zfcp_qdio_handler_error(qdio, "qdires1");
|
|
|
return;
|
|
|
}
|
|
@@ -129,16 +104,16 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
|
|
|
* returned by QDIO layer
|
|
|
*/
|
|
|
for (sbal_no = 0; sbal_no < count; sbal_no++) {
|
|
|
- sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
|
|
|
+ sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
|
|
|
/* go through all SBALEs of SBAL */
|
|
|
zfcp_fsf_reqid_check(qdio, sbal_idx);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * put range of SBALs back to response queue
|
|
|
- * (including SBALs which have already been free before)
|
|
|
+ * put SBALs back to response queue
|
|
|
*/
|
|
|
- zfcp_qdio_resp_put_back(qdio, count);
|
|
|
+ if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count))
|
|
|
+ zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL);
|
|
|
}
|
|
|
|
|
|
static struct qdio_buffer_element *
|
|
@@ -185,17 +160,6 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
|
|
return zfcp_qdio_sbale_curr(qdio, q_req);
|
|
|
}
|
|
|
|
|
|
-static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
|
|
|
- struct zfcp_qdio_req *q_req)
|
|
|
-{
|
|
|
- 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);
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list
|
|
|
* @qdio: pointer to struct zfcp_qdio
|
|
@@ -218,7 +182,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|
|
sbale = zfcp_qdio_sbale_next(qdio, q_req);
|
|
|
if (!sbale) {
|
|
|
atomic_inc(&qdio->req_q_full);
|
|
|
- zfcp_qdio_undo_sbals(qdio, q_req);
|
|
|
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
|
|
|
+ q_req->sbal_number);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
@@ -237,10 +202,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|
|
|
|
|
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
|
|
|
{
|
|
|
- struct zfcp_qdio_queue *req_q = &qdio->req_q;
|
|
|
-
|
|
|
spin_lock_bh(&qdio->req_q_lock);
|
|
|
- if (atomic_read(&req_q->count) ||
|
|
|
+ if (atomic_read(&qdio->req_q_free) ||
|
|
|
!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
|
|
|
return 1;
|
|
|
spin_unlock_bh(&qdio->req_q_lock);
|
|
@@ -289,25 +252,25 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
|
|
|
*/
|
|
|
int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
|
|
{
|
|
|
- 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;
|
|
|
+ u8 sbal_number = q_req->sbal_number;
|
|
|
|
|
|
zfcp_qdio_account(qdio);
|
|
|
|
|
|
- retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
|
|
|
- count);
|
|
|
+ retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0,
|
|
|
+ q_req->sbal_first, sbal_number);
|
|
|
+
|
|
|
if (unlikely(retval)) {
|
|
|
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
|
|
|
+ zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first,
|
|
|
+ sbal_number);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
/* account for transferred buffers */
|
|
|
- atomic_sub(count, &req_q->count);
|
|
|
- req_q->first += count;
|
|
|
- req_q->first %= QDIO_MAX_BUFFERS_PER_Q;
|
|
|
+ atomic_sub(sbal_number, &qdio->req_q_free);
|
|
|
+ qdio->req_q_idx += sbal_number;
|
|
|
+ qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -329,8 +292,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
|
|
|
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);
|
|
|
+ id->input_sbal_addr_array = (void **) (qdio->res_q);
|
|
|
+ id->output_sbal_addr_array = (void **) (qdio->req_q);
|
|
|
|
|
|
}
|
|
|
/**
|
|
@@ -343,8 +306,8 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
|
|
|
{
|
|
|
struct qdio_initialize init_data;
|
|
|
|
|
|
- if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
|
|
|
- zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
|
|
|
+ if (zfcp_qdio_buffers_enqueue(qdio->req_q) ||
|
|
|
+ zfcp_qdio_buffers_enqueue(qdio->res_q))
|
|
|
return -ENOMEM;
|
|
|
|
|
|
zfcp_qdio_setup_init_data(&init_data, qdio);
|
|
@@ -358,34 +321,30 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
|
|
|
*/
|
|
|
void zfcp_qdio_close(struct zfcp_qdio *qdio)
|
|
|
{
|
|
|
- struct zfcp_qdio_queue *req_q;
|
|
|
- int first, count;
|
|
|
+ struct zfcp_adapter *adapter = qdio->adapter;
|
|
|
+ int idx, count;
|
|
|
|
|
|
- if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
|
|
|
+ if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
|
|
|
return;
|
|
|
|
|
|
/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
|
|
|
- req_q = &qdio->req_q;
|
|
|
spin_lock_bh(&qdio->req_q_lock);
|
|
|
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
|
|
|
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
|
|
|
spin_unlock_bh(&qdio->req_q_lock);
|
|
|
|
|
|
wake_up(&qdio->req_q_wq);
|
|
|
|
|
|
- qdio_shutdown(qdio->adapter->ccw_device,
|
|
|
- QDIO_FLAG_CLEANUP_USING_CLEAR);
|
|
|
+ qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR);
|
|
|
|
|
|
/* cleanup used outbound sbals */
|
|
|
- count = atomic_read(&req_q->count);
|
|
|
+ count = atomic_read(&qdio->req_q_free);
|
|
|
if (count < QDIO_MAX_BUFFERS_PER_Q) {
|
|
|
- first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q;
|
|
|
+ idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q;
|
|
|
count = QDIO_MAX_BUFFERS_PER_Q - count;
|
|
|
- zfcp_qdio_zero_sbals(req_q->sbal, first, count);
|
|
|
+ zfcp_qdio_zero_sbals(qdio->req_q, idx, count);
|
|
|
}
|
|
|
- req_q->first = 0;
|
|
|
- atomic_set(&req_q->count, 0);
|
|
|
- qdio->resp_q.first = 0;
|
|
|
- atomic_set(&qdio->resp_q.count, 0);
|
|
|
+ qdio->req_q_idx = 0;
|
|
|
+ atomic_set(&qdio->req_q_free, 0);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -397,10 +356,11 @@ 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;
|
|
|
+ struct zfcp_adapter *adapter = qdio->adapter;
|
|
|
+ struct ccw_device *cdev = adapter->ccw_device;
|
|
|
int cc;
|
|
|
|
|
|
- if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
|
|
|
+ if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
|
|
|
return -EIO;
|
|
|
|
|
|
zfcp_qdio_setup_init_data(&init_data, qdio);
|
|
@@ -412,19 +372,18 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
|
|
|
goto failed_qdio;
|
|
|
|
|
|
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
|
|
|
- sbale = &(qdio->resp_q.sbal[cc]->element[0]);
|
|
|
+ sbale = &(qdio->res_q[cc]->element[0]);
|
|
|
sbale->length = 0;
|
|
|
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
|
|
|
sbale->addr = NULL;
|
|
|
}
|
|
|
|
|
|
- if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
|
|
|
- QDIO_MAX_BUFFERS_PER_Q))
|
|
|
+ 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 */
|
|
|
- qdio->req_q.first = 0;
|
|
|
- atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
|
|
|
+ qdio->req_q_idx = 0;
|
|
|
+ atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -438,7 +397,6 @@ failed_establish:
|
|
|
|
|
|
void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
|
|
|
{
|
|
|
- struct qdio_buffer **sbal_req, **sbal_resp;
|
|
|
int p;
|
|
|
|
|
|
if (!qdio)
|
|
@@ -447,12 +405,9 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio)
|
|
|
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]);
|
|
|
+ free_page((unsigned long) qdio->req_q[p]);
|
|
|
+ free_page((unsigned long) qdio->res_q[p]);
|
|
|
}
|
|
|
|
|
|
kfree(qdio);
|