Blame view
drivers/s390/scsi/zfcp_qdio.c
12.2 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
00bab9106 [SCSI] zfcp: Clea... |
2 |
* zfcp device driver |
1da177e4c Linux-2.6.12-rc2 |
3 |
* |
00bab9106 [SCSI] zfcp: Clea... |
4 |
* Setup and helper functions to access QDIO. |
1da177e4c Linux-2.6.12-rc2 |
5 |
* |
42428f747 [SCSI] zfcp: Sepa... |
6 |
* Copyright IBM Corporation 2002, 2009 |
1da177e4c Linux-2.6.12-rc2 |
7 |
*/ |
ecf39d421 [S390] convert zf... |
8 9 |
#define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
10 |
#include "zfcp_ext.h" |
34c2b7129 [SCSI] zfcp: Intr... |
11 |
#include "zfcp_qdio.h" |
1da177e4c Linux-2.6.12-rc2 |
12 |
|
5d4e22624 [SCSI] zfcp: Smal... |
13 |
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) |
1da177e4c Linux-2.6.12-rc2 |
14 |
|
00bab9106 [SCSI] zfcp: Clea... |
15 |
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) |
1da177e4c Linux-2.6.12-rc2 |
16 |
{ |
b4e44590f [SCSI] zfcp: code... |
17 |
int pos; |
1da177e4c Linux-2.6.12-rc2 |
18 |
|
b4e44590f [SCSI] zfcp: code... |
19 |
for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) { |
00bab9106 [SCSI] zfcp: Clea... |
20 21 |
sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL); if (!sbal[pos]) |
b4e44590f [SCSI] zfcp: code... |
22 |
return -ENOMEM; |
b4e44590f [SCSI] zfcp: code... |
23 24 25 |
} for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++) if (pos % QBUFF_PER_PAGE) |
00bab9106 [SCSI] zfcp: Clea... |
26 |
sbal[pos] = sbal[pos - 1] + 1; |
b4e44590f [SCSI] zfcp: code... |
27 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
28 |
} |
564e1c86c [SCSI] zfcp: Move... |
29 |
static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id) |
1da177e4c Linux-2.6.12-rc2 |
30 |
{ |
564e1c86c [SCSI] zfcp: Move... |
31 |
struct zfcp_adapter *adapter = qdio->adapter; |
ff3b24fa5 [SCSI] zfcp: Upda... |
32 33 |
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred "); |
1da177e4c Linux-2.6.12-rc2 |
34 |
|
00bab9106 [SCSI] zfcp: Clea... |
35 36 37 |
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); |
1da177e4c Linux-2.6.12-rc2 |
38 |
} |
5d4e22624 [SCSI] zfcp: Smal... |
39 40 41 42 43 44 45 46 47 |
static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) { int i, sbal_idx; for (i = first; i < first + cnt; i++) { sbal_idx = i % QDIO_MAX_BUFFERS_PER_Q; memset(sbal[sbal_idx], 0, sizeof(struct qdio_buffer)); } } |
94506fd14 [SCSI] zfcp: add ... |
48 |
/* this needs to be called prior to updating the queue fill level */ |
41e05a12c [SCSI] zfcp: opti... |
49 |
static inline void zfcp_qdio_account(struct zfcp_qdio *qdio) |
94506fd14 [SCSI] zfcp: add ... |
50 |
{ |
41e05a12c [SCSI] zfcp: opti... |
51 |
unsigned long long now, span; |
94506fd14 [SCSI] zfcp: add ... |
52 |
int free, used; |
564e1c86c [SCSI] zfcp: Move... |
53 |
spin_lock(&qdio->stat_lock); |
41e05a12c [SCSI] zfcp: opti... |
54 55 56 |
now = get_clock_monotonic(); span = (now - qdio->req_q_time) >> 12; free = atomic_read(&qdio->req_q.count); |
94506fd14 [SCSI] zfcp: add ... |
57 |
used = QDIO_MAX_BUFFERS_PER_Q - free; |
564e1c86c [SCSI] zfcp: Move... |
58 59 60 |
qdio->req_q_util += used * span; qdio->req_q_time = now; spin_unlock(&qdio->stat_lock); |
94506fd14 [SCSI] zfcp: add ... |
61 |
} |
779e6e1c7 [S390] qdio: new ... |
62 63 |
static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, int queue_no, int first, int count, |
00bab9106 [SCSI] zfcp: Clea... |
64 |
unsigned long parm) |
1da177e4c Linux-2.6.12-rc2 |
65 |
{ |
564e1c86c [SCSI] zfcp: Move... |
66 67 |
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; struct zfcp_qdio_queue *queue = &qdio->req_q; |
1da177e4c Linux-2.6.12-rc2 |
68 |
|
779e6e1c7 [S390] qdio: new ... |
69 |
if (unlikely(qdio_err)) { |
5771710bd [SCSI] zfcp: Upda... |
70 71 |
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, count); |
564e1c86c [SCSI] zfcp: Move... |
72 |
zfcp_qdio_handler_error(qdio, "qdireq1"); |
00bab9106 [SCSI] zfcp: Clea... |
73 74 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
75 76 |
/* cleanup all SBALs being program-owned now */ |
00bab9106 [SCSI] zfcp: Clea... |
77 |
zfcp_qdio_zero_sbals(queue->sbal, first, count); |
1da177e4c Linux-2.6.12-rc2 |
78 |
|
564e1c86c [SCSI] zfcp: Move... |
79 |
zfcp_qdio_account(qdio); |
00bab9106 [SCSI] zfcp: Clea... |
80 |
atomic_add(count, &queue->count); |
564e1c86c [SCSI] zfcp: Move... |
81 |
wake_up(&qdio->req_q_wq); |
1da177e4c Linux-2.6.12-rc2 |
82 |
} |
564e1c86c [SCSI] zfcp: Move... |
83 |
static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed) |
1da177e4c Linux-2.6.12-rc2 |
84 |
{ |
564e1c86c [SCSI] zfcp: Move... |
85 86 |
struct zfcp_qdio_queue *queue = &qdio->resp_q; struct ccw_device *cdev = qdio->adapter->ccw_device; |
00bab9106 [SCSI] zfcp: Clea... |
87 88 |
u8 count, start = queue->first; unsigned int retval; |
1da177e4c Linux-2.6.12-rc2 |
89 |
|
00bab9106 [SCSI] zfcp: Clea... |
90 |
count = atomic_read(&queue->count) + processed; |
779e6e1c7 [S390] qdio: new ... |
91 |
retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count); |
00bab9106 [SCSI] zfcp: Clea... |
92 93 94 |
if (unlikely(retval)) { atomic_set(&queue->count, count); |
452b505c5 [SCSI] zfcp: Remo... |
95 |
zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL); |
00bab9106 [SCSI] zfcp: Clea... |
96 97 98 99 100 101 |
} else { queue->first += count; queue->first %= QDIO_MAX_BUFFERS_PER_Q; atomic_set(&queue->count, 0); } } |
779e6e1c7 [S390] qdio: new ... |
102 103 |
static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, int queue_no, int first, int count, |
00bab9106 [SCSI] zfcp: Clea... |
104 105 |
unsigned long parm) { |
564e1c86c [SCSI] zfcp: Move... |
106 |
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; |
bd63eaf4b [SCSI] zfcp: fix ... |
107 |
int sbal_idx, sbal_no; |
00bab9106 [SCSI] zfcp: Clea... |
108 |
|
779e6e1c7 [S390] qdio: new ... |
109 |
if (unlikely(qdio_err)) { |
5771710bd [SCSI] zfcp: Upda... |
110 111 |
zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, count); |
564e1c86c [SCSI] zfcp: Move... |
112 |
zfcp_qdio_handler_error(qdio, "qdires1"); |
00bab9106 [SCSI] zfcp: Clea... |
113 114 |
return; } |
1da177e4c Linux-2.6.12-rc2 |
115 |
|
1da177e4c Linux-2.6.12-rc2 |
116 117 118 119 |
/* * go through all SBALs from input queue currently * returned by QDIO layer */ |
00bab9106 [SCSI] zfcp: Clea... |
120 121 |
for (sbal_no = 0; sbal_no < count; sbal_no++) { sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; |
1da177e4c Linux-2.6.12-rc2 |
122 |
/* go through all SBALEs of SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
123 |
zfcp_fsf_reqid_check(qdio, sbal_idx); |
1da177e4c Linux-2.6.12-rc2 |
124 125 126 127 128 129 |
} /* * put range of SBALs back to response queue * (including SBALs which have already been free before) */ |
564e1c86c [SCSI] zfcp: Move... |
130 |
zfcp_qdio_resp_put_back(qdio, count); |
1da177e4c Linux-2.6.12-rc2 |
131 |
} |
564e1c86c [SCSI] zfcp: Move... |
132 |
static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, |
34c2b7129 [SCSI] zfcp: Intr... |
133 |
struct zfcp_qdio_req *q_req, int max_sbals) |
1da177e4c Linux-2.6.12-rc2 |
134 |
{ |
564e1c86c [SCSI] zfcp: Move... |
135 |
int count = atomic_read(&qdio->req_q.count); |
1da177e4c Linux-2.6.12-rc2 |
136 |
count = min(count, max_sbals); |
42428f747 [SCSI] zfcp: Sepa... |
137 |
q_req->sbal_limit = (q_req->sbal_first + count - 1) |
00bab9106 [SCSI] zfcp: Clea... |
138 |
% QDIO_MAX_BUFFERS_PER_Q; |
1da177e4c Linux-2.6.12-rc2 |
139 |
} |
44cc76f2d [SCSI] zfcp: remo... |
140 |
static struct qdio_buffer_element * |
34c2b7129 [SCSI] zfcp: Intr... |
141 |
zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, |
42428f747 [SCSI] zfcp: Sepa... |
142 |
unsigned long sbtype) |
1da177e4c Linux-2.6.12-rc2 |
143 |
{ |
44cc76f2d [SCSI] zfcp: remo... |
144 |
struct qdio_buffer_element *sbale; |
1da177e4c Linux-2.6.12-rc2 |
145 146 |
/* set last entry flag in current SBALE of current SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
147 |
sbale = zfcp_qdio_sbale_curr(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
148 149 150 |
sbale->flags |= SBAL_FLAGS_LAST_ENTRY; /* don't exceed last allowed SBAL */ |
42428f747 [SCSI] zfcp: Sepa... |
151 |
if (q_req->sbal_last == q_req->sbal_limit) |
1da177e4c Linux-2.6.12-rc2 |
152 153 154 |
return NULL; /* set chaining flag in first SBALE of current SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
155 |
sbale = zfcp_qdio_sbale_req(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
156 157 158 |
sbale->flags |= SBAL_FLAGS0_MORE_SBALS; /* calculate index of next SBAL */ |
42428f747 [SCSI] zfcp: Sepa... |
159 160 |
q_req->sbal_last++; q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q; |
1da177e4c Linux-2.6.12-rc2 |
161 162 |
/* keep this requests number of SBALs up-to-date */ |
42428f747 [SCSI] zfcp: Sepa... |
163 |
q_req->sbal_number++; |
1da177e4c Linux-2.6.12-rc2 |
164 165 |
/* start at first SBALE of new SBAL */ |
42428f747 [SCSI] zfcp: Sepa... |
166 |
q_req->sbale_curr = 0; |
1da177e4c Linux-2.6.12-rc2 |
167 168 |
/* set storage-block type for new SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
169 |
sbale = zfcp_qdio_sbale_curr(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
170 171 172 173 |
sbale->flags |= sbtype; return sbale; } |
44cc76f2d [SCSI] zfcp: remo... |
174 |
static struct qdio_buffer_element * |
34c2b7129 [SCSI] zfcp: Intr... |
175 |
zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, |
42428f747 [SCSI] zfcp: Sepa... |
176 |
unsigned int sbtype) |
1da177e4c Linux-2.6.12-rc2 |
177 |
{ |
42428f747 [SCSI] zfcp: Sepa... |
178 |
if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) |
564e1c86c [SCSI] zfcp: Move... |
179 |
return zfcp_qdio_sbal_chain(qdio, q_req, sbtype); |
42428f747 [SCSI] zfcp: Sepa... |
180 |
q_req->sbale_curr++; |
564e1c86c [SCSI] zfcp: Move... |
181 |
return zfcp_qdio_sbale_curr(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
182 |
} |
564e1c86c [SCSI] zfcp: Move... |
183 |
static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio, |
34c2b7129 [SCSI] zfcp: Intr... |
184 |
struct zfcp_qdio_req *q_req) |
1da177e4c Linux-2.6.12-rc2 |
185 |
{ |
564e1c86c [SCSI] zfcp: Move... |
186 |
struct qdio_buffer **sbal = qdio->req_q.sbal; |
42428f747 [SCSI] zfcp: Sepa... |
187 188 |
int first = q_req->sbal_first; int last = q_req->sbal_last; |
00bab9106 [SCSI] zfcp: Clea... |
189 190 191 |
int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % QDIO_MAX_BUFFERS_PER_Q + 1; zfcp_qdio_zero_sbals(sbal, first, count); |
1da177e4c Linux-2.6.12-rc2 |
192 |
} |
564e1c86c [SCSI] zfcp: Move... |
193 |
static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio, |
34c2b7129 [SCSI] zfcp: Intr... |
194 |
struct zfcp_qdio_req *q_req, |
00bab9106 [SCSI] zfcp: Clea... |
195 196 |
unsigned int sbtype, void *start_addr, unsigned int total_length) |
1da177e4c Linux-2.6.12-rc2 |
197 |
{ |
44cc76f2d [SCSI] zfcp: remo... |
198 |
struct qdio_buffer_element *sbale; |
1da177e4c Linux-2.6.12-rc2 |
199 200 |
unsigned long remaining, length; void *addr; |
00bab9106 [SCSI] zfcp: Clea... |
201 |
/* split segment up */ |
1da177e4c Linux-2.6.12-rc2 |
202 203 |
for (addr = start_addr, remaining = total_length; remaining > 0; addr += length, remaining -= length) { |
564e1c86c [SCSI] zfcp: Move... |
204 |
sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype); |
00bab9106 [SCSI] zfcp: Clea... |
205 |
if (!sbale) { |
564e1c86c [SCSI] zfcp: Move... |
206 207 |
atomic_inc(&qdio->req_q_full); zfcp_qdio_undo_sbals(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
208 209 |
return -EINVAL; } |
00bab9106 [SCSI] zfcp: Clea... |
210 211 |
/* new piece must not exceed next page boundary */ |
1da177e4c Linux-2.6.12-rc2 |
212 |
length = min(remaining, |
00bab9106 [SCSI] zfcp: Clea... |
213 |
(PAGE_SIZE - ((unsigned long)addr & |
1da177e4c Linux-2.6.12-rc2 |
214 |
(PAGE_SIZE - 1)))); |
00bab9106 [SCSI] zfcp: Clea... |
215 216 |
sbale->addr = addr; sbale->length = length; |
1da177e4c Linux-2.6.12-rc2 |
217 |
} |
00bab9106 [SCSI] zfcp: Clea... |
218 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
219 |
} |
1da177e4c Linux-2.6.12-rc2 |
220 221 222 223 224 |
/** * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list * @fsf_req: request to be processed * @sbtype: SBALE flags * @sg: scatter-gather list |
1da177e4c Linux-2.6.12-rc2 |
225 |
* @max_sbals: upper bound for number of SBALs to be used |
00bab9106 [SCSI] zfcp: Clea... |
226 |
* Returns: number of bytes, or error (negativ) |
1da177e4c Linux-2.6.12-rc2 |
227 |
*/ |
34c2b7129 [SCSI] zfcp: Intr... |
228 |
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, |
42428f747 [SCSI] zfcp: Sepa... |
229 230 |
unsigned long sbtype, struct scatterlist *sg, int max_sbals) |
1da177e4c Linux-2.6.12-rc2 |
231 |
{ |
44cc76f2d [SCSI] zfcp: remo... |
232 |
struct qdio_buffer_element *sbale; |
00bab9106 [SCSI] zfcp: Clea... |
233 |
int retval, bytes = 0; |
1da177e4c Linux-2.6.12-rc2 |
234 235 |
/* figure out last allowed SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
236 |
zfcp_qdio_sbal_limit(qdio, q_req, max_sbals); |
1da177e4c Linux-2.6.12-rc2 |
237 |
|
00bab9106 [SCSI] zfcp: Clea... |
238 |
/* set storage-block type for this request */ |
564e1c86c [SCSI] zfcp: Move... |
239 |
sbale = zfcp_qdio_sbale_req(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
240 |
sbale->flags |= sbtype; |
00bab9106 [SCSI] zfcp: Clea... |
241 |
for (; sg; sg = sg_next(sg)) { |
564e1c86c [SCSI] zfcp: Move... |
242 |
retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype, |
42428f747 [SCSI] zfcp: Sepa... |
243 |
sg_virt(sg), sg->length); |
00bab9106 [SCSI] zfcp: Clea... |
244 245 246 |
if (retval < 0) return retval; bytes += sg->length; |
1da177e4c Linux-2.6.12-rc2 |
247 |
} |
00bab9106 [SCSI] zfcp: Clea... |
248 |
|
1da177e4c Linux-2.6.12-rc2 |
249 |
/* assume that no other SBALEs are to follow in the same SBAL */ |
564e1c86c [SCSI] zfcp: Move... |
250 |
sbale = zfcp_qdio_sbale_curr(qdio, q_req); |
1da177e4c Linux-2.6.12-rc2 |
251 |
sbale->flags |= SBAL_FLAGS_LAST_ENTRY; |
00bab9106 [SCSI] zfcp: Clea... |
252 |
|
1da177e4c Linux-2.6.12-rc2 |
253 254 |
return bytes; } |
1da177e4c Linux-2.6.12-rc2 |
255 |
/** |
00bab9106 [SCSI] zfcp: Clea... |
256 |
* zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO |
564e1c86c [SCSI] zfcp: Move... |
257 |
* @qdio: pointer to struct zfcp_qdio |
34c2b7129 [SCSI] zfcp: Intr... |
258 |
* @q_req: pointer to struct zfcp_qdio_req |
00bab9106 [SCSI] zfcp: Clea... |
259 |
* Returns: 0 on success, error otherwise |
1da177e4c Linux-2.6.12-rc2 |
260 |
*/ |
34c2b7129 [SCSI] zfcp: Intr... |
261 |
int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) |
1da177e4c Linux-2.6.12-rc2 |
262 |
{ |
564e1c86c [SCSI] zfcp: Move... |
263 |
struct zfcp_qdio_queue *req_q = &qdio->req_q; |
42428f747 [SCSI] zfcp: Sepa... |
264 265 |
int first = q_req->sbal_first; int count = q_req->sbal_number; |
21ddaa53f [SCSI] zfcp: Remo... |
266 267 |
int retval; unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; |
00bab9106 [SCSI] zfcp: Clea... |
268 |
|
564e1c86c [SCSI] zfcp: Move... |
269 |
zfcp_qdio_account(qdio); |
94506fd14 [SCSI] zfcp: add ... |
270 |
|
564e1c86c [SCSI] zfcp: Move... |
271 272 |
retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first, count); |
00bab9106 [SCSI] zfcp: Clea... |
273 274 275 276 277 278 279 280 281 |
if (unlikely(retval)) { zfcp_qdio_zero_sbals(req_q->sbal, first, count); return retval; } /* account for transferred buffers */ atomic_sub(count, &req_q->count); req_q->first += count; req_q->first %= QDIO_MAX_BUFFERS_PER_Q; |
00bab9106 [SCSI] zfcp: Clea... |
282 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
283 |
} |
564e1c86c [SCSI] zfcp: Move... |
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
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); } |
1da177e4c Linux-2.6.12-rc2 |
308 |
/** |
00bab9106 [SCSI] zfcp: Clea... |
309 310 311 312 313 |
* 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 */ |
d5a282a1c [SCSI] zfcp: intr... |
314 |
static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) |
00bab9106 [SCSI] zfcp: Clea... |
315 |
{ |
564e1c86c [SCSI] zfcp: Move... |
316 |
struct qdio_initialize init_data; |
00bab9106 [SCSI] zfcp: Clea... |
317 |
|
564e1c86c [SCSI] zfcp: Move... |
318 319 |
if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) || zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal)) |
00bab9106 [SCSI] zfcp: Clea... |
320 |
return -ENOMEM; |
564e1c86c [SCSI] zfcp: Move... |
321 322 323 |
zfcp_qdio_setup_init_data(&init_data, qdio); return qdio_allocate(&init_data); |
00bab9106 [SCSI] zfcp: Clea... |
324 325 326 327 |
} /** * zfcp_close_qdio - close qdio queues for an adapter |
564e1c86c [SCSI] zfcp: Move... |
328 |
* @qdio: pointer to structure zfcp_qdio |
1da177e4c Linux-2.6.12-rc2 |
329 |
*/ |
564e1c86c [SCSI] zfcp: Move... |
330 |
void zfcp_qdio_close(struct zfcp_qdio *qdio) |
1da177e4c Linux-2.6.12-rc2 |
331 |
{ |
00bab9106 [SCSI] zfcp: Clea... |
332 333 |
struct zfcp_qdio_queue *req_q; int first, count; |
564e1c86c [SCSI] zfcp: Move... |
334 |
if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) |
00bab9106 [SCSI] zfcp: Clea... |
335 336 337 |
return; /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ |
564e1c86c [SCSI] zfcp: Move... |
338 339 340 341 |
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); |
00bab9106 [SCSI] zfcp: Clea... |
342 |
|
564e1c86c [SCSI] zfcp: Move... |
343 344 |
qdio_shutdown(qdio->adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); |
00bab9106 [SCSI] zfcp: Clea... |
345 346 347 348 349 350 351 |
/* cleanup used outbound sbals */ count = atomic_read(&req_q->count); if (count < QDIO_MAX_BUFFERS_PER_Q) { first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q; count = QDIO_MAX_BUFFERS_PER_Q - count; zfcp_qdio_zero_sbals(req_q->sbal, first, count); |
1da177e4c Linux-2.6.12-rc2 |
352 |
} |
00bab9106 [SCSI] zfcp: Clea... |
353 354 |
req_q->first = 0; atomic_set(&req_q->count, 0); |
564e1c86c [SCSI] zfcp: Move... |
355 356 |
qdio->resp_q.first = 0; atomic_set(&qdio->resp_q.count, 0); |
1da177e4c Linux-2.6.12-rc2 |
357 |
} |
00bab9106 [SCSI] zfcp: Clea... |
358 359 |
/** * zfcp_qdio_open - prepare and initialize response queue |
564e1c86c [SCSI] zfcp: Move... |
360 |
* @qdio: pointer to struct zfcp_qdio |
00bab9106 [SCSI] zfcp: Clea... |
361 362 |
* Returns: 0 on success, otherwise -EIO */ |
564e1c86c [SCSI] zfcp: Move... |
363 |
int zfcp_qdio_open(struct zfcp_qdio *qdio) |
00bab9106 [SCSI] zfcp: Clea... |
364 |
{ |
44cc76f2d [SCSI] zfcp: remo... |
365 |
struct qdio_buffer_element *sbale; |
564e1c86c [SCSI] zfcp: Move... |
366 367 |
struct qdio_initialize init_data; struct ccw_device *cdev = qdio->adapter->ccw_device; |
00bab9106 [SCSI] zfcp: Clea... |
368 |
int cc; |
564e1c86c [SCSI] zfcp: Move... |
369 |
if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) |
00bab9106 [SCSI] zfcp: Clea... |
370 |
return -EIO; |
564e1c86c [SCSI] zfcp: Move... |
371 372 373 |
zfcp_qdio_setup_init_data(&init_data, qdio); if (qdio_establish(&init_data)) |
ff3b24fa5 [SCSI] zfcp: Upda... |
374 |
goto failed_establish; |
00bab9106 [SCSI] zfcp: Clea... |
375 |
|
564e1c86c [SCSI] zfcp: Move... |
376 |
if (qdio_activate(cdev)) |
00bab9106 [SCSI] zfcp: Clea... |
377 |
goto failed_qdio; |
00bab9106 [SCSI] zfcp: Clea... |
378 379 |
for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { |
564e1c86c [SCSI] zfcp: Move... |
380 |
sbale = &(qdio->resp_q.sbal[cc]->element[0]); |
00bab9106 [SCSI] zfcp: Clea... |
381 382 383 384 |
sbale->length = 0; sbale->flags = SBAL_FLAGS_LAST_ENTRY; sbale->addr = NULL; } |
564e1c86c [SCSI] zfcp: Move... |
385 |
if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, |
ff3b24fa5 [SCSI] zfcp: Upda... |
386 |
QDIO_MAX_BUFFERS_PER_Q)) |
00bab9106 [SCSI] zfcp: Clea... |
387 |
goto failed_qdio; |
00bab9106 [SCSI] zfcp: Clea... |
388 389 |
/* set index of first avalable SBALS / number of available SBALS */ |
564e1c86c [SCSI] zfcp: Move... |
390 391 |
qdio->req_q.first = 0; atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q); |
00bab9106 [SCSI] zfcp: Clea... |
392 393 394 395 |
return 0; failed_qdio: |
564e1c86c [SCSI] zfcp: Move... |
396 |
qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); |
ff3b24fa5 [SCSI] zfcp: Upda... |
397 |
failed_establish: |
564e1c86c [SCSI] zfcp: Move... |
398 |
dev_err(&cdev->dev, |
ff3b24fa5 [SCSI] zfcp: Upda... |
399 400 |
"Setting up the QDIO connection to the FCP adapter failed "); |
00bab9106 [SCSI] zfcp: Clea... |
401 402 |
return -EIO; } |
d5a282a1c [SCSI] zfcp: intr... |
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
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; } |