Blame view

drivers/s390/scsi/zfcp_qdio.c 12.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
2
   * zfcp device driver
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
4
   * Setup and helper functions to access QDIO.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   *
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
6
   * Copyright IBM Corporation 2002, 2009
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   */
ecf39d421   Christof Schmitt   [S390] convert zf...
8
9
  #define KMSG_COMPONENT "zfcp"
  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
  #include "zfcp_ext.h"
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
11
  #include "zfcp_qdio.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12

5d4e22624   Christof Schmitt   [SCSI] zfcp: Smal...
13
  #define QBUFF_PER_PAGE		(PAGE_SIZE / sizeof(struct qdio_buffer))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14

00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
15
  static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  {
b4e44590f   Swen Schillig   [SCSI] zfcp: code...
17
  	int pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

b4e44590f   Swen Schillig   [SCSI] zfcp: code...
19
  	for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) {
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
20
21
  		sbal[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL);
  		if (!sbal[pos])
b4e44590f   Swen Schillig   [SCSI] zfcp: code...
22
  			return -ENOMEM;
b4e44590f   Swen Schillig   [SCSI] zfcp: code...
23
24
25
  	}
  	for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++)
  		if (pos % QBUFF_PER_PAGE)
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
26
  			sbal[pos] = sbal[pos - 1] + 1;
b4e44590f   Swen Schillig   [SCSI] zfcp: code...
27
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  }
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
29
  static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
31
  	struct zfcp_adapter *adapter = qdio->adapter;
ff3b24fa5   Christof Schmitt   [SCSI] zfcp: Upda...
32
33
  	dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
35
36
37
  	zfcp_erp_adapter_reopen(adapter,
  				ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
  				ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  }
5d4e22624   Christof Schmitt   [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   Martin Peschke   [SCSI] zfcp: add ...
48
  /* this needs to be called prior to updating the queue fill level */
41e05a12c   Heiko Carstens   [SCSI] zfcp: opti...
49
  static inline void zfcp_qdio_account(struct zfcp_qdio *qdio)
94506fd14   Martin Peschke   [SCSI] zfcp: add ...
50
  {
41e05a12c   Heiko Carstens   [SCSI] zfcp: opti...
51
  	unsigned long long now, span;
94506fd14   Martin Peschke   [SCSI] zfcp: add ...
52
  	int free, used;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
53
  	spin_lock(&qdio->stat_lock);
41e05a12c   Heiko Carstens   [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   Martin Peschke   [SCSI] zfcp: add ...
57
  	used = QDIO_MAX_BUFFERS_PER_Q - free;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
58
59
60
  	qdio->req_q_util += used * span;
  	qdio->req_q_time = now;
  	spin_unlock(&qdio->stat_lock);
94506fd14   Martin Peschke   [SCSI] zfcp: add ...
61
  }
779e6e1c7   Jan Glauber   [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   Swen Schillig   [SCSI] zfcp: Clea...
64
  			      unsigned long parm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
66
67
  	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
  	struct zfcp_qdio_queue *queue = &qdio->req_q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

779e6e1c7   Jan Glauber   [S390] qdio: new ...
69
  	if (unlikely(qdio_err)) {
5771710bd   Swen Schillig   [SCSI] zfcp: Upda...
70
71
  		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
  					count);
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
72
  		zfcp_qdio_handler_error(qdio, "qdireq1");
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
73
74
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  
  	/* cleanup all SBALs being program-owned now */
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
77
  	zfcp_qdio_zero_sbals(queue->sbal, first, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
79
  	zfcp_qdio_account(qdio);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
80
  	atomic_add(count, &queue->count);
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
81
  	wake_up(&qdio->req_q_wq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
83
  static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
85
86
  	struct zfcp_qdio_queue *queue = &qdio->resp_q;
  	struct ccw_device *cdev = qdio->adapter->ccw_device;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
87
88
  	u8 count, start = queue->first;
  	unsigned int retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
90
  	count = atomic_read(&queue->count) + processed;
779e6e1c7   Jan Glauber   [S390] qdio: new ...
91
  	retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
92
93
94
  
  	if (unlikely(retval)) {
  		atomic_set(&queue->count, count);
452b505c5   Christof Schmitt   [SCSI] zfcp: Remo...
95
  		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL);
00bab9106   Swen Schillig   [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   Jan Glauber   [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   Swen Schillig   [SCSI] zfcp: Clea...
104
105
  			       unsigned long parm)
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
106
  	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
bd63eaf4b   Swen Schillig   [SCSI] zfcp: fix ...
107
  	int sbal_idx, sbal_no;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
108

779e6e1c7   Jan Glauber   [S390] qdio: new ...
109
  	if (unlikely(qdio_err)) {
5771710bd   Swen Schillig   [SCSI] zfcp: Upda...
110
111
  		zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first,
  					count);
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
112
  		zfcp_qdio_handler_error(qdio, "qdires1");
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
113
114
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
  	/*
  	 * go through all SBALs from input queue currently
  	 * returned by QDIO layer
  	 */
00bab9106   Swen Schillig   [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   Linus Torvalds   Linux-2.6.12-rc2
122
  		/* go through all SBALEs of SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
123
  		zfcp_fsf_reqid_check(qdio, sbal_idx);
1da177e4c   Linus Torvalds   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   Swen Schillig   [SCSI] zfcp: Move...
130
  	zfcp_qdio_resp_put_back(qdio, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  }
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
132
  static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
133
  				 struct zfcp_qdio_req *q_req, int max_sbals)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
135
  	int count = atomic_read(&qdio->req_q.count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	count = min(count, max_sbals);
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
137
  	q_req->sbal_limit = (q_req->sbal_first + count - 1)
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
138
  					% QDIO_MAX_BUFFERS_PER_Q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  }
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
140
  static struct qdio_buffer_element *
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
141
  zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
142
  		     unsigned long sbtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  {
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
144
  	struct qdio_buffer_element *sbale;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
  
  	/* set last entry flag in current SBALE of current SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
147
  	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
  	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
  
  	/* don't exceed last allowed SBAL */
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
151
  	if (q_req->sbal_last == q_req->sbal_limit)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  		return NULL;
  
  	/* set chaining flag in first SBALE of current SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
155
  	sbale = zfcp_qdio_sbale_req(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
  	sbale->flags |= SBAL_FLAGS0_MORE_SBALS;
  
  	/* calculate index of next SBAL */
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
159
160
  	q_req->sbal_last++;
  	q_req->sbal_last %= QDIO_MAX_BUFFERS_PER_Q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
  
  	/* keep this requests number of SBALs up-to-date */
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
163
  	q_req->sbal_number++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
  
  	/* start at first SBALE of new SBAL */
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
166
  	q_req->sbale_curr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
  
  	/* set storage-block type for new SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
169
  	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
  	sbale->flags |= sbtype;
  
  	return sbale;
  }
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
174
  static struct qdio_buffer_element *
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
175
  zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
176
  		     unsigned int sbtype)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  {
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
178
  	if (q_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
179
  		return zfcp_qdio_sbal_chain(qdio, q_req, sbtype);
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
180
  	q_req->sbale_curr++;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
181
  	return zfcp_qdio_sbale_curr(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
183
  static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio,
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
184
  				 struct zfcp_qdio_req *q_req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
186
  	struct qdio_buffer **sbal = qdio->req_q.sbal;
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
187
188
  	int first = q_req->sbal_first;
  	int last = q_req->sbal_last;
00bab9106   Swen Schillig   [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   Linus Torvalds   Linux-2.6.12-rc2
192
  }
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
193
  static int zfcp_qdio_fill_sbals(struct zfcp_qdio *qdio,
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
194
  				struct zfcp_qdio_req *q_req,
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
195
196
  				unsigned int sbtype, void *start_addr,
  				unsigned int total_length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  {
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
198
  	struct qdio_buffer_element *sbale;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  	unsigned long remaining, length;
  	void *addr;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
201
  	/* split segment up */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
  	for (addr = start_addr, remaining = total_length; remaining > 0;
  	     addr += length, remaining -= length) {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
204
  		sbale = zfcp_qdio_sbale_next(qdio, q_req, sbtype);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
205
  		if (!sbale) {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
206
207
  			atomic_inc(&qdio->req_q_full);
  			zfcp_qdio_undo_sbals(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  			return -EINVAL;
  		}
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
210
211
  
  		/* new piece must not exceed next page boundary */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  		length = min(remaining,
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
213
  			     (PAGE_SIZE - ((unsigned long)addr &
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  					   (PAGE_SIZE - 1))));
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
215
216
  		sbale->addr = addr;
  		sbale->length = length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	}
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
218
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  }
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
225
   * @max_sbals: upper bound for number of SBALs to be used
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
226
   * Returns: number of bytes, or error (negativ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
   */
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
228
  int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
229
230
  			    unsigned long sbtype, struct scatterlist *sg,
  			    int max_sbals)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  {
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
232
  	struct qdio_buffer_element *sbale;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
233
  	int retval, bytes = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  
  	/* figure out last allowed SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
236
  	zfcp_qdio_sbal_limit(qdio, q_req, max_sbals);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
238
  	/* set storage-block type for this request */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
239
  	sbale = zfcp_qdio_sbale_req(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	sbale->flags |= sbtype;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
241
  	for (; sg; sg = sg_next(sg)) {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
242
  		retval = zfcp_qdio_fill_sbals(qdio, q_req, sbtype,
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
243
  					      sg_virt(sg), sg->length);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
244
245
246
  		if (retval < 0)
  			return retval;
  		bytes += sg->length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
  	}
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
248

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  	/* assume that no other SBALEs are to follow in the same SBAL */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
250
  	sbale = zfcp_qdio_sbale_curr(qdio, q_req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
252

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  	return bytes;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  /**
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
256
   * zfcp_qdio_send - set PCI flag in first SBALE and send req to QDIO
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
257
   * @qdio: pointer to struct zfcp_qdio
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
258
   * @q_req: pointer to struct zfcp_qdio_req
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
259
   * Returns: 0 on success, error otherwise
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
   */
34c2b7129   Christof Schmitt   [SCSI] zfcp: Intr...
261
  int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
263
  	struct zfcp_qdio_queue *req_q = &qdio->req_q;
42428f747   Swen Schillig   [SCSI] zfcp: Sepa...
264
265
  	int first = q_req->sbal_first;
  	int count = q_req->sbal_number;
21ddaa53f   Christof Schmitt   [SCSI] zfcp: Remo...
266
267
  	int retval;
  	unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
268

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
269
  	zfcp_qdio_account(qdio);
94506fd14   Martin Peschke   [SCSI] zfcp: add ...
270

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
271
272
  	retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first,
  			 count);
00bab9106   Swen Schillig   [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   Swen Schillig   [SCSI] zfcp: Clea...
282
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  }
564e1c86c   Swen Schillig   [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   Linus Torvalds   Linux-2.6.12-rc2
308
  /**
00bab9106   Swen Schillig   [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   Swen Schillig   [SCSI] zfcp: intr...
314
  static int zfcp_qdio_allocate(struct zfcp_qdio *qdio)
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
315
  {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
316
  	struct qdio_initialize init_data;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
317

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
318
319
  	if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) ||
  	    zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal))
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
320
  		return -ENOMEM;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
321
322
323
  	zfcp_qdio_setup_init_data(&init_data, qdio);
  
  	return qdio_allocate(&init_data);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
324
325
326
327
  }
  
  /**
   * zfcp_close_qdio - close qdio queues for an adapter
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
328
   * @qdio: pointer to structure zfcp_qdio
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
   */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
330
  void zfcp_qdio_close(struct zfcp_qdio *qdio)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  {
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
332
333
  	struct zfcp_qdio_queue *req_q;
  	int first, count;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
334
  	if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP))
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
335
336
337
  		return;
  
  	/* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
564e1c86c   Swen Schillig   [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   Swen Schillig   [SCSI] zfcp: Clea...
342

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
343
344
  	qdio_shutdown(qdio->adapter->ccw_device,
  		      QDIO_FLAG_CLEANUP_USING_CLEAR);
00bab9106   Swen Schillig   [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   Linus Torvalds   Linux-2.6.12-rc2
352
  	}
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
353
354
  	req_q->first = 0;
  	atomic_set(&req_q->count, 0);
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
355
356
  	qdio->resp_q.first = 0;
  	atomic_set(&qdio->resp_q.count, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  }
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
358
359
  /**
   * zfcp_qdio_open - prepare and initialize response queue
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
360
   * @qdio: pointer to struct zfcp_qdio
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
361
362
   * Returns: 0 on success, otherwise -EIO
   */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
363
  int zfcp_qdio_open(struct zfcp_qdio *qdio)
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
364
  {
44cc76f2d   Swen Schillig   [SCSI] zfcp: remo...
365
  	struct qdio_buffer_element *sbale;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
366
367
  	struct qdio_initialize init_data;
  	struct ccw_device *cdev = qdio->adapter->ccw_device;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
368
  	int cc;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
369
  	if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
370
  		return -EIO;
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
371
372
373
  	zfcp_qdio_setup_init_data(&init_data, qdio);
  
  	if (qdio_establish(&init_data))
ff3b24fa5   Christof Schmitt   [SCSI] zfcp: Upda...
374
  		goto failed_establish;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
375

564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
376
  	if (qdio_activate(cdev))
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
377
  		goto failed_qdio;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
378
379
  
  	for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) {
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
380
  		sbale = &(qdio->resp_q.sbal[cc]->element[0]);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
381
382
383
384
  		sbale->length = 0;
  		sbale->flags = SBAL_FLAGS_LAST_ENTRY;
  		sbale->addr = NULL;
  	}
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
385
  	if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0,
ff3b24fa5   Christof Schmitt   [SCSI] zfcp: Upda...
386
  		     QDIO_MAX_BUFFERS_PER_Q))
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
387
  		goto failed_qdio;
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
388
389
  
  	/* set index of first avalable SBALS / number of available SBALS */
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
390
391
  	qdio->req_q.first = 0;
  	atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q);
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
392
393
394
395
  
  	return 0;
  
  failed_qdio:
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
396
  	qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
ff3b24fa5   Christof Schmitt   [SCSI] zfcp: Upda...
397
  failed_establish:
564e1c86c   Swen Schillig   [SCSI] zfcp: Move...
398
  	dev_err(&cdev->dev,
ff3b24fa5   Christof Schmitt   [SCSI] zfcp: Upda...
399
400
  		"Setting up the QDIO connection to the FCP adapter failed
  ");
00bab9106   Swen Schillig   [SCSI] zfcp: Clea...
401
402
  	return -EIO;
  }
d5a282a1c   Swen Schillig   [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;
  }