diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/qla2xxx/qla_iocb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_iocb.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_iocb.c | 633 |
1 files changed, 633 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c new file mode 100644 index 000000000000..ec066074c722 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_iocb.c | |||
@@ -0,0 +1,633 @@ | |||
1 | /****************************************************************************** | ||
2 | * QLOGIC LINUX SOFTWARE | ||
3 | * | ||
4 | * QLogic ISP2x00 device driver for Linux 2.6.x | ||
5 | * Copyright (C) 2003-2004 QLogic Corporation | ||
6 | * (www.qlogic.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2, or (at your option) any | ||
11 | * later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | ******************************************************************************/ | ||
19 | |||
20 | #include "qla_def.h" | ||
21 | |||
22 | #include <linux/blkdev.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #include <scsi/scsi_tcq.h> | ||
26 | |||
27 | static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); | ||
28 | static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); | ||
29 | static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); | ||
30 | static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); | ||
31 | |||
32 | /** | ||
33 | * qla2x00_get_cmd_direction() - Determine control_flag data direction. | ||
34 | * @cmd: SCSI command | ||
35 | * | ||
36 | * Returns the proper CF_* direction based on CDB. | ||
37 | */ | ||
38 | static inline uint16_t | ||
39 | qla2x00_get_cmd_direction(struct scsi_cmnd *cmd) | ||
40 | { | ||
41 | uint16_t cflags; | ||
42 | |||
43 | cflags = 0; | ||
44 | |||
45 | /* Set transfer direction */ | ||
46 | if (cmd->sc_data_direction == DMA_TO_DEVICE) | ||
47 | cflags = CF_WRITE; | ||
48 | else if (cmd->sc_data_direction == DMA_FROM_DEVICE) | ||
49 | cflags = CF_READ; | ||
50 | return (cflags); | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and | ||
55 | * Continuation Type 0 IOCBs to allocate. | ||
56 | * | ||
57 | * @dsds: number of data segment decriptors needed | ||
58 | * | ||
59 | * Returns the number of IOCB entries needed to store @dsds. | ||
60 | */ | ||
61 | uint16_t | ||
62 | qla2x00_calc_iocbs_32(uint16_t dsds) | ||
63 | { | ||
64 | uint16_t iocbs; | ||
65 | |||
66 | iocbs = 1; | ||
67 | if (dsds > 3) { | ||
68 | iocbs += (dsds - 3) / 7; | ||
69 | if ((dsds - 3) % 7) | ||
70 | iocbs++; | ||
71 | } | ||
72 | return (iocbs); | ||
73 | } | ||
74 | |||
75 | /** | ||
76 | * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and | ||
77 | * Continuation Type 1 IOCBs to allocate. | ||
78 | * | ||
79 | * @dsds: number of data segment decriptors needed | ||
80 | * | ||
81 | * Returns the number of IOCB entries needed to store @dsds. | ||
82 | */ | ||
83 | uint16_t | ||
84 | qla2x00_calc_iocbs_64(uint16_t dsds) | ||
85 | { | ||
86 | uint16_t iocbs; | ||
87 | |||
88 | iocbs = 1; | ||
89 | if (dsds > 2) { | ||
90 | iocbs += (dsds - 2) / 5; | ||
91 | if ((dsds - 2) % 5) | ||
92 | iocbs++; | ||
93 | } | ||
94 | return (iocbs); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. | ||
99 | * @ha: HA context | ||
100 | * | ||
101 | * Returns a pointer to the Continuation Type 0 IOCB packet. | ||
102 | */ | ||
103 | static inline cont_entry_t * | ||
104 | qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *ha) | ||
105 | { | ||
106 | cont_entry_t *cont_pkt; | ||
107 | |||
108 | /* Adjust ring index. */ | ||
109 | ha->req_ring_index++; | ||
110 | if (ha->req_ring_index == ha->request_q_length) { | ||
111 | ha->req_ring_index = 0; | ||
112 | ha->request_ring_ptr = ha->request_ring; | ||
113 | } else { | ||
114 | ha->request_ring_ptr++; | ||
115 | } | ||
116 | |||
117 | cont_pkt = (cont_entry_t *)ha->request_ring_ptr; | ||
118 | |||
119 | /* Load packet defaults. */ | ||
120 | *((uint32_t *)(&cont_pkt->entry_type)) = | ||
121 | __constant_cpu_to_le32(CONTINUE_TYPE); | ||
122 | |||
123 | return (cont_pkt); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. | ||
128 | * @ha: HA context | ||
129 | * | ||
130 | * Returns a pointer to the continuation type 1 IOCB packet. | ||
131 | */ | ||
132 | static inline cont_a64_entry_t * | ||
133 | qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *ha) | ||
134 | { | ||
135 | cont_a64_entry_t *cont_pkt; | ||
136 | |||
137 | /* Adjust ring index. */ | ||
138 | ha->req_ring_index++; | ||
139 | if (ha->req_ring_index == ha->request_q_length) { | ||
140 | ha->req_ring_index = 0; | ||
141 | ha->request_ring_ptr = ha->request_ring; | ||
142 | } else { | ||
143 | ha->request_ring_ptr++; | ||
144 | } | ||
145 | |||
146 | cont_pkt = (cont_a64_entry_t *)ha->request_ring_ptr; | ||
147 | |||
148 | /* Load packet defaults. */ | ||
149 | *((uint32_t *)(&cont_pkt->entry_type)) = | ||
150 | __constant_cpu_to_le32(CONTINUE_A64_TYPE); | ||
151 | |||
152 | return (cont_pkt); | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit | ||
157 | * capable IOCB types. | ||
158 | * | ||
159 | * @sp: SRB command to process | ||
160 | * @cmd_pkt: Command type 2 IOCB | ||
161 | * @tot_dsds: Total number of segments to transfer | ||
162 | */ | ||
163 | void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, | ||
164 | uint16_t tot_dsds) | ||
165 | { | ||
166 | uint16_t avail_dsds; | ||
167 | uint32_t *cur_dsd; | ||
168 | scsi_qla_host_t *ha; | ||
169 | struct scsi_cmnd *cmd; | ||
170 | |||
171 | cmd = sp->cmd; | ||
172 | |||
173 | /* Update entry type to indicate Command Type 2 IOCB */ | ||
174 | *((uint32_t *)(&cmd_pkt->entry_type)) = | ||
175 | __constant_cpu_to_le32(COMMAND_TYPE); | ||
176 | |||
177 | /* No data transfer */ | ||
178 | if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { | ||
179 | cmd_pkt->byte_count = __constant_cpu_to_le32(0); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | ha = sp->ha; | ||
184 | |||
185 | cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); | ||
186 | |||
187 | /* Three DSDs are available in the Command Type 2 IOCB */ | ||
188 | avail_dsds = 3; | ||
189 | cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; | ||
190 | |||
191 | /* Load data segments */ | ||
192 | if (cmd->use_sg != 0) { | ||
193 | struct scatterlist *cur_seg; | ||
194 | struct scatterlist *end_seg; | ||
195 | |||
196 | cur_seg = (struct scatterlist *)cmd->request_buffer; | ||
197 | end_seg = cur_seg + tot_dsds; | ||
198 | while (cur_seg < end_seg) { | ||
199 | cont_entry_t *cont_pkt; | ||
200 | |||
201 | /* Allocate additional continuation packets? */ | ||
202 | if (avail_dsds == 0) { | ||
203 | /* | ||
204 | * Seven DSDs are available in the Continuation | ||
205 | * Type 0 IOCB. | ||
206 | */ | ||
207 | cont_pkt = qla2x00_prep_cont_type0_iocb(ha); | ||
208 | cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; | ||
209 | avail_dsds = 7; | ||
210 | } | ||
211 | |||
212 | *cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg)); | ||
213 | *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); | ||
214 | avail_dsds--; | ||
215 | |||
216 | cur_seg++; | ||
217 | } | ||
218 | } else { | ||
219 | dma_addr_t req_dma; | ||
220 | struct page *page; | ||
221 | unsigned long offset; | ||
222 | |||
223 | page = virt_to_page(cmd->request_buffer); | ||
224 | offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); | ||
225 | req_dma = pci_map_page(ha->pdev, page, offset, | ||
226 | cmd->request_bufflen, cmd->sc_data_direction); | ||
227 | |||
228 | sp->dma_handle = req_dma; | ||
229 | |||
230 | *cur_dsd++ = cpu_to_le32(req_dma); | ||
231 | *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /** | ||
236 | * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit | ||
237 | * capable IOCB types. | ||
238 | * | ||
239 | * @sp: SRB command to process | ||
240 | * @cmd_pkt: Command type 3 IOCB | ||
241 | * @tot_dsds: Total number of segments to transfer | ||
242 | */ | ||
243 | void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, | ||
244 | uint16_t tot_dsds) | ||
245 | { | ||
246 | uint16_t avail_dsds; | ||
247 | uint32_t *cur_dsd; | ||
248 | scsi_qla_host_t *ha; | ||
249 | struct scsi_cmnd *cmd; | ||
250 | |||
251 | cmd = sp->cmd; | ||
252 | |||
253 | /* Update entry type to indicate Command Type 3 IOCB */ | ||
254 | *((uint32_t *)(&cmd_pkt->entry_type)) = | ||
255 | __constant_cpu_to_le32(COMMAND_A64_TYPE); | ||
256 | |||
257 | /* No data transfer */ | ||
258 | if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) { | ||
259 | cmd_pkt->byte_count = __constant_cpu_to_le32(0); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | ha = sp->ha; | ||
264 | |||
265 | cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd)); | ||
266 | |||
267 | /* Two DSDs are available in the Command Type 3 IOCB */ | ||
268 | avail_dsds = 2; | ||
269 | cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; | ||
270 | |||
271 | /* Load data segments */ | ||
272 | if (cmd->use_sg != 0) { | ||
273 | struct scatterlist *cur_seg; | ||
274 | struct scatterlist *end_seg; | ||
275 | |||
276 | cur_seg = (struct scatterlist *)cmd->request_buffer; | ||
277 | end_seg = cur_seg + tot_dsds; | ||
278 | while (cur_seg < end_seg) { | ||
279 | dma_addr_t sle_dma; | ||
280 | cont_a64_entry_t *cont_pkt; | ||
281 | |||
282 | /* Allocate additional continuation packets? */ | ||
283 | if (avail_dsds == 0) { | ||
284 | /* | ||
285 | * Five DSDs are available in the Continuation | ||
286 | * Type 1 IOCB. | ||
287 | */ | ||
288 | cont_pkt = qla2x00_prep_cont_type1_iocb(ha); | ||
289 | cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; | ||
290 | avail_dsds = 5; | ||
291 | } | ||
292 | |||
293 | sle_dma = sg_dma_address(cur_seg); | ||
294 | *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); | ||
295 | *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); | ||
296 | *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); | ||
297 | avail_dsds--; | ||
298 | |||
299 | cur_seg++; | ||
300 | } | ||
301 | } else { | ||
302 | dma_addr_t req_dma; | ||
303 | struct page *page; | ||
304 | unsigned long offset; | ||
305 | |||
306 | page = virt_to_page(cmd->request_buffer); | ||
307 | offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK); | ||
308 | req_dma = pci_map_page(ha->pdev, page, offset, | ||
309 | cmd->request_bufflen, cmd->sc_data_direction); | ||
310 | |||
311 | sp->dma_handle = req_dma; | ||
312 | |||
313 | *cur_dsd++ = cpu_to_le32(LSD(req_dma)); | ||
314 | *cur_dsd++ = cpu_to_le32(MSD(req_dma)); | ||
315 | *cur_dsd++ = cpu_to_le32(cmd->request_bufflen); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * qla2x00_start_scsi() - Send a SCSI command to the ISP | ||
321 | * @sp: command to send to the ISP | ||
322 | * | ||
323 | * Returns non-zero if a failure occured, else zero. | ||
324 | */ | ||
325 | int | ||
326 | qla2x00_start_scsi(srb_t *sp) | ||
327 | { | ||
328 | int ret; | ||
329 | unsigned long flags; | ||
330 | scsi_qla_host_t *ha; | ||
331 | fc_lun_t *fclun; | ||
332 | struct scsi_cmnd *cmd; | ||
333 | uint32_t *clr_ptr; | ||
334 | uint32_t index; | ||
335 | uint32_t handle; | ||
336 | cmd_entry_t *cmd_pkt; | ||
337 | uint32_t timeout; | ||
338 | struct scatterlist *sg; | ||
339 | uint16_t cnt; | ||
340 | uint16_t req_cnt; | ||
341 | uint16_t tot_dsds; | ||
342 | device_reg_t __iomem *reg; | ||
343 | char tag[2]; | ||
344 | |||
345 | /* Setup device pointers. */ | ||
346 | ret = 0; | ||
347 | fclun = sp->lun_queue->fclun; | ||
348 | ha = fclun->fcport->ha; | ||
349 | reg = ha->iobase; | ||
350 | cmd = sp->cmd; | ||
351 | |||
352 | /* Send marker if required */ | ||
353 | if (ha->marker_needed != 0) { | ||
354 | if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { | ||
355 | return (QLA_FUNCTION_FAILED); | ||
356 | } | ||
357 | ha->marker_needed = 0; | ||
358 | } | ||
359 | |||
360 | /* Acquire ring specific lock */ | ||
361 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
362 | |||
363 | /* Check for room in outstanding command list. */ | ||
364 | handle = ha->current_outstanding_cmd; | ||
365 | for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { | ||
366 | handle++; | ||
367 | if (handle == MAX_OUTSTANDING_COMMANDS) | ||
368 | handle = 1; | ||
369 | if (ha->outstanding_cmds[handle] == 0) | ||
370 | break; | ||
371 | } | ||
372 | if (index == MAX_OUTSTANDING_COMMANDS) | ||
373 | goto queuing_error; | ||
374 | |||
375 | /* Calculate the number of request entries needed. */ | ||
376 | req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments); | ||
377 | if (ha->req_q_cnt < (req_cnt + 2)) { | ||
378 | cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg)); | ||
379 | if (ha->req_ring_index < cnt) | ||
380 | ha->req_q_cnt = cnt - ha->req_ring_index; | ||
381 | else | ||
382 | ha->req_q_cnt = ha->request_q_length - | ||
383 | (ha->req_ring_index - cnt); | ||
384 | } | ||
385 | if (ha->req_q_cnt < (req_cnt + 2)) | ||
386 | goto queuing_error; | ||
387 | |||
388 | /* Finally, we have enough space, now perform mappings. */ | ||
389 | tot_dsds = 0; | ||
390 | if (cmd->use_sg) { | ||
391 | sg = (struct scatterlist *) cmd->request_buffer; | ||
392 | tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg, | ||
393 | cmd->sc_data_direction); | ||
394 | if (tot_dsds == 0) | ||
395 | goto queuing_error; | ||
396 | } else if (cmd->request_bufflen) { | ||
397 | tot_dsds++; | ||
398 | } | ||
399 | req_cnt = (ha->calc_request_entries)(tot_dsds); | ||
400 | |||
401 | /* Build command packet */ | ||
402 | ha->current_outstanding_cmd = handle; | ||
403 | ha->outstanding_cmds[handle] = sp; | ||
404 | sp->ha = ha; | ||
405 | sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; | ||
406 | ha->req_q_cnt -= req_cnt; | ||
407 | |||
408 | cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr; | ||
409 | cmd_pkt->handle = handle; | ||
410 | /* Zero out remaining portion of packet. */ | ||
411 | clr_ptr = (uint32_t *)cmd_pkt + 2; | ||
412 | memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); | ||
413 | cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); | ||
414 | |||
415 | /* Set target ID */ | ||
416 | SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id); | ||
417 | |||
418 | /* Set LUN number*/ | ||
419 | cmd_pkt->lun = cpu_to_le16(fclun->lun); | ||
420 | |||
421 | /* Update tagged queuing modifier */ | ||
422 | cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); | ||
423 | if (scsi_populate_tag_msg(cmd, tag)) { | ||
424 | switch (tag[0]) { | ||
425 | case MSG_HEAD_TAG: | ||
426 | cmd_pkt->control_flags = | ||
427 | __constant_cpu_to_le16(CF_HEAD_TAG); | ||
428 | break; | ||
429 | case MSG_ORDERED_TAG: | ||
430 | cmd_pkt->control_flags = | ||
431 | __constant_cpu_to_le16(CF_ORDERED_TAG); | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Allocate at least 5 (+ QLA_CMD_TIMER_DELTA) seconds for RISC timeout. | ||
438 | */ | ||
439 | timeout = (uint32_t)(cmd->timeout_per_command / HZ); | ||
440 | if (timeout > 65535) | ||
441 | cmd_pkt->timeout = __constant_cpu_to_le16(0); | ||
442 | else if (timeout > 25) | ||
443 | cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout - | ||
444 | (5 + QLA_CMD_TIMER_DELTA)); | ||
445 | else | ||
446 | cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout); | ||
447 | |||
448 | /* Load SCSI command packet. */ | ||
449 | memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); | ||
450 | cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen); | ||
451 | |||
452 | /* Build IOCB segments */ | ||
453 | (ha->build_scsi_iocbs)(sp, cmd_pkt, tot_dsds); | ||
454 | |||
455 | /* Set total data segment count. */ | ||
456 | cmd_pkt->entry_count = (uint8_t)req_cnt; | ||
457 | wmb(); | ||
458 | |||
459 | /* Adjust ring index. */ | ||
460 | ha->req_ring_index++; | ||
461 | if (ha->req_ring_index == ha->request_q_length) { | ||
462 | ha->req_ring_index = 0; | ||
463 | ha->request_ring_ptr = ha->request_ring; | ||
464 | } else | ||
465 | ha->request_ring_ptr++; | ||
466 | |||
467 | ha->actthreads++; | ||
468 | ha->total_ios++; | ||
469 | sp->lun_queue->out_cnt++; | ||
470 | sp->flags |= SRB_DMA_VALID; | ||
471 | sp->state = SRB_ACTIVE_STATE; | ||
472 | sp->u_start = jiffies; | ||
473 | |||
474 | /* Set chip new ring index. */ | ||
475 | WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); | ||
476 | RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ | ||
477 | |||
478 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
479 | return (QLA_SUCCESS); | ||
480 | |||
481 | queuing_error: | ||
482 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
483 | |||
484 | return (QLA_FUNCTION_FAILED); | ||
485 | } | ||
486 | |||
487 | /** | ||
488 | * qla2x00_marker() - Send a marker IOCB to the firmware. | ||
489 | * @ha: HA context | ||
490 | * @loop_id: loop ID | ||
491 | * @lun: LUN | ||
492 | * @type: marker modifier | ||
493 | * | ||
494 | * Can be called from both normal and interrupt context. | ||
495 | * | ||
496 | * Returns non-zero if a failure occured, else zero. | ||
497 | */ | ||
498 | int | ||
499 | __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, | ||
500 | uint8_t type) | ||
501 | { | ||
502 | mrk_entry_t *pkt; | ||
503 | |||
504 | pkt = (mrk_entry_t *)qla2x00_req_pkt(ha); | ||
505 | if (pkt == NULL) { | ||
506 | DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); | ||
507 | |||
508 | return (QLA_FUNCTION_FAILED); | ||
509 | } | ||
510 | |||
511 | pkt->entry_type = MARKER_TYPE; | ||
512 | pkt->modifier = type; | ||
513 | |||
514 | if (type != MK_SYNC_ALL) { | ||
515 | pkt->lun = cpu_to_le16(lun); | ||
516 | SET_TARGET_ID(ha, pkt->target, loop_id); | ||
517 | } | ||
518 | wmb(); | ||
519 | |||
520 | /* Issue command to ISP */ | ||
521 | qla2x00_isp_cmd(ha); | ||
522 | |||
523 | return (QLA_SUCCESS); | ||
524 | } | ||
525 | |||
526 | int | ||
527 | qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, | ||
528 | uint8_t type) | ||
529 | { | ||
530 | int ret; | ||
531 | unsigned long flags = 0; | ||
532 | |||
533 | spin_lock_irqsave(&ha->hardware_lock, flags); | ||
534 | ret = __qla2x00_marker(ha, loop_id, lun, type); | ||
535 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | ||
536 | |||
537 | return (ret); | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * qla2x00_req_pkt() - Retrieve a request packet from the request ring. | ||
542 | * @ha: HA context | ||
543 | * | ||
544 | * Note: The caller must hold the hardware lock before calling this routine. | ||
545 | * | ||
546 | * Returns NULL if function failed, else, a pointer to the request packet. | ||
547 | */ | ||
548 | static request_t * | ||
549 | qla2x00_req_pkt(scsi_qla_host_t *ha) | ||
550 | { | ||
551 | device_reg_t __iomem *reg = ha->iobase; | ||
552 | request_t *pkt = NULL; | ||
553 | uint16_t cnt; | ||
554 | uint32_t *dword_ptr; | ||
555 | uint32_t timer; | ||
556 | uint16_t req_cnt = 1; | ||
557 | |||
558 | /* Wait 1 second for slot. */ | ||
559 | for (timer = HZ; timer; timer--) { | ||
560 | if ((req_cnt + 2) >= ha->req_q_cnt) { | ||
561 | /* Calculate number of free request entries. */ | ||
562 | cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); | ||
563 | if (ha->req_ring_index < cnt) | ||
564 | ha->req_q_cnt = cnt - ha->req_ring_index; | ||
565 | else | ||
566 | ha->req_q_cnt = ha->request_q_length - | ||
567 | (ha->req_ring_index - cnt); | ||
568 | } | ||
569 | /* If room for request in request ring. */ | ||
570 | if ((req_cnt + 2) < ha->req_q_cnt) { | ||
571 | ha->req_q_cnt--; | ||
572 | pkt = ha->request_ring_ptr; | ||
573 | |||
574 | /* Zero out packet. */ | ||
575 | dword_ptr = (uint32_t *)pkt; | ||
576 | for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++) | ||
577 | *dword_ptr++ = 0; | ||
578 | |||
579 | /* Set system defined field. */ | ||
580 | pkt->sys_define = (uint8_t)ha->req_ring_index; | ||
581 | |||
582 | /* Set entry count. */ | ||
583 | pkt->entry_count = 1; | ||
584 | |||
585 | break; | ||
586 | } | ||
587 | |||
588 | /* Release ring specific lock */ | ||
589 | spin_unlock(&ha->hardware_lock); | ||
590 | |||
591 | udelay(2); /* 2 us */ | ||
592 | |||
593 | /* Check for pending interrupts. */ | ||
594 | /* During init we issue marker directly */ | ||
595 | if (!ha->marker_needed) | ||
596 | qla2x00_poll(ha); | ||
597 | |||
598 | spin_lock_irq(&ha->hardware_lock); | ||
599 | } | ||
600 | if (!pkt) { | ||
601 | DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); | ||
602 | } | ||
603 | |||
604 | return (pkt); | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * qla2x00_isp_cmd() - Modify the request ring pointer. | ||
609 | * @ha: HA context | ||
610 | * | ||
611 | * Note: The caller must hold the hardware lock before calling this routine. | ||
612 | */ | ||
613 | void | ||
614 | qla2x00_isp_cmd(scsi_qla_host_t *ha) | ||
615 | { | ||
616 | device_reg_t __iomem *reg = ha->iobase; | ||
617 | |||
618 | DEBUG5(printk("%s(): IOCB data:\n", __func__)); | ||
619 | DEBUG5(qla2x00_dump_buffer( | ||
620 | (uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE)); | ||
621 | |||
622 | /* Adjust ring index. */ | ||
623 | ha->req_ring_index++; | ||
624 | if (ha->req_ring_index == ha->request_q_length) { | ||
625 | ha->req_ring_index = 0; | ||
626 | ha->request_ring_ptr = ha->request_ring; | ||
627 | } else | ||
628 | ha->request_ring_ptr++; | ||
629 | |||
630 | /* Set chip new ring index. */ | ||
631 | WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index); | ||
632 | RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ | ||
633 | } | ||