blob: cb40d61e82d53730f1b5846f3a256252a64f9e19 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Andrew Vasquezfa90c542005-10-27 11:10:08 -07002 * QLogic Fibre Channel HBA Driver
3 * Copyright (c) 2003-2005 QLogic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Andrew Vasquezfa90c542005-10-27 11:10:08 -07005 * See LICENSE.qla2xxx for copyright and licensing details.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
7#include "qla_def.h"
8
9/**
10 * IO descriptor handle definitions.
11 *
12 * Signature form:
13 *
14 * |31------28|27-------------------12|11-------0|
15 * | Type | Rolling Signature | Index |
16 * |----------|-----------------------|----------|
17 *
18 **/
19
20#define HDL_TYPE_SCSI 0
21#define HDL_TYPE_ASYNC_IOCB 0x0A
22
23#define HDL_INDEX_BITS 12
24#define HDL_ITER_BITS 16
25#define HDL_TYPE_BITS 4
26
27#define HDL_INDEX_MASK ((1UL << HDL_INDEX_BITS) - 1)
28#define HDL_ITER_MASK ((1UL << HDL_ITER_BITS) - 1)
29#define HDL_TYPE_MASK ((1UL << HDL_TYPE_BITS) - 1)
30
31#define HDL_INDEX_SHIFT 0
32#define HDL_ITER_SHIFT (HDL_INDEX_SHIFT + HDL_INDEX_BITS)
33#define HDL_TYPE_SHIFT (HDL_ITER_SHIFT + HDL_ITER_BITS)
34
35/* Local Prototypes. */
36static inline uint32_t qla2x00_to_handle(uint16_t, uint16_t, uint16_t);
37static inline uint16_t qla2x00_handle_to_idx(uint32_t);
38static inline uint32_t qla2x00_iodesc_to_handle(struct io_descriptor *);
39static inline struct io_descriptor *qla2x00_handle_to_iodesc(scsi_qla_host_t *,
40 uint32_t);
41
42static inline struct io_descriptor *qla2x00_alloc_iodesc(scsi_qla_host_t *);
43static inline void qla2x00_free_iodesc(struct io_descriptor *);
44static inline void qla2x00_init_io_descriptors(scsi_qla_host_t *);
45
46static void qla2x00_iodesc_timeout(unsigned long);
47static inline void qla2x00_add_iodesc_timer(struct io_descriptor *);
48static inline void qla2x00_remove_iodesc_timer(struct io_descriptor *);
49
50static inline void qla2x00_update_login_fcport(scsi_qla_host_t *,
51 struct mbx_entry *, fc_port_t *);
52
53static int qla2x00_send_abort_iocb(scsi_qla_host_t *, struct io_descriptor *,
54 uint32_t, int);
55static int qla2x00_send_abort_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
56 struct mbx_entry *);
57
58static int qla2x00_send_adisc_iocb(scsi_qla_host_t *, struct io_descriptor *,
59 int);
60static int qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
61 struct mbx_entry *);
62
63static int qla2x00_send_logout_iocb(scsi_qla_host_t *, struct io_descriptor *,
64 int);
65static int qla2x00_send_logout_iocb_cb(scsi_qla_host_t *,
66 struct io_descriptor *, struct mbx_entry *);
67
68static int qla2x00_send_login_iocb(scsi_qla_host_t *, struct io_descriptor *,
69 port_id_t *, int);
70static int qla2x00_send_login_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
71 struct mbx_entry *);
72
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -070073/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 * Mailbox IOCB callback array.
75 **/
76static int (*iocb_function_cb_list[LAST_IOCB_CB])
77 (scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *) = {
78
79 qla2x00_send_abort_iocb_cb,
80 qla2x00_send_adisc_iocb_cb,
81 qla2x00_send_logout_iocb_cb,
82 qla2x00_send_login_iocb_cb,
83};
84
85
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -070086/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 * Generic IO descriptor handle routines.
88 **/
89
90/**
91 * qla2x00_to_handle() - Create a descriptor handle.
92 * @type: descriptor type
93 * @iter: descriptor rolling signature
94 * @idx: index to the descriptor array
95 *
96 * Returns a composite handle based in the @type, @iter, and @idx.
97 */
98static inline uint32_t
99qla2x00_to_handle(uint16_t type, uint16_t iter, uint16_t idx)
100{
101 return ((uint32_t)(((uint32_t)type << HDL_TYPE_SHIFT) |
102 ((uint32_t)iter << HDL_ITER_SHIFT) |
103 ((uint32_t)idx << HDL_INDEX_SHIFT)));
104}
105
106/**
107 * qla2x00_handle_to_idx() - Retrive the index for a given handle.
108 * @handle: descriptor handle
109 *
110 * Returns the index specified by the @handle.
111 */
112static inline uint16_t
113qla2x00_handle_to_idx(uint32_t handle)
114{
115 return ((uint16_t)(((handle) >> HDL_INDEX_SHIFT) & HDL_INDEX_MASK));
116}
117
118/**
119 * qla2x00_iodesc_to_handle() - Convert an IO descriptor to a unique handle.
120 * @iodesc: io descriptor
121 *
122 * Returns a unique handle for @iodesc.
123 */
124static inline uint32_t
125qla2x00_iodesc_to_handle(struct io_descriptor *iodesc)
126{
127 uint32_t handle;
128
129 handle = qla2x00_to_handle(HDL_TYPE_ASYNC_IOCB,
130 ++iodesc->ha->iodesc_signature, iodesc->idx);
131 iodesc->signature = handle;
132
133 return (handle);
134}
135
136/**
137 * qla2x00_handle_to_iodesc() - Retrieve an IO descriptor given a unique handle.
138 * @ha: HA context
139 * @handle: handle to io descriptor
140 *
141 * Returns a pointer to the io descriptor, or NULL, if the io descriptor does
142 * not exist or the io descriptors signature does not @handle.
143 */
144static inline struct io_descriptor *
145qla2x00_handle_to_iodesc(scsi_qla_host_t *ha, uint32_t handle)
146{
147 uint16_t idx;
148 struct io_descriptor *iodesc;
149
150 idx = qla2x00_handle_to_idx(handle);
151 iodesc = &ha->io_descriptors[idx];
152 if (iodesc)
153 if (iodesc->signature != handle)
154 iodesc = NULL;
155
156 return (iodesc);
157}
158
159
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700160/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 * IO descriptor allocation routines.
162 **/
163
164/**
165 * qla2x00_alloc_iodesc() - Allocate an IO descriptor from the pool.
166 * @ha: HA context
167 *
168 * Returns a pointer to the allocated io descriptor, or NULL, if none available.
169 */
170static inline struct io_descriptor *
171qla2x00_alloc_iodesc(scsi_qla_host_t *ha)
172{
173 uint16_t iter;
174 struct io_descriptor *iodesc;
175
176 iodesc = NULL;
177 for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) {
178 if (ha->io_descriptors[iter].used)
179 continue;
180
181 iodesc = &ha->io_descriptors[iter];
182 iodesc->used = 1;
183 iodesc->idx = iter;
184 init_timer(&iodesc->timer);
185 iodesc->ha = ha;
186 iodesc->signature = qla2x00_iodesc_to_handle(iodesc);
187 break;
188 }
189
190 return (iodesc);
191}
192
193/**
194 * qla2x00_free_iodesc() - Free an IO descriptor.
195 * @iodesc: io descriptor
196 *
197 * NOTE: The io descriptors timer *must* be stopped before it can be free'd.
198 */
199static inline void
200qla2x00_free_iodesc(struct io_descriptor *iodesc)
201{
202 iodesc->used = 0;
203 iodesc->signature = 0;
204}
205
206/**
207 * qla2x00_remove_iodesc_timer() - Remove an active timer from an IO descriptor.
208 * @iodesc: io descriptor
209 */
210static inline void
211qla2x00_remove_iodesc_timer(struct io_descriptor *iodesc)
212{
213 if (iodesc->timer.function != NULL) {
214 del_timer_sync(&iodesc->timer);
215 iodesc->timer.data = (unsigned long) NULL;
216 iodesc->timer.function = NULL;
217 }
218}
219
220/**
221 * qla2x00_init_io_descriptors() - Initialize the pool of IO descriptors.
222 * @ha: HA context
223 */
224static inline void
225qla2x00_init_io_descriptors(scsi_qla_host_t *ha)
226{
227 uint16_t iter;
228
229 for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) {
230 if (!ha->io_descriptors[iter].used)
231 continue;
232
233 qla2x00_remove_iodesc_timer(&ha->io_descriptors[iter]);
234 qla2x00_free_iodesc(&ha->io_descriptors[iter]);
235 }
236}
237
238
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700239/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 * IO descriptor timer routines.
241 **/
242
243/**
244 * qla2x00_iodesc_timeout() - Timeout IO descriptor handler.
245 * @data: io descriptor
246 */
247static void
248qla2x00_iodesc_timeout(unsigned long data)
249{
250 struct io_descriptor *iodesc;
251
252 iodesc = (struct io_descriptor *) data;
253
254 DEBUG14(printk("scsi(%ld): IO descriptor timeout, index=%x "
255 "signature=%08x, scheduling ISP abort.\n", iodesc->ha->host_no,
256 iodesc->idx, iodesc->signature));
257
258 qla2x00_free_iodesc(iodesc);
259
260 qla_printk(KERN_WARNING, iodesc->ha,
261 "IO descriptor timeout. Scheduling ISP abort.\n");
262 set_bit(ISP_ABORT_NEEDED, &iodesc->ha->dpc_flags);
263}
264
265/**
266 * qla2x00_add_iodesc_timer() - Add and start a timer for an IO descriptor.
267 * @iodesc: io descriptor
268 *
269 * NOTE:
270 * The firmware shall timeout an outstanding mailbox IOCB in 2 * R_A_TOV (in
271 * tenths of a second) after it hits the wire. But, if there are any request
272 * resource contraints (i.e. during heavy I/O), exchanges can be held off for
273 * at most R_A_TOV. Therefore, the driver will wait 4 * R_A_TOV before
274 * scheduling a recovery (big hammer).
275 */
276static inline void
277qla2x00_add_iodesc_timer(struct io_descriptor *iodesc)
278{
279 unsigned long timeout;
280
281 timeout = (iodesc->ha->r_a_tov * 4) / 10;
282 init_timer(&iodesc->timer);
283 iodesc->timer.data = (unsigned long) iodesc;
284 iodesc->timer.expires = jiffies + (timeout * HZ);
285 iodesc->timer.function =
286 (void (*) (unsigned long)) qla2x00_iodesc_timeout;
287 add_timer(&iodesc->timer);
288}
289
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700290/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 * IO descriptor support routines.
292 **/
293
294/**
295 * qla2x00_update_login_fcport() - Update fcport data after login processing.
296 * @ha: HA context
297 * @mbxstat: Mailbox command status IOCB
298 * @fcport: port to update
299 */
300static inline void
301qla2x00_update_login_fcport(scsi_qla_host_t *ha, struct mbx_entry *mbxstat,
302 fc_port_t *fcport)
303{
304 if (le16_to_cpu(mbxstat->mb1) & BIT_0) {
305 fcport->port_type = FCT_INITIATOR;
306 } else {
307 fcport->port_type = FCT_TARGET;
308 if (le16_to_cpu(mbxstat->mb1) & BIT_1) {
309 fcport->flags |= FCF_TAPE_PRESENT;
310 }
311 }
312 fcport->login_retry = 0;
313 fcport->port_login_retry_count = ha->port_down_retry_count *
314 PORT_RETRY_TIME;
315 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
316 PORT_RETRY_TIME);
317 fcport->flags |= FCF_FABRIC_DEVICE;
318 fcport->flags &= ~FCF_FAILOVER_NEEDED;
319 fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
320 atomic_set(&fcport->state, FCS_ONLINE);
Andrew Vasquez44550322005-09-20 13:32:11 -0700321 if (fcport->rport)
322 fc_remote_port_unblock(fcport->rport);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
325
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700326/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 * Mailbox IOCB commands.
328 **/
329
330/**
331 * qla2x00_get_mbx_iocb_entry() - Retrieve an IOCB from the request queue.
332 * @ha: HA context
333 * @handle: handle to io descriptor
334 *
335 * Returns a pointer to the reqest entry, or NULL, if none were available.
336 */
337static inline struct mbx_entry *
338qla2x00_get_mbx_iocb_entry(scsi_qla_host_t *ha, uint32_t handle)
339{
340 uint16_t cnt;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700341 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 struct mbx_entry *mbxentry;
343
344 mbxentry = NULL;
345
346 if (ha->req_q_cnt < 3) {
347 cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg));
348 if (ha->req_ring_index < cnt)
349 ha->req_q_cnt = cnt - ha->req_ring_index;
350 else
351 ha->req_q_cnt = ha->request_q_length -
352 (ha->req_ring_index - cnt);
353 }
354 if (ha->req_q_cnt >= 3) {
355 mbxentry = (struct mbx_entry *)ha->request_ring_ptr;
356
357 memset(mbxentry, 0, sizeof(struct mbx_entry));
358 mbxentry->entry_type = MBX_IOCB_TYPE;
359 mbxentry->entry_count = 1;
360 mbxentry->sys_define1 = SOURCE_ASYNC_IOCB;
361 mbxentry->handle = handle;
362 }
363 return (mbxentry);
364}
365
366/**
367 * qla2x00_send_abort_iocb() - Issue an abort IOCB to the firmware.
368 * @ha: HA context
369 * @iodesc: io descriptor
370 * @handle_to_abort: firmware handle to abort
371 * @ha_locked: is function called with the hardware lock
372 *
373 * Returns QLA_SUCCESS if the IOCB was issued.
374 */
375static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700376qla2x00_send_abort_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 uint32_t handle_to_abort, int ha_locked)
378{
379 unsigned long flags = 0;
380 struct mbx_entry *mbxentry;
381
382 /* Send marker if required. */
383 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
384 return (QLA_FUNCTION_FAILED);
385
386 if (!ha_locked)
387 spin_lock_irqsave(&ha->hardware_lock, flags);
388
389 /* Build abort mailbox IOCB. */
390 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
391 if (mbxentry == NULL) {
392 if (!ha_locked)
393 spin_unlock_irqrestore(&ha->hardware_lock, flags);
394
395 return (QLA_FUNCTION_FAILED);
396 }
397 mbxentry->mb0 = __constant_cpu_to_le16(MBC_ABORT_COMMAND);
398 mbxentry->mb1 = mbxentry->loop_id.extended =
399 cpu_to_le16(iodesc->remote_fcport->loop_id);
400 mbxentry->mb2 = LSW(handle_to_abort);
401 mbxentry->mb3 = MSW(handle_to_abort);
402 wmb();
403
404 qla2x00_add_iodesc_timer(iodesc);
405
406 /* Issue command to ISP. */
407 qla2x00_isp_cmd(ha);
408
409 if (!ha_locked)
410 spin_unlock_irqrestore(&ha->hardware_lock, flags);
411
412 DEBUG14(printk("scsi(%ld): Sending Abort IOCB (%08x) to [%x], aborting "
413 "%08x.\n", ha->host_no, iodesc->signature,
414 iodesc->remote_fcport->loop_id, handle_to_abort));
415
416 return (QLA_SUCCESS);
417}
418
419/**
420 * qla2x00_send_abort_iocb_cb() - Abort IOCB callback.
421 * @ha: HA context
422 * @iodesc: io descriptor
423 * @mbxstat: mailbox status IOCB
424 *
425 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
426 * will be used for a retry.
427 */
428static int
429qla2x00_send_abort_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
430 struct mbx_entry *mbxstat)
431{
432 DEBUG14(printk("scsi(%ld): Abort IOCB -- sent to [%x/%02x%02x%02x], "
433 "status=%x mb0=%x.\n", ha->host_no, iodesc->remote_fcport->loop_id,
434 iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa,
435 le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
436
437 return (QLA_SUCCESS);
438}
439
440
441/**
442 * qla2x00_send_adisc_iocb() - Issue a Get Port Database IOCB to the firmware.
443 * @ha: HA context
444 * @iodesc: io descriptor
445 * @ha_locked: is function called with the hardware lock
446 *
447 * Returns QLA_SUCCESS if the IOCB was issued.
448 */
449static int
450qla2x00_send_adisc_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
451 int ha_locked)
452{
453 unsigned long flags = 0;
454 struct mbx_entry *mbxentry;
455
456 /* Send marker if required. */
457 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
458 return (QLA_FUNCTION_FAILED);
459
460 if (!ha_locked)
461 spin_lock_irqsave(&ha->hardware_lock, flags);
462
463 /* Build Get Port Database IOCB. */
464 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
465 if (mbxentry == NULL) {
466 if (!ha_locked)
467 spin_unlock_irqrestore(&ha->hardware_lock, flags);
468
469 return (QLA_FUNCTION_FAILED);
470 }
471 mbxentry->mb0 = __constant_cpu_to_le16(MBC_GET_PORT_DATABASE);
472 mbxentry->mb1 = mbxentry->loop_id.extended =
473 cpu_to_le16(iodesc->remote_fcport->loop_id);
474 mbxentry->mb2 = cpu_to_le16(MSW(LSD(ha->iodesc_pd_dma)));
475 mbxentry->mb3 = cpu_to_le16(LSW(LSD(ha->iodesc_pd_dma)));
476 mbxentry->mb6 = cpu_to_le16(MSW(MSD(ha->iodesc_pd_dma)));
477 mbxentry->mb7 = cpu_to_le16(LSW(MSD(ha->iodesc_pd_dma)));
478 mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
479 wmb();
480
481 qla2x00_add_iodesc_timer(iodesc);
482
483 /* Issue command to ISP. */
484 qla2x00_isp_cmd(ha);
485
486 if (!ha_locked)
487 spin_unlock_irqrestore(&ha->hardware_lock, flags);
488
489 DEBUG14(printk("scsi(%ld): Sending Adisc IOCB (%08x) to [%x].\n",
490 ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
491
492 return (QLA_SUCCESS);
493}
494
495/**
496 * qla2x00_send_adisc_iocb_cb() - Get Port Database IOCB callback.
497 * @ha: HA context
498 * @iodesc: io descriptor
499 * @mbxstat: mailbox status IOCB
500 *
501 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
502 * will be used for a retry.
503 */
504static int
505qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
506 struct mbx_entry *mbxstat)
507{
508 fc_port_t *remote_fcport;
509
510 remote_fcport = iodesc->remote_fcport;
511
512 /* Ensure the port IDs are consistent. */
513 if (remote_fcport->d_id.b24 != iodesc->d_id.b24) {
514 DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, remote port "
515 "id changed from [%02x%02x%02x] to [%02x%02x%02x].\n",
516 ha->host_no, remote_fcport->d_id.b.domain,
517 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
518 iodesc->d_id.b.domain, iodesc->d_id.b.area,
519 iodesc->d_id.b.al_pa));
520
521 return (QLA_SUCCESS);
522 }
523
524 /* Only process the last command. */
525 if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
526 DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, sent to "
527 "[%02x%02x%02x], expected %x, received %x.\n", ha->host_no,
528 iodesc->d_id.b.domain, iodesc->d_id.b.area,
529 iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
530 iodesc->idx));
531
532 return (QLA_SUCCESS);
533 }
534
535 if (le16_to_cpu(mbxstat->status) == CS_COMPLETE) {
536 DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
537 "[%x/%02x%02x%02x] online.\n", ha->host_no,
538 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
539 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
540
541 atomic_set(&remote_fcport->state, FCS_ONLINE);
542 } else {
543 DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
544 "[%x/%02x%02x%02x] lost, status=%x mb0=%x.\n", ha->host_no,
545 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
546 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
547 le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
548
549 if (atomic_read(&remote_fcport->state) != FCS_DEVICE_DEAD)
550 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
551 }
552 remote_fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
553
554 return (QLA_SUCCESS);
555}
556
557
558/**
559 * qla2x00_send_logout_iocb() - Issue a fabric port logout IOCB to the firmware.
560 * @ha: HA context
561 * @iodesc: io descriptor
562 * @ha_locked: is function called with the hardware lock
563 *
564 * Returns QLA_SUCCESS if the IOCB was issued.
565 */
566static int
567qla2x00_send_logout_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
568 int ha_locked)
569{
570 unsigned long flags = 0;
571 struct mbx_entry *mbxentry;
572
573 /* Send marker if required. */
574 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
575 return (QLA_FUNCTION_FAILED);
576
577 if (!ha_locked)
578 spin_lock_irqsave(&ha->hardware_lock, flags);
579
580 /* Build fabric port logout mailbox IOCB. */
581 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
582 if (mbxentry == NULL) {
583 if (!ha_locked)
584 spin_unlock_irqrestore(&ha->hardware_lock, flags);
585
586 return (QLA_FUNCTION_FAILED);
587 }
588 mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
589 mbxentry->mb1 = mbxentry->loop_id.extended =
590 cpu_to_le16(iodesc->remote_fcport->loop_id);
591 wmb();
592
593 qla2x00_add_iodesc_timer(iodesc);
594
595 /* Issue command to ISP. */
596 qla2x00_isp_cmd(ha);
597
598 if (!ha_locked)
599 spin_unlock_irqrestore(&ha->hardware_lock, flags);
600
601 DEBUG14(printk("scsi(%ld): Sending Logout IOCB (%08x) to [%x].\n",
602 ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
603
604 return (QLA_SUCCESS);
605}
606
607/**
608 * qla2x00_send_logout_iocb_cb() - Fabric port logout IOCB callback.
609 * @ha: HA context
610 * @iodesc: io descriptor
611 * @mbxstat: mailbox status IOCB
612 *
613 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
614 * will be used for a retry.
615 */
616static int
617qla2x00_send_logout_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
618 struct mbx_entry *mbxstat)
619{
620 DEBUG14(printk("scsi(%ld): Logout IOCB -- sent to [%x/%02x%02x%02x], "
621 "status=%x mb0=%x mb1=%x.\n", ha->host_no,
622 iodesc->remote_fcport->loop_id,
623 iodesc->remote_fcport->d_id.b.domain,
624 iodesc->remote_fcport->d_id.b.area,
625 iodesc->remote_fcport->d_id.b.al_pa, le16_to_cpu(mbxstat->status),
626 le16_to_cpu(mbxstat->mb0), le16_to_cpu(mbxstat->mb1)));
627
628 return (QLA_SUCCESS);
629}
630
631
632/**
633 * qla2x00_send_login_iocb() - Issue a fabric port login IOCB to the firmware.
634 * @ha: HA context
635 * @iodesc: io descriptor
636 * @d_id: port id for device
637 * @ha_locked: is function called with the hardware lock
638 *
639 * Returns QLA_SUCCESS if the IOCB was issued.
640 */
641static int
642qla2x00_send_login_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
643 port_id_t *d_id, int ha_locked)
644{
645 unsigned long flags = 0;
646 struct mbx_entry *mbxentry;
647
648 /* Send marker if required. */
649 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
650 return (QLA_FUNCTION_FAILED);
651
652 if (!ha_locked)
653 spin_lock_irqsave(&ha->hardware_lock, flags);
654
655 /* Build fabric port login mailbox IOCB. */
656 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
657 if (mbxentry == NULL) {
658 if (!ha_locked)
659 spin_unlock_irqrestore(&ha->hardware_lock, flags);
660
661 return (QLA_FUNCTION_FAILED);
662 }
663 mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
664 mbxentry->mb1 = mbxentry->loop_id.extended =
665 cpu_to_le16(iodesc->remote_fcport->loop_id);
666 mbxentry->mb2 = cpu_to_le16(d_id->b.domain);
667 mbxentry->mb3 = cpu_to_le16(d_id->b.area << 8 | d_id->b.al_pa);
668 mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
669 wmb();
670
671 qla2x00_add_iodesc_timer(iodesc);
672
673 /* Issue command to ISP. */
674 qla2x00_isp_cmd(ha);
675
676 if (!ha_locked)
677 spin_unlock_irqrestore(&ha->hardware_lock, flags);
678
679 DEBUG14(printk("scsi(%ld): Sending Login IOCB (%08x) to "
680 "[%x/%02x%02x%02x].\n", ha->host_no, iodesc->signature,
681 iodesc->remote_fcport->loop_id, d_id->b.domain, d_id->b.area,
682 d_id->b.al_pa));
683
684 return (QLA_SUCCESS);
685}
686
687/**
688 * qla2x00_send_login_iocb_cb() - Fabric port logout IOCB callback.
689 * @ha: HA context
690 * @iodesc: io descriptor
691 * @mbxstat: mailbox status IOCB
692 *
693 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
694 * will be used for a retry.
695 */
696static int
697qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
698 struct mbx_entry *mbxstat)
699{
700 int rval;
701 fc_port_t *fcport, *remote_fcport, *exist_fcport;
702 struct io_descriptor *abort_iodesc, *login_iodesc;
703 uint16_t status, mb[8];
704 uint16_t reuse;
705 uint16_t remote_loopid;
706 port_id_t remote_did, inuse_did;
707
708 remote_fcport = iodesc->remote_fcport;
709
710 /* Only process the last command. */
711 if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
712 DEBUG14(printk("scsi(%ld): Login IOCB -- ignoring, sent to "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700713 "[%02x%02x%02x], expected %x, received %x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 ha->host_no, iodesc->d_id.b.domain, iodesc->d_id.b.area,
715 iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
716 iodesc->idx));
717
718 /* Free RSCN fcport resources. */
719 if (remote_fcport->port_type == FCT_RSCN) {
720 DEBUG14(printk("scsi(%ld): Login IOCB -- Freeing RSCN "
721 "fcport %p [%x/%02x%02x%02x] given ignored Login "
722 "IOCB.\n", ha->host_no, remote_fcport,
723 remote_fcport->loop_id,
724 remote_fcport->d_id.b.domain,
725 remote_fcport->d_id.b.area,
726 remote_fcport->d_id.b.al_pa));
727
728 list_del(&remote_fcport->list);
729 kfree(remote_fcport);
730 }
731 return (QLA_SUCCESS);
732 }
733
734 status = le16_to_cpu(mbxstat->status);
735 mb[0] = le16_to_cpu(mbxstat->mb0);
736 mb[1] = le16_to_cpu(mbxstat->mb1);
737 mb[2] = le16_to_cpu(mbxstat->mb2);
738 mb[6] = le16_to_cpu(mbxstat->mb6);
739 mb[7] = le16_to_cpu(mbxstat->mb7);
740
741 /* Good status? */
742 if ((status == CS_COMPLETE || status == CS_COMPLETE_CHKCOND) &&
743 mb[0] == MBS_COMMAND_COMPLETE) {
744
745 DEBUG14(printk("scsi(%ld): Login IOCB -- status=%x mb1=%x pn="
746 "%02x%02x%02x%02x%02x%02x%02x%02x.\n", ha->host_no, status,
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700747 mb[1], mbxstat->port_name[0], mbxstat->port_name[1],
748 mbxstat->port_name[2], mbxstat->port_name[3],
749 mbxstat->port_name[4], mbxstat->port_name[5],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 mbxstat->port_name[6], mbxstat->port_name[7]));
751
752 memcpy(remote_fcport->node_name, mbxstat->node_name, WWN_SIZE);
753 memcpy(remote_fcport->port_name, mbxstat->port_name, WWN_SIZE);
754
755 /* Is the device already in our fcports list? */
756 if (remote_fcport->port_type != FCT_RSCN) {
757 DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
758 "[%x/%02x%02x%02x] online.\n", ha->host_no,
759 remote_fcport->loop_id,
760 remote_fcport->d_id.b.domain,
761 remote_fcport->d_id.b.area,
762 remote_fcport->d_id.b.al_pa));
763
764 qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
765
766 return (QLA_SUCCESS);
767 }
768
769 /* Does the RSCN portname already exist in our fcports list? */
770 exist_fcport = NULL;
771 list_for_each_entry(fcport, &ha->fcports, list) {
772 if (memcmp(remote_fcport->port_name, fcport->port_name,
773 WWN_SIZE) == 0) {
774 exist_fcport = fcport;
775 break;
776 }
777 }
778 if (exist_fcport != NULL) {
779 DEBUG14(printk("scsi(%ld): Login IOCB -- found RSCN "
780 "fcport in fcports list [%p].\n", ha->host_no,
781 exist_fcport));
782
783 /* Abort any ADISC that could have been sent. */
784 if (exist_fcport->iodesc_idx_sent != iodesc->idx &&
785 exist_fcport->iodesc_idx_sent <
786 MAX_IO_DESCRIPTORS &&
787 ha->io_descriptors[exist_fcport->iodesc_idx_sent].
788 cb_idx == ADISC_PORT_IOCB_CB) {
789
790 abort_iodesc = qla2x00_alloc_iodesc(ha);
791 if (abort_iodesc) {
792 DEBUG14(printk("scsi(%ld): Login IOCB "
793 "-- issuing abort to outstanding "
794 "Adisc [%x/%02x%02x%02x].\n",
795 ha->host_no, remote_fcport->loop_id,
796 exist_fcport->d_id.b.domain,
797 exist_fcport->d_id.b.area,
798 exist_fcport->d_id.b.al_pa));
799
800 abort_iodesc->cb_idx = ABORT_IOCB_CB;
801 abort_iodesc->d_id.b24 =
802 exist_fcport->d_id.b24;
803 abort_iodesc->remote_fcport =
804 exist_fcport;
805 exist_fcport->iodesc_idx_sent =
806 abort_iodesc->idx;
807 qla2x00_send_abort_iocb(ha,
808 abort_iodesc, ha->io_descriptors[
809 exist_fcport->iodesc_idx_sent].
810 signature, 1);
811 } else {
812 DEBUG14(printk("scsi(%ld): Login IOCB "
813 "-- unable to abort outstanding "
814 "Adisc [%x/%02x%02x%02x].\n",
815 ha->host_no, remote_fcport->loop_id,
816 exist_fcport->d_id.b.domain,
817 exist_fcport->d_id.b.area,
818 exist_fcport->d_id.b.al_pa));
819 }
820 }
821
822 /*
823 * If the existing fcport is waiting to send an ADISC
824 * or LOGIN, then reuse remote fcport (RSCN) to
825 * continue waiting.
826 */
827 reuse = 0;
828 remote_loopid = remote_fcport->loop_id;
829 remote_did.b24 = remote_fcport->d_id.b24;
830 if (exist_fcport->iodesc_idx_sent ==
831 IODESC_ADISC_NEEDED ||
832 exist_fcport->iodesc_idx_sent ==
833 IODESC_LOGIN_NEEDED) {
834 DEBUG14(printk("scsi(%ld): Login IOCB -- "
835 "existing fcport [%x/%02x%02x%02x] "
836 "waiting for IO descriptor, reuse RSCN "
837 "fcport.\n", ha->host_no,
838 exist_fcport->loop_id,
839 exist_fcport->d_id.b.domain,
840 exist_fcport->d_id.b.area,
841 exist_fcport->d_id.b.al_pa));
842
843 reuse++;
844 remote_fcport->iodesc_idx_sent =
845 exist_fcport->iodesc_idx_sent;
846 exist_fcport->iodesc_idx_sent =
847 IODESC_INVALID_INDEX;
848 remote_fcport->loop_id = exist_fcport->loop_id;
849 remote_fcport->d_id.b24 =
850 exist_fcport->d_id.b24;
851 }
852
853 /* Logout the old loopid. */
854 if (!reuse &&
855 exist_fcport->loop_id != remote_fcport->loop_id &&
856 exist_fcport->loop_id != FC_NO_LOOP_ID) {
857 login_iodesc = qla2x00_alloc_iodesc(ha);
858 if (login_iodesc) {
859 DEBUG14(printk("scsi(%ld): Login IOCB "
860 "-- issuing logout to free old "
861 "loop id [%x/%02x%02x%02x].\n",
862 ha->host_no, exist_fcport->loop_id,
863 exist_fcport->d_id.b.domain,
864 exist_fcport->d_id.b.area,
865 exist_fcport->d_id.b.al_pa));
866
867 login_iodesc->cb_idx =
868 LOGOUT_PORT_IOCB_CB;
869 login_iodesc->d_id.b24 =
870 exist_fcport->d_id.b24;
871 login_iodesc->remote_fcport =
872 exist_fcport;
873 exist_fcport->iodesc_idx_sent =
874 login_iodesc->idx;
875 qla2x00_send_logout_iocb(ha,
876 login_iodesc, 1);
877 } else {
878 /* Ran out of IO descriptiors. */
879 DEBUG14(printk("scsi(%ld): Login IOCB "
880 "-- unable to logout to free old "
881 "loop id [%x/%02x%02x%02x].\n",
882 ha->host_no, exist_fcport->loop_id,
883 exist_fcport->d_id.b.domain,
884 exist_fcport->d_id.b.area,
885 exist_fcport->d_id.b.al_pa));
886
887 exist_fcport->iodesc_idx_sent =
888 IODESC_INVALID_INDEX;
889 }
890
891 }
892
893 /* Update existing fcport with remote fcport info. */
894 DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
895 "existing fcport [%x/%02x%02x%02x] online.\n",
896 ha->host_no, remote_loopid, remote_did.b.domain,
897 remote_did.b.area, remote_did.b.al_pa));
898
899 memcpy(exist_fcport->node_name,
900 remote_fcport->node_name, WWN_SIZE);
901 exist_fcport->loop_id = remote_loopid;
902 exist_fcport->d_id.b24 = remote_did.b24;
903 qla2x00_update_login_fcport(ha, mbxstat, exist_fcport);
904
905 /* Finally, free the remote (RSCN) fcport. */
906 if (!reuse) {
907 DEBUG14(printk("scsi(%ld): Login IOCB -- "
908 "Freeing RSCN fcport %p "
909 "[%x/%02x%02x%02x].\n", ha->host_no,
910 remote_fcport, remote_fcport->loop_id,
911 remote_fcport->d_id.b.domain,
912 remote_fcport->d_id.b.area,
913 remote_fcport->d_id.b.al_pa));
914
915 list_del(&remote_fcport->list);
916 kfree(remote_fcport);
917 }
918
919 return (QLA_SUCCESS);
920 }
921
922 /*
923 * A new device has been added, move the RSCN fcport to our
924 * fcports list.
925 */
926 DEBUG14(printk("scsi(%ld): Login IOCB -- adding RSCN fcport "
927 "[%x/%02x%02x%02x] to fcports list.\n", ha->host_no,
928 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
929 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
930
931 list_del(&remote_fcport->list);
932 remote_fcport->flags = (FCF_RLC_SUPPORT | FCF_RESCAN_NEEDED);
933 qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
934 list_add_tail(&remote_fcport->list, &ha->fcports);
935 set_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags);
936 } else {
937 /* Handle login failure. */
938 if (remote_fcport->login_retry != 0) {
939 if (mb[0] == MBS_LOOP_ID_USED) {
940 inuse_did.b.domain = LSB(mb[1]);
941 inuse_did.b.area = MSB(mb[2]);
942 inuse_did.b.al_pa = LSB(mb[2]);
943
944 DEBUG14(printk("scsi(%ld): Login IOCB -- loop "
945 "id [%x] used by port id [%02x%02x%02x].\n",
946 ha->host_no, remote_fcport->loop_id,
947 inuse_did.b.domain, inuse_did.b.area,
948 inuse_did.b.al_pa));
949
950 if (remote_fcport->d_id.b24 ==
951 INVALID_PORT_ID) {
952 /*
953 * Invalid port id means we are trying
954 * to login to a remote port with just
955 * a loop id without knowing about the
956 * port id. Copy the port id and try
957 * again.
958 */
959 remote_fcport->d_id.b24 = inuse_did.b24;
960 iodesc->d_id.b24 = inuse_did.b24;
961 } else {
962 remote_fcport->loop_id++;
963 rval = qla2x00_find_new_loop_id(ha,
964 remote_fcport);
965 if (rval == QLA_FUNCTION_FAILED) {
966 /* No more loop ids. */
967 return (QLA_SUCCESS);
968 }
969 }
970 } else if (mb[0] == MBS_PORT_ID_USED) {
971 /*
972 * Device has another loop ID. The firmware
973 * group recommends the driver perform an
974 * implicit login with the specified ID.
975 */
976 DEBUG14(printk("scsi(%ld): Login IOCB -- port "
977 "id [%02x%02x%02x] already assigned to "
978 "loop id [%x].\n", ha->host_no,
979 iodesc->d_id.b.domain, iodesc->d_id.b.area,
980 iodesc->d_id.b.al_pa, mb[1]));
981
982 remote_fcport->loop_id = mb[1];
983
984 } else {
985 /* Unable to perform login, try again. */
986 DEBUG14(printk("scsi(%ld): Login IOCB -- "
987 "failed login [%x/%02x%02x%02x], status=%x "
988 "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
989 ha->host_no, remote_fcport->loop_id,
990 iodesc->d_id.b.domain, iodesc->d_id.b.area,
991 iodesc->d_id.b.al_pa, status, mb[0], mb[1],
992 mb[2], mb[6], mb[7]));
993 }
994
995 /* Reissue Login with the same IO descriptor. */
996 iodesc->signature =
997 qla2x00_iodesc_to_handle(iodesc);
998 iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
999 iodesc->d_id.b24 = remote_fcport->d_id.b24;
1000 remote_fcport->iodesc_idx_sent = iodesc->idx;
1001 remote_fcport->login_retry--;
1002
1003 DEBUG14(printk("scsi(%ld): Login IOCB -- retrying "
1004 "login to [%x/%02x%02x%02x] (%d).\n", ha->host_no,
1005 remote_fcport->loop_id,
1006 remote_fcport->d_id.b.domain,
1007 remote_fcport->d_id.b.area,
1008 remote_fcport->d_id.b.al_pa,
1009 remote_fcport->login_retry));
1010
1011 qla2x00_send_login_iocb(ha, iodesc,
1012 &remote_fcport->d_id, 1);
1013
1014 return (QLA_FUNCTION_FAILED);
1015 } else {
1016 /* No more logins, mark device dead. */
1017 DEBUG14(printk("scsi(%ld): Login IOCB -- failed "
1018 "login [%x/%02x%02x%02x] after retries, status=%x "
1019 "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
1020 ha->host_no, remote_fcport->loop_id,
1021 iodesc->d_id.b.domain, iodesc->d_id.b.area,
1022 iodesc->d_id.b.al_pa, status, mb[0], mb[1],
1023 mb[2], mb[6], mb[7]));
1024
1025 atomic_set(&remote_fcport->state, FCS_DEVICE_DEAD);
1026 if (remote_fcport->port_type == FCT_RSCN) {
1027 DEBUG14(printk("scsi(%ld): Login IOCB -- "
1028 "Freeing dead RSCN fcport %p "
1029 "[%x/%02x%02x%02x].\n", ha->host_no,
1030 remote_fcport, remote_fcport->loop_id,
1031 remote_fcport->d_id.b.domain,
1032 remote_fcport->d_id.b.area,
1033 remote_fcport->d_id.b.al_pa));
1034
1035 list_del(&remote_fcport->list);
1036 kfree(remote_fcport);
1037 }
1038 }
1039 }
1040
1041 return (QLA_SUCCESS);
1042}
1043
1044
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001045/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 * IO descriptor processing routines.
1047 **/
1048
1049/**
1050 * qla2x00_alloc_rscn_fcport() - Allocate an RSCN type fcport.
1051 * @ha: HA context
1052 * @flags: allocation flags
1053 *
1054 * Returns a pointer to the allocated RSCN fcport, or NULL, if none available.
1055 */
1056fc_port_t *
Al Viroc53033f2005-10-21 03:22:08 -04001057qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058{
1059 fc_port_t *fcport;
1060
1061 fcport = qla2x00_alloc_fcport(ha, flags);
1062 if (fcport == NULL)
1063 return (fcport);
1064
1065 /* Setup RSCN fcport structure. */
1066 fcport->port_type = FCT_RSCN;
1067
1068 return (fcport);
1069}
1070
1071/**
1072 * qla2x00_handle_port_rscn() - Handle port RSCN.
1073 * @ha: HA context
1074 * @rscn_entry: RSCN entry
1075 * @fcport: fcport entry to updated
1076 *
1077 * Returns QLA_SUCCESS if the port RSCN was handled.
1078 */
1079int
1080qla2x00_handle_port_rscn(scsi_qla_host_t *ha, uint32_t rscn_entry,
1081 fc_port_t *known_fcport, int ha_locked)
1082{
1083 int rval;
1084 port_id_t rscn_pid;
1085 fc_port_t *fcport, *remote_fcport, *rscn_fcport;
1086 struct io_descriptor *iodesc;
1087
1088 remote_fcport = NULL;
1089 rscn_fcport = NULL;
1090
1091 /* Prepare port id based on incoming entries. */
1092 if (known_fcport) {
1093 rscn_pid.b24 = known_fcport->d_id.b24;
1094 remote_fcport = known_fcport;
1095
1096 DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
1097 "fcport [%02x%02x%02x].\n", ha->host_no,
1098 remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area,
1099 remote_fcport->d_id.b.al_pa));
1100 } else {
1101 rscn_pid.b.domain = LSB(MSW(rscn_entry));
1102 rscn_pid.b.area = MSB(LSW(rscn_entry));
1103 rscn_pid.b.al_pa = LSB(LSW(rscn_entry));
1104
1105 DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
1106 "port id [%02x%02x%02x].\n", ha->host_no,
1107 rscn_pid.b.domain, rscn_pid.b.area, rscn_pid.b.al_pa));
1108
1109 /*
1110 * Search fcport lists for a known entry at the specified port
1111 * ID.
1112 */
1113 list_for_each_entry(fcport, &ha->fcports, list) {
1114 if (rscn_pid.b24 == fcport->d_id.b24) {
1115 remote_fcport = fcport;
1116 break;
1117 }
1118 }
1119 list_for_each_entry(fcport, &ha->rscn_fcports, list) {
1120 if (rscn_pid.b24 == fcport->d_id.b24) {
1121 rscn_fcport = fcport;
1122 break;
1123 }
1124 }
1125 if (remote_fcport == NULL)
1126 remote_fcport = rscn_fcport;
1127 }
1128
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001129 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 * If the port is already in our fcport list and online, send an ADISC
1131 * to see if it's still alive. Issue login if a new fcport or the known
1132 * fcport is currently offline.
1133 */
1134 if (remote_fcport) {
1135 /*
1136 * No need to send request if the remote fcport is currently
1137 * waiting for an available io descriptor.
1138 */
1139 if (known_fcport == NULL &&
1140 (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1141 remote_fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED)) {
1142 /*
1143 * If previous waiting io descriptor is an ADISC, then
1144 * the new RSCN may come from a new remote fcport being
1145 * plugged into the same location.
1146 */
1147 if (remote_fcport->port_type == FCT_RSCN) {
1148 remote_fcport->iodesc_idx_sent =
1149 IODESC_LOGIN_NEEDED;
1150 } else if (remote_fcport->iodesc_idx_sent ==
1151 IODESC_ADISC_NEEDED) {
1152 fc_port_t *new_fcport;
1153
1154 remote_fcport->iodesc_idx_sent =
1155 IODESC_INVALID_INDEX;
1156
1157 /* Create new fcport for later login. */
1158 new_fcport = qla2x00_alloc_rscn_fcport(ha,
1159 ha_locked ? GFP_ATOMIC: GFP_KERNEL);
1160 if (new_fcport) {
1161 DEBUG14(printk("scsi(%ld): Handle RSCN "
1162 "-- creating RSCN fcport %p for "
1163 "future login.\n", ha->host_no,
1164 new_fcport));
1165
1166 new_fcport->d_id.b24 =
1167 remote_fcport->d_id.b24;
1168 new_fcport->iodesc_idx_sent =
1169 IODESC_LOGIN_NEEDED;
1170
1171 list_add_tail(&new_fcport->list,
1172 &ha->rscn_fcports);
1173 set_bit(IODESC_PROCESS_NEEDED,
1174 &ha->dpc_flags);
1175 } else {
1176 DEBUG14(printk("scsi(%ld): Handle RSCN "
1177 "-- unable to allocate RSCN fcport "
1178 "for future login.\n",
1179 ha->host_no));
1180 }
1181 }
1182 return (QLA_SUCCESS);
1183 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 /* Send ADISC if the fcport is online */
1186 if (atomic_read(&remote_fcport->state) == FCS_ONLINE ||
1187 remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) {
1188
1189 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
1190
1191 iodesc = qla2x00_alloc_iodesc(ha);
1192 if (iodesc == NULL) {
1193 /* Mark fcport for later adisc processing */
1194 DEBUG14(printk("scsi(%ld): Handle RSCN -- not "
1195 "enough IO descriptors for Adisc, flag "
1196 "for later processing.\n", ha->host_no));
1197
1198 remote_fcport->iodesc_idx_sent =
1199 IODESC_ADISC_NEEDED;
1200 set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1201
1202 return (QLA_SUCCESS);
1203 }
1204
1205 iodesc->cb_idx = ADISC_PORT_IOCB_CB;
1206 iodesc->d_id.b24 = rscn_pid.b24;
1207 iodesc->remote_fcport = remote_fcport;
1208 remote_fcport->iodesc_idx_sent = iodesc->idx;
1209 qla2x00_send_adisc_iocb(ha, iodesc, ha_locked);
1210
1211 return (QLA_SUCCESS);
1212 } else if (remote_fcport->iodesc_idx_sent <
1213 MAX_IO_DESCRIPTORS &&
1214 ha->io_descriptors[remote_fcport->iodesc_idx_sent].cb_idx ==
1215 ADISC_PORT_IOCB_CB) {
1216 /*
1217 * Receiving another RSCN while an ADISC is pending,
1218 * abort the IOCB. Use the same descriptor for the
1219 * abort.
1220 */
1221 uint32_t handle_to_abort;
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001222
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 iodesc = &ha->io_descriptors[
1224 remote_fcport->iodesc_idx_sent];
1225 qla2x00_remove_iodesc_timer(iodesc);
1226 handle_to_abort = iodesc->signature;
1227 iodesc->signature = qla2x00_iodesc_to_handle(iodesc);
1228 iodesc->cb_idx = ABORT_IOCB_CB;
1229 iodesc->d_id.b24 = remote_fcport->d_id.b24;
1230 iodesc->remote_fcport = remote_fcport;
1231 remote_fcport->iodesc_idx_sent = iodesc->idx;
1232
1233 DEBUG14(printk("scsi(%ld): Handle RSCN -- issuing "
1234 "abort to outstanding Adisc [%x/%02x%02x%02x].\n",
1235 ha->host_no, remote_fcport->loop_id,
1236 iodesc->d_id.b.domain, iodesc->d_id.b.area,
1237 iodesc->d_id.b.al_pa));
1238
1239 qla2x00_send_abort_iocb(ha, iodesc, handle_to_abort,
1240 ha_locked);
1241 }
1242 }
1243
1244 /* We need to login to the remote port, find it. */
1245 if (known_fcport) {
1246 remote_fcport = known_fcport;
1247 } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
1248 rscn_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS &&
1249 ha->io_descriptors[rscn_fcport->iodesc_idx_sent].cb_idx ==
1250 LOGIN_PORT_IOCB_CB) {
1251 /*
1252 * Ignore duplicate RSCN on fcport which has already
1253 * initiated a login IOCB.
1254 */
1255 DEBUG14(printk("scsi(%ld): Handle RSCN -- ignoring, login "
1256 "already sent to [%02x%02x%02x].\n", ha->host_no,
1257 rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
1258 rscn_fcport->d_id.b.al_pa));
1259
1260 return (QLA_SUCCESS);
1261 } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
1262 rscn_fcport != remote_fcport) {
1263 /* Reuse same rscn fcport. */
1264 DEBUG14(printk("scsi(%ld): Handle RSCN -- reusing RSCN fcport "
1265 "[%02x%02x%02x].\n", ha->host_no,
1266 rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
1267 rscn_fcport->d_id.b.al_pa));
1268
1269 remote_fcport = rscn_fcport;
1270 } else {
1271 /* Create new fcport for later login. */
1272 remote_fcport = qla2x00_alloc_rscn_fcport(ha,
1273 ha_locked ? GFP_ATOMIC: GFP_KERNEL);
1274 list_add_tail(&remote_fcport->list, &ha->rscn_fcports);
1275 }
1276 if (remote_fcport == NULL)
1277 return (QLA_SUCCESS);
1278
1279 /* Prepare fcport for login. */
1280 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
1281 remote_fcport->login_retry = 3; /* ha->login_retry_count; */
1282 remote_fcport->d_id.b24 = rscn_pid.b24;
1283
1284 iodesc = qla2x00_alloc_iodesc(ha);
1285 if (iodesc == NULL) {
1286 /* Mark fcport for later adisc processing. */
1287 DEBUG14(printk("scsi(%ld): Handle RSCN -- not enough IO "
1288 "descriptors for Login, flag for later processing.\n",
1289 ha->host_no));
1290
1291 remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED;
1292 set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1293
1294 return (QLA_SUCCESS);
1295 }
1296
1297 if (known_fcport == NULL || rscn_pid.b24 != INVALID_PORT_ID) {
1298 remote_fcport->loop_id = ha->min_external_loopid;
1299
1300 rval = qla2x00_find_new_loop_id(ha, remote_fcport);
1301 if (rval == QLA_FUNCTION_FAILED) {
1302 /* No more loop ids, failed. */
1303 DEBUG14(printk("scsi(%ld): Handle RSCN -- no available "
1304 "loop id to perform Login, failed.\n",
1305 ha->host_no));
1306
1307 return (rval);
1308 }
1309 }
1310
1311 iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
1312 iodesc->d_id.b24 = rscn_pid.b24;
1313 iodesc->remote_fcport = remote_fcport;
1314 remote_fcport->iodesc_idx_sent = iodesc->idx;
1315
1316 DEBUG14(printk("scsi(%ld): Handle RSCN -- attempting login to "
1317 "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id,
1318 iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa));
1319
1320 qla2x00_send_login_iocb(ha, iodesc, &rscn_pid, ha_locked);
1321
1322 return (QLA_SUCCESS);
1323}
1324
1325/**
1326 * qla2x00_process_iodesc() - Complete IO descriptor processing.
1327 * @ha: HA context
1328 * @mbxstat: Mailbox IOCB status
1329 */
1330void
1331qla2x00_process_iodesc(scsi_qla_host_t *ha, struct mbx_entry *mbxstat)
1332{
1333 int rval;
1334 uint32_t signature;
1335 fc_port_t *fcport;
1336 struct io_descriptor *iodesc;
1337
1338 signature = mbxstat->handle;
1339
1340 DEBUG14(printk("scsi(%ld): Process IODesc -- processing %08x.\n",
1341 ha->host_no, signature));
1342
1343 /* Retrieve proper IO descriptor. */
1344 iodesc = qla2x00_handle_to_iodesc(ha, signature);
1345 if (iodesc == NULL) {
1346 DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
1347 "incorrect signature %08x.\n", ha->host_no, signature));
1348
1349 return;
1350 }
1351
1352 /* Stop IO descriptor timer. */
1353 qla2x00_remove_iodesc_timer(iodesc);
1354
1355 /* Verify signature match. */
1356 if (iodesc->signature != signature) {
1357 DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
1358 "signature mismatch, sent %08x, received %08x.\n",
1359 ha->host_no, iodesc->signature, signature));
1360
1361 return;
1362 }
1363
1364 /* Go with IOCB callback. */
1365 rval = iocb_function_cb_list[iodesc->cb_idx](ha, iodesc, mbxstat);
1366 if (rval != QLA_SUCCESS) {
1367 /* IO descriptor reused by callback. */
1368 return;
1369 }
1370
1371 qla2x00_free_iodesc(iodesc);
1372
1373 if (test_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags)) {
1374 /* Scan our fcports list for any RSCN requests. */
1375 list_for_each_entry(fcport, &ha->fcports, list) {
1376 if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1377 fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
1378 qla2x00_handle_port_rscn(ha, 0, fcport, 1);
1379 return;
1380 }
1381 }
1382
1383 /* Scan our RSCN fcports list for any RSCN requests. */
1384 list_for_each_entry(fcport, &ha->rscn_fcports, list) {
1385 if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1386 fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
1387 qla2x00_handle_port_rscn(ha, 0, fcport, 1);
1388 return;
1389 }
1390 }
1391 }
1392 clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1393}
1394
1395/**
1396 * qla2x00_cancel_io_descriptors() - Cancel all outstanding io descriptors.
1397 * @ha: HA context
1398 *
1399 * This routine will also delete any RSCN entries related to the outstanding
1400 * IO descriptors.
1401 */
1402void
1403qla2x00_cancel_io_descriptors(scsi_qla_host_t *ha)
1404{
1405 fc_port_t *fcport, *fcptemp;
1406
1407 clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1408
1409 /* Abort all IO descriptors. */
1410 qla2x00_init_io_descriptors(ha);
1411
1412 /* Reset all pending IO descriptors in fcports list. */
1413 list_for_each_entry(fcport, &ha->fcports, list) {
1414 fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
1415 }
1416
1417 /* Reset all pending IO descriptors in rscn fcports list. */
1418 list_for_each_entry_safe(fcport, fcptemp, &ha->rscn_fcports, list) {
1419 DEBUG14(printk("scsi(%ld): Cancel IOs -- Freeing RSCN fcport "
1420 "%p [%x/%02x%02x%02x].\n", ha->host_no, fcport,
1421 fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
1422 fcport->d_id.b.al_pa));
1423
1424 list_del(&fcport->list);
1425 kfree(fcport);
1426 }
1427}