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