blob: 2c3342108dd82219f311adc9644cd50acbc9a3eb [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);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -0400323 schedule_work(&fcport->rport_add_work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
326
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700327/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 * Mailbox IOCB commands.
329 **/
330
331/**
332 * qla2x00_get_mbx_iocb_entry() - Retrieve an IOCB from the request queue.
333 * @ha: HA context
334 * @handle: handle to io descriptor
335 *
336 * Returns a pointer to the reqest entry, or NULL, if none were available.
337 */
338static inline struct mbx_entry *
339qla2x00_get_mbx_iocb_entry(scsi_qla_host_t *ha, uint32_t handle)
340{
341 uint16_t cnt;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700342 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 struct mbx_entry *mbxentry;
344
345 mbxentry = NULL;
346
347 if (ha->req_q_cnt < 3) {
348 cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg));
349 if (ha->req_ring_index < cnt)
350 ha->req_q_cnt = cnt - ha->req_ring_index;
351 else
352 ha->req_q_cnt = ha->request_q_length -
353 (ha->req_ring_index - cnt);
354 }
355 if (ha->req_q_cnt >= 3) {
356 mbxentry = (struct mbx_entry *)ha->request_ring_ptr;
357
358 memset(mbxentry, 0, sizeof(struct mbx_entry));
359 mbxentry->entry_type = MBX_IOCB_TYPE;
360 mbxentry->entry_count = 1;
361 mbxentry->sys_define1 = SOURCE_ASYNC_IOCB;
362 mbxentry->handle = handle;
363 }
364 return (mbxentry);
365}
366
367/**
368 * qla2x00_send_abort_iocb() - Issue an abort IOCB to the firmware.
369 * @ha: HA context
370 * @iodesc: io descriptor
371 * @handle_to_abort: firmware handle to abort
372 * @ha_locked: is function called with the hardware lock
373 *
374 * Returns QLA_SUCCESS if the IOCB was issued.
375 */
376static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700377qla2x00_send_abort_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 uint32_t handle_to_abort, int ha_locked)
379{
380 unsigned long flags = 0;
381 struct mbx_entry *mbxentry;
382
383 /* Send marker if required. */
384 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
385 return (QLA_FUNCTION_FAILED);
386
387 if (!ha_locked)
388 spin_lock_irqsave(&ha->hardware_lock, flags);
389
390 /* Build abort mailbox IOCB. */
391 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
392 if (mbxentry == NULL) {
393 if (!ha_locked)
394 spin_unlock_irqrestore(&ha->hardware_lock, flags);
395
396 return (QLA_FUNCTION_FAILED);
397 }
398 mbxentry->mb0 = __constant_cpu_to_le16(MBC_ABORT_COMMAND);
399 mbxentry->mb1 = mbxentry->loop_id.extended =
400 cpu_to_le16(iodesc->remote_fcport->loop_id);
401 mbxentry->mb2 = LSW(handle_to_abort);
402 mbxentry->mb3 = MSW(handle_to_abort);
403 wmb();
404
405 qla2x00_add_iodesc_timer(iodesc);
406
407 /* Issue command to ISP. */
408 qla2x00_isp_cmd(ha);
409
410 if (!ha_locked)
411 spin_unlock_irqrestore(&ha->hardware_lock, flags);
412
413 DEBUG14(printk("scsi(%ld): Sending Abort IOCB (%08x) to [%x], aborting "
414 "%08x.\n", ha->host_no, iodesc->signature,
415 iodesc->remote_fcport->loop_id, handle_to_abort));
416
417 return (QLA_SUCCESS);
418}
419
420/**
421 * qla2x00_send_abort_iocb_cb() - Abort IOCB callback.
422 * @ha: HA context
423 * @iodesc: io descriptor
424 * @mbxstat: mailbox status IOCB
425 *
426 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
427 * will be used for a retry.
428 */
429static int
430qla2x00_send_abort_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
431 struct mbx_entry *mbxstat)
432{
433 DEBUG14(printk("scsi(%ld): Abort IOCB -- sent to [%x/%02x%02x%02x], "
434 "status=%x mb0=%x.\n", ha->host_no, iodesc->remote_fcport->loop_id,
435 iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa,
436 le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
437
438 return (QLA_SUCCESS);
439}
440
441
442/**
443 * qla2x00_send_adisc_iocb() - Issue a Get Port Database IOCB to the firmware.
444 * @ha: HA context
445 * @iodesc: io descriptor
446 * @ha_locked: is function called with the hardware lock
447 *
448 * Returns QLA_SUCCESS if the IOCB was issued.
449 */
450static int
451qla2x00_send_adisc_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
452 int ha_locked)
453{
454 unsigned long flags = 0;
455 struct mbx_entry *mbxentry;
456
457 /* Send marker if required. */
458 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
459 return (QLA_FUNCTION_FAILED);
460
461 if (!ha_locked)
462 spin_lock_irqsave(&ha->hardware_lock, flags);
463
464 /* Build Get Port Database IOCB. */
465 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
466 if (mbxentry == NULL) {
467 if (!ha_locked)
468 spin_unlock_irqrestore(&ha->hardware_lock, flags);
469
470 return (QLA_FUNCTION_FAILED);
471 }
472 mbxentry->mb0 = __constant_cpu_to_le16(MBC_GET_PORT_DATABASE);
473 mbxentry->mb1 = mbxentry->loop_id.extended =
474 cpu_to_le16(iodesc->remote_fcport->loop_id);
475 mbxentry->mb2 = cpu_to_le16(MSW(LSD(ha->iodesc_pd_dma)));
476 mbxentry->mb3 = cpu_to_le16(LSW(LSD(ha->iodesc_pd_dma)));
477 mbxentry->mb6 = cpu_to_le16(MSW(MSD(ha->iodesc_pd_dma)));
478 mbxentry->mb7 = cpu_to_le16(LSW(MSD(ha->iodesc_pd_dma)));
479 mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
480 wmb();
481
482 qla2x00_add_iodesc_timer(iodesc);
483
484 /* Issue command to ISP. */
485 qla2x00_isp_cmd(ha);
486
487 if (!ha_locked)
488 spin_unlock_irqrestore(&ha->hardware_lock, flags);
489
490 DEBUG14(printk("scsi(%ld): Sending Adisc IOCB (%08x) to [%x].\n",
491 ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
492
493 return (QLA_SUCCESS);
494}
495
496/**
497 * qla2x00_send_adisc_iocb_cb() - Get Port Database IOCB callback.
498 * @ha: HA context
499 * @iodesc: io descriptor
500 * @mbxstat: mailbox status IOCB
501 *
502 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
503 * will be used for a retry.
504 */
505static int
506qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
507 struct mbx_entry *mbxstat)
508{
509 fc_port_t *remote_fcport;
510
511 remote_fcport = iodesc->remote_fcport;
512
513 /* Ensure the port IDs are consistent. */
514 if (remote_fcport->d_id.b24 != iodesc->d_id.b24) {
515 DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, remote port "
516 "id changed from [%02x%02x%02x] to [%02x%02x%02x].\n",
517 ha->host_no, remote_fcport->d_id.b.domain,
518 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
519 iodesc->d_id.b.domain, iodesc->d_id.b.area,
520 iodesc->d_id.b.al_pa));
521
522 return (QLA_SUCCESS);
523 }
524
525 /* Only process the last command. */
526 if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
527 DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, sent to "
528 "[%02x%02x%02x], expected %x, received %x.\n", ha->host_no,
529 iodesc->d_id.b.domain, iodesc->d_id.b.area,
530 iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
531 iodesc->idx));
532
533 return (QLA_SUCCESS);
534 }
535
536 if (le16_to_cpu(mbxstat->status) == CS_COMPLETE) {
537 DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
538 "[%x/%02x%02x%02x] online.\n", ha->host_no,
539 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
540 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
541
542 atomic_set(&remote_fcport->state, FCS_ONLINE);
543 } else {
544 DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
545 "[%x/%02x%02x%02x] lost, status=%x mb0=%x.\n", ha->host_no,
546 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
547 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
548 le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
549
550 if (atomic_read(&remote_fcport->state) != FCS_DEVICE_DEAD)
551 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
552 }
553 remote_fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
554
555 return (QLA_SUCCESS);
556}
557
558
559/**
560 * qla2x00_send_logout_iocb() - Issue a fabric port logout IOCB to the firmware.
561 * @ha: HA context
562 * @iodesc: io descriptor
563 * @ha_locked: is function called with the hardware lock
564 *
565 * Returns QLA_SUCCESS if the IOCB was issued.
566 */
567static int
568qla2x00_send_logout_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
569 int ha_locked)
570{
571 unsigned long flags = 0;
572 struct mbx_entry *mbxentry;
573
574 /* Send marker if required. */
575 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
576 return (QLA_FUNCTION_FAILED);
577
578 if (!ha_locked)
579 spin_lock_irqsave(&ha->hardware_lock, flags);
580
581 /* Build fabric port logout mailbox IOCB. */
582 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
583 if (mbxentry == NULL) {
584 if (!ha_locked)
585 spin_unlock_irqrestore(&ha->hardware_lock, flags);
586
587 return (QLA_FUNCTION_FAILED);
588 }
589 mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
590 mbxentry->mb1 = mbxentry->loop_id.extended =
591 cpu_to_le16(iodesc->remote_fcport->loop_id);
592 wmb();
593
594 qla2x00_add_iodesc_timer(iodesc);
595
596 /* Issue command to ISP. */
597 qla2x00_isp_cmd(ha);
598
599 if (!ha_locked)
600 spin_unlock_irqrestore(&ha->hardware_lock, flags);
601
602 DEBUG14(printk("scsi(%ld): Sending Logout IOCB (%08x) to [%x].\n",
603 ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
604
605 return (QLA_SUCCESS);
606}
607
608/**
609 * qla2x00_send_logout_iocb_cb() - Fabric port logout IOCB callback.
610 * @ha: HA context
611 * @iodesc: io descriptor
612 * @mbxstat: mailbox status IOCB
613 *
614 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
615 * will be used for a retry.
616 */
617static int
618qla2x00_send_logout_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
619 struct mbx_entry *mbxstat)
620{
621 DEBUG14(printk("scsi(%ld): Logout IOCB -- sent to [%x/%02x%02x%02x], "
622 "status=%x mb0=%x mb1=%x.\n", ha->host_no,
623 iodesc->remote_fcport->loop_id,
624 iodesc->remote_fcport->d_id.b.domain,
625 iodesc->remote_fcport->d_id.b.area,
626 iodesc->remote_fcport->d_id.b.al_pa, le16_to_cpu(mbxstat->status),
627 le16_to_cpu(mbxstat->mb0), le16_to_cpu(mbxstat->mb1)));
628
629 return (QLA_SUCCESS);
630}
631
632
633/**
634 * qla2x00_send_login_iocb() - Issue a fabric port login IOCB to the firmware.
635 * @ha: HA context
636 * @iodesc: io descriptor
637 * @d_id: port id for device
638 * @ha_locked: is function called with the hardware lock
639 *
640 * Returns QLA_SUCCESS if the IOCB was issued.
641 */
642static int
643qla2x00_send_login_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
644 port_id_t *d_id, int ha_locked)
645{
646 unsigned long flags = 0;
647 struct mbx_entry *mbxentry;
648
649 /* Send marker if required. */
650 if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
651 return (QLA_FUNCTION_FAILED);
652
653 if (!ha_locked)
654 spin_lock_irqsave(&ha->hardware_lock, flags);
655
656 /* Build fabric port login mailbox IOCB. */
657 mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
658 if (mbxentry == NULL) {
659 if (!ha_locked)
660 spin_unlock_irqrestore(&ha->hardware_lock, flags);
661
662 return (QLA_FUNCTION_FAILED);
663 }
664 mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
665 mbxentry->mb1 = mbxentry->loop_id.extended =
666 cpu_to_le16(iodesc->remote_fcport->loop_id);
667 mbxentry->mb2 = cpu_to_le16(d_id->b.domain);
668 mbxentry->mb3 = cpu_to_le16(d_id->b.area << 8 | d_id->b.al_pa);
669 mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
670 wmb();
671
672 qla2x00_add_iodesc_timer(iodesc);
673
674 /* Issue command to ISP. */
675 qla2x00_isp_cmd(ha);
676
677 if (!ha_locked)
678 spin_unlock_irqrestore(&ha->hardware_lock, flags);
679
680 DEBUG14(printk("scsi(%ld): Sending Login IOCB (%08x) to "
681 "[%x/%02x%02x%02x].\n", ha->host_no, iodesc->signature,
682 iodesc->remote_fcport->loop_id, d_id->b.domain, d_id->b.area,
683 d_id->b.al_pa));
684
685 return (QLA_SUCCESS);
686}
687
688/**
689 * qla2x00_send_login_iocb_cb() - Fabric port logout IOCB callback.
690 * @ha: HA context
691 * @iodesc: io descriptor
692 * @mbxstat: mailbox status IOCB
693 *
694 * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
695 * will be used for a retry.
696 */
697static int
698qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
699 struct mbx_entry *mbxstat)
700{
701 int rval;
702 fc_port_t *fcport, *remote_fcport, *exist_fcport;
703 struct io_descriptor *abort_iodesc, *login_iodesc;
704 uint16_t status, mb[8];
705 uint16_t reuse;
706 uint16_t remote_loopid;
707 port_id_t remote_did, inuse_did;
708
709 remote_fcport = iodesc->remote_fcport;
710
711 /* Only process the last command. */
712 if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
713 DEBUG14(printk("scsi(%ld): Login IOCB -- ignoring, sent to "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700714 "[%02x%02x%02x], expected %x, received %x.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 ha->host_no, iodesc->d_id.b.domain, iodesc->d_id.b.area,
716 iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
717 iodesc->idx));
718
719 /* Free RSCN fcport resources. */
720 if (remote_fcport->port_type == FCT_RSCN) {
721 DEBUG14(printk("scsi(%ld): Login IOCB -- Freeing RSCN "
722 "fcport %p [%x/%02x%02x%02x] given ignored Login "
723 "IOCB.\n", ha->host_no, remote_fcport,
724 remote_fcport->loop_id,
725 remote_fcport->d_id.b.domain,
726 remote_fcport->d_id.b.area,
727 remote_fcport->d_id.b.al_pa));
728
729 list_del(&remote_fcport->list);
730 kfree(remote_fcport);
731 }
732 return (QLA_SUCCESS);
733 }
734
735 status = le16_to_cpu(mbxstat->status);
736 mb[0] = le16_to_cpu(mbxstat->mb0);
737 mb[1] = le16_to_cpu(mbxstat->mb1);
738 mb[2] = le16_to_cpu(mbxstat->mb2);
739 mb[6] = le16_to_cpu(mbxstat->mb6);
740 mb[7] = le16_to_cpu(mbxstat->mb7);
741
742 /* Good status? */
743 if ((status == CS_COMPLETE || status == CS_COMPLETE_CHKCOND) &&
744 mb[0] == MBS_COMMAND_COMPLETE) {
745
746 DEBUG14(printk("scsi(%ld): Login IOCB -- status=%x mb1=%x pn="
747 "%02x%02x%02x%02x%02x%02x%02x%02x.\n", ha->host_no, status,
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700748 mb[1], mbxstat->port_name[0], mbxstat->port_name[1],
749 mbxstat->port_name[2], mbxstat->port_name[3],
750 mbxstat->port_name[4], mbxstat->port_name[5],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 mbxstat->port_name[6], mbxstat->port_name[7]));
752
753 memcpy(remote_fcport->node_name, mbxstat->node_name, WWN_SIZE);
754 memcpy(remote_fcport->port_name, mbxstat->port_name, WWN_SIZE);
755
756 /* Is the device already in our fcports list? */
757 if (remote_fcport->port_type != FCT_RSCN) {
758 DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
759 "[%x/%02x%02x%02x] online.\n", ha->host_no,
760 remote_fcport->loop_id,
761 remote_fcport->d_id.b.domain,
762 remote_fcport->d_id.b.area,
763 remote_fcport->d_id.b.al_pa));
764
765 qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
766
767 return (QLA_SUCCESS);
768 }
769
770 /* Does the RSCN portname already exist in our fcports list? */
771 exist_fcport = NULL;
772 list_for_each_entry(fcport, &ha->fcports, list) {
773 if (memcmp(remote_fcport->port_name, fcport->port_name,
774 WWN_SIZE) == 0) {
775 exist_fcport = fcport;
776 break;
777 }
778 }
779 if (exist_fcport != NULL) {
780 DEBUG14(printk("scsi(%ld): Login IOCB -- found RSCN "
781 "fcport in fcports list [%p].\n", ha->host_no,
782 exist_fcport));
783
784 /* Abort any ADISC that could have been sent. */
785 if (exist_fcport->iodesc_idx_sent != iodesc->idx &&
786 exist_fcport->iodesc_idx_sent <
787 MAX_IO_DESCRIPTORS &&
788 ha->io_descriptors[exist_fcport->iodesc_idx_sent].
789 cb_idx == ADISC_PORT_IOCB_CB) {
790
791 abort_iodesc = qla2x00_alloc_iodesc(ha);
792 if (abort_iodesc) {
793 DEBUG14(printk("scsi(%ld): Login IOCB "
794 "-- issuing abort to outstanding "
795 "Adisc [%x/%02x%02x%02x].\n",
796 ha->host_no, remote_fcport->loop_id,
797 exist_fcport->d_id.b.domain,
798 exist_fcport->d_id.b.area,
799 exist_fcport->d_id.b.al_pa));
800
801 abort_iodesc->cb_idx = ABORT_IOCB_CB;
802 abort_iodesc->d_id.b24 =
803 exist_fcport->d_id.b24;
804 abort_iodesc->remote_fcport =
805 exist_fcport;
806 exist_fcport->iodesc_idx_sent =
807 abort_iodesc->idx;
808 qla2x00_send_abort_iocb(ha,
809 abort_iodesc, ha->io_descriptors[
810 exist_fcport->iodesc_idx_sent].
811 signature, 1);
812 } else {
813 DEBUG14(printk("scsi(%ld): Login IOCB "
814 "-- unable to abort outstanding "
815 "Adisc [%x/%02x%02x%02x].\n",
816 ha->host_no, remote_fcport->loop_id,
817 exist_fcport->d_id.b.domain,
818 exist_fcport->d_id.b.area,
819 exist_fcport->d_id.b.al_pa));
820 }
821 }
822
823 /*
824 * If the existing fcport is waiting to send an ADISC
825 * or LOGIN, then reuse remote fcport (RSCN) to
826 * continue waiting.
827 */
828 reuse = 0;
829 remote_loopid = remote_fcport->loop_id;
830 remote_did.b24 = remote_fcport->d_id.b24;
831 if (exist_fcport->iodesc_idx_sent ==
832 IODESC_ADISC_NEEDED ||
833 exist_fcport->iodesc_idx_sent ==
834 IODESC_LOGIN_NEEDED) {
835 DEBUG14(printk("scsi(%ld): Login IOCB -- "
836 "existing fcport [%x/%02x%02x%02x] "
837 "waiting for IO descriptor, reuse RSCN "
838 "fcport.\n", ha->host_no,
839 exist_fcport->loop_id,
840 exist_fcport->d_id.b.domain,
841 exist_fcport->d_id.b.area,
842 exist_fcport->d_id.b.al_pa));
843
844 reuse++;
845 remote_fcport->iodesc_idx_sent =
846 exist_fcport->iodesc_idx_sent;
847 exist_fcport->iodesc_idx_sent =
848 IODESC_INVALID_INDEX;
849 remote_fcport->loop_id = exist_fcport->loop_id;
850 remote_fcport->d_id.b24 =
851 exist_fcport->d_id.b24;
852 }
853
854 /* Logout the old loopid. */
855 if (!reuse &&
856 exist_fcport->loop_id != remote_fcport->loop_id &&
857 exist_fcport->loop_id != FC_NO_LOOP_ID) {
858 login_iodesc = qla2x00_alloc_iodesc(ha);
859 if (login_iodesc) {
860 DEBUG14(printk("scsi(%ld): Login IOCB "
861 "-- issuing logout to free old "
862 "loop id [%x/%02x%02x%02x].\n",
863 ha->host_no, exist_fcport->loop_id,
864 exist_fcport->d_id.b.domain,
865 exist_fcport->d_id.b.area,
866 exist_fcport->d_id.b.al_pa));
867
868 login_iodesc->cb_idx =
869 LOGOUT_PORT_IOCB_CB;
870 login_iodesc->d_id.b24 =
871 exist_fcport->d_id.b24;
872 login_iodesc->remote_fcport =
873 exist_fcport;
874 exist_fcport->iodesc_idx_sent =
875 login_iodesc->idx;
876 qla2x00_send_logout_iocb(ha,
877 login_iodesc, 1);
878 } else {
879 /* Ran out of IO descriptiors. */
880 DEBUG14(printk("scsi(%ld): Login IOCB "
881 "-- unable to logout to free old "
882 "loop id [%x/%02x%02x%02x].\n",
883 ha->host_no, exist_fcport->loop_id,
884 exist_fcport->d_id.b.domain,
885 exist_fcport->d_id.b.area,
886 exist_fcport->d_id.b.al_pa));
887
888 exist_fcport->iodesc_idx_sent =
889 IODESC_INVALID_INDEX;
890 }
891
892 }
893
894 /* Update existing fcport with remote fcport info. */
895 DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
896 "existing fcport [%x/%02x%02x%02x] online.\n",
897 ha->host_no, remote_loopid, remote_did.b.domain,
898 remote_did.b.area, remote_did.b.al_pa));
899
900 memcpy(exist_fcport->node_name,
901 remote_fcport->node_name, WWN_SIZE);
902 exist_fcport->loop_id = remote_loopid;
903 exist_fcport->d_id.b24 = remote_did.b24;
904 qla2x00_update_login_fcport(ha, mbxstat, exist_fcport);
905
906 /* Finally, free the remote (RSCN) fcport. */
907 if (!reuse) {
908 DEBUG14(printk("scsi(%ld): Login IOCB -- "
909 "Freeing RSCN fcport %p "
910 "[%x/%02x%02x%02x].\n", ha->host_no,
911 remote_fcport, remote_fcport->loop_id,
912 remote_fcport->d_id.b.domain,
913 remote_fcport->d_id.b.area,
914 remote_fcport->d_id.b.al_pa));
915
916 list_del(&remote_fcport->list);
917 kfree(remote_fcport);
918 }
919
920 return (QLA_SUCCESS);
921 }
922
923 /*
924 * A new device has been added, move the RSCN fcport to our
925 * fcports list.
926 */
927 DEBUG14(printk("scsi(%ld): Login IOCB -- adding RSCN fcport "
928 "[%x/%02x%02x%02x] to fcports list.\n", ha->host_no,
929 remote_fcport->loop_id, remote_fcport->d_id.b.domain,
930 remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
931
932 list_del(&remote_fcport->list);
933 remote_fcport->flags = (FCF_RLC_SUPPORT | FCF_RESCAN_NEEDED);
934 qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
935 list_add_tail(&remote_fcport->list, &ha->fcports);
936 set_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags);
937 } else {
938 /* Handle login failure. */
939 if (remote_fcport->login_retry != 0) {
940 if (mb[0] == MBS_LOOP_ID_USED) {
941 inuse_did.b.domain = LSB(mb[1]);
942 inuse_did.b.area = MSB(mb[2]);
943 inuse_did.b.al_pa = LSB(mb[2]);
944
945 DEBUG14(printk("scsi(%ld): Login IOCB -- loop "
946 "id [%x] used by port id [%02x%02x%02x].\n",
947 ha->host_no, remote_fcport->loop_id,
948 inuse_did.b.domain, inuse_did.b.area,
949 inuse_did.b.al_pa));
950
951 if (remote_fcport->d_id.b24 ==
952 INVALID_PORT_ID) {
953 /*
954 * Invalid port id means we are trying
955 * to login to a remote port with just
956 * a loop id without knowing about the
957 * port id. Copy the port id and try
958 * again.
959 */
960 remote_fcport->d_id.b24 = inuse_did.b24;
961 iodesc->d_id.b24 = inuse_did.b24;
962 } else {
963 remote_fcport->loop_id++;
964 rval = qla2x00_find_new_loop_id(ha,
965 remote_fcport);
966 if (rval == QLA_FUNCTION_FAILED) {
967 /* No more loop ids. */
968 return (QLA_SUCCESS);
969 }
970 }
971 } else if (mb[0] == MBS_PORT_ID_USED) {
972 /*
973 * Device has another loop ID. The firmware
974 * group recommends the driver perform an
975 * implicit login with the specified ID.
976 */
977 DEBUG14(printk("scsi(%ld): Login IOCB -- port "
978 "id [%02x%02x%02x] already assigned to "
979 "loop id [%x].\n", ha->host_no,
980 iodesc->d_id.b.domain, iodesc->d_id.b.area,
981 iodesc->d_id.b.al_pa, mb[1]));
982
983 remote_fcport->loop_id = mb[1];
984
985 } else {
986 /* Unable to perform login, try again. */
987 DEBUG14(printk("scsi(%ld): Login IOCB -- "
988 "failed login [%x/%02x%02x%02x], status=%x "
989 "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
990 ha->host_no, remote_fcport->loop_id,
991 iodesc->d_id.b.domain, iodesc->d_id.b.area,
992 iodesc->d_id.b.al_pa, status, mb[0], mb[1],
993 mb[2], mb[6], mb[7]));
994 }
995
996 /* Reissue Login with the same IO descriptor. */
997 iodesc->signature =
998 qla2x00_iodesc_to_handle(iodesc);
999 iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
1000 iodesc->d_id.b24 = remote_fcport->d_id.b24;
1001 remote_fcport->iodesc_idx_sent = iodesc->idx;
1002 remote_fcport->login_retry--;
1003
1004 DEBUG14(printk("scsi(%ld): Login IOCB -- retrying "
1005 "login to [%x/%02x%02x%02x] (%d).\n", ha->host_no,
1006 remote_fcport->loop_id,
1007 remote_fcport->d_id.b.domain,
1008 remote_fcport->d_id.b.area,
1009 remote_fcport->d_id.b.al_pa,
1010 remote_fcport->login_retry));
1011
1012 qla2x00_send_login_iocb(ha, iodesc,
1013 &remote_fcport->d_id, 1);
1014
1015 return (QLA_FUNCTION_FAILED);
1016 } else {
1017 /* No more logins, mark device dead. */
1018 DEBUG14(printk("scsi(%ld): Login IOCB -- failed "
1019 "login [%x/%02x%02x%02x] after retries, status=%x "
1020 "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
1021 ha->host_no, remote_fcport->loop_id,
1022 iodesc->d_id.b.domain, iodesc->d_id.b.area,
1023 iodesc->d_id.b.al_pa, status, mb[0], mb[1],
1024 mb[2], mb[6], mb[7]));
1025
1026 atomic_set(&remote_fcport->state, FCS_DEVICE_DEAD);
1027 if (remote_fcport->port_type == FCT_RSCN) {
1028 DEBUG14(printk("scsi(%ld): Login IOCB -- "
1029 "Freeing dead RSCN fcport %p "
1030 "[%x/%02x%02x%02x].\n", ha->host_no,
1031 remote_fcport, remote_fcport->loop_id,
1032 remote_fcport->d_id.b.domain,
1033 remote_fcport->d_id.b.area,
1034 remote_fcport->d_id.b.al_pa));
1035
1036 list_del(&remote_fcport->list);
1037 kfree(remote_fcport);
1038 }
1039 }
1040 }
1041
1042 return (QLA_SUCCESS);
1043}
1044
1045
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001046/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 * IO descriptor processing routines.
1048 **/
1049
1050/**
1051 * qla2x00_alloc_rscn_fcport() - Allocate an RSCN type fcport.
1052 * @ha: HA context
1053 * @flags: allocation flags
1054 *
1055 * Returns a pointer to the allocated RSCN fcport, or NULL, if none available.
1056 */
1057fc_port_t *
Al Viroc53033f2005-10-21 03:22:08 -04001058qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
1060 fc_port_t *fcport;
1061
1062 fcport = qla2x00_alloc_fcport(ha, flags);
1063 if (fcport == NULL)
1064 return (fcport);
1065
1066 /* Setup RSCN fcport structure. */
1067 fcport->port_type = FCT_RSCN;
1068
1069 return (fcport);
1070}
1071
1072/**
1073 * qla2x00_handle_port_rscn() - Handle port RSCN.
1074 * @ha: HA context
1075 * @rscn_entry: RSCN entry
1076 * @fcport: fcport entry to updated
1077 *
1078 * Returns QLA_SUCCESS if the port RSCN was handled.
1079 */
1080int
1081qla2x00_handle_port_rscn(scsi_qla_host_t *ha, uint32_t rscn_entry,
1082 fc_port_t *known_fcport, int ha_locked)
1083{
1084 int rval;
1085 port_id_t rscn_pid;
1086 fc_port_t *fcport, *remote_fcport, *rscn_fcport;
1087 struct io_descriptor *iodesc;
1088
1089 remote_fcport = NULL;
1090 rscn_fcport = NULL;
1091
1092 /* Prepare port id based on incoming entries. */
1093 if (known_fcport) {
1094 rscn_pid.b24 = known_fcport->d_id.b24;
1095 remote_fcport = known_fcport;
1096
1097 DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
1098 "fcport [%02x%02x%02x].\n", ha->host_no,
1099 remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area,
1100 remote_fcport->d_id.b.al_pa));
1101 } else {
1102 rscn_pid.b.domain = LSB(MSW(rscn_entry));
1103 rscn_pid.b.area = MSB(LSW(rscn_entry));
1104 rscn_pid.b.al_pa = LSB(LSW(rscn_entry));
1105
1106 DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
1107 "port id [%02x%02x%02x].\n", ha->host_no,
1108 rscn_pid.b.domain, rscn_pid.b.area, rscn_pid.b.al_pa));
1109
1110 /*
1111 * Search fcport lists for a known entry at the specified port
1112 * ID.
1113 */
1114 list_for_each_entry(fcport, &ha->fcports, list) {
1115 if (rscn_pid.b24 == fcport->d_id.b24) {
1116 remote_fcport = fcport;
1117 break;
1118 }
1119 }
1120 list_for_each_entry(fcport, &ha->rscn_fcports, list) {
1121 if (rscn_pid.b24 == fcport->d_id.b24) {
1122 rscn_fcport = fcport;
1123 break;
1124 }
1125 }
1126 if (remote_fcport == NULL)
1127 remote_fcport = rscn_fcport;
1128 }
1129
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001130 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 * If the port is already in our fcport list and online, send an ADISC
1132 * to see if it's still alive. Issue login if a new fcport or the known
1133 * fcport is currently offline.
1134 */
1135 if (remote_fcport) {
1136 /*
1137 * No need to send request if the remote fcport is currently
1138 * waiting for an available io descriptor.
1139 */
1140 if (known_fcport == NULL &&
1141 (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1142 remote_fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED)) {
1143 /*
1144 * If previous waiting io descriptor is an ADISC, then
1145 * the new RSCN may come from a new remote fcport being
1146 * plugged into the same location.
1147 */
1148 if (remote_fcport->port_type == FCT_RSCN) {
1149 remote_fcport->iodesc_idx_sent =
1150 IODESC_LOGIN_NEEDED;
1151 } else if (remote_fcport->iodesc_idx_sent ==
1152 IODESC_ADISC_NEEDED) {
1153 fc_port_t *new_fcport;
1154
1155 remote_fcport->iodesc_idx_sent =
1156 IODESC_INVALID_INDEX;
1157
1158 /* Create new fcport for later login. */
1159 new_fcport = qla2x00_alloc_rscn_fcport(ha,
1160 ha_locked ? GFP_ATOMIC: GFP_KERNEL);
1161 if (new_fcport) {
1162 DEBUG14(printk("scsi(%ld): Handle RSCN "
1163 "-- creating RSCN fcport %p for "
1164 "future login.\n", ha->host_no,
1165 new_fcport));
1166
1167 new_fcport->d_id.b24 =
1168 remote_fcport->d_id.b24;
1169 new_fcport->iodesc_idx_sent =
1170 IODESC_LOGIN_NEEDED;
1171
1172 list_add_tail(&new_fcport->list,
1173 &ha->rscn_fcports);
1174 set_bit(IODESC_PROCESS_NEEDED,
1175 &ha->dpc_flags);
1176 } else {
1177 DEBUG14(printk("scsi(%ld): Handle RSCN "
1178 "-- unable to allocate RSCN fcport "
1179 "for future login.\n",
1180 ha->host_no));
1181 }
1182 }
1183 return (QLA_SUCCESS);
1184 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 /* Send ADISC if the fcport is online */
1187 if (atomic_read(&remote_fcport->state) == FCS_ONLINE ||
1188 remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) {
1189
1190 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
1191
1192 iodesc = qla2x00_alloc_iodesc(ha);
1193 if (iodesc == NULL) {
1194 /* Mark fcport for later adisc processing */
1195 DEBUG14(printk("scsi(%ld): Handle RSCN -- not "
1196 "enough IO descriptors for Adisc, flag "
1197 "for later processing.\n", ha->host_no));
1198
1199 remote_fcport->iodesc_idx_sent =
1200 IODESC_ADISC_NEEDED;
1201 set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1202
1203 return (QLA_SUCCESS);
1204 }
1205
1206 iodesc->cb_idx = ADISC_PORT_IOCB_CB;
1207 iodesc->d_id.b24 = rscn_pid.b24;
1208 iodesc->remote_fcport = remote_fcport;
1209 remote_fcport->iodesc_idx_sent = iodesc->idx;
1210 qla2x00_send_adisc_iocb(ha, iodesc, ha_locked);
1211
1212 return (QLA_SUCCESS);
1213 } else if (remote_fcport->iodesc_idx_sent <
1214 MAX_IO_DESCRIPTORS &&
1215 ha->io_descriptors[remote_fcport->iodesc_idx_sent].cb_idx ==
1216 ADISC_PORT_IOCB_CB) {
1217 /*
1218 * Receiving another RSCN while an ADISC is pending,
1219 * abort the IOCB. Use the same descriptor for the
1220 * abort.
1221 */
1222 uint32_t handle_to_abort;
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001223
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 iodesc = &ha->io_descriptors[
1225 remote_fcport->iodesc_idx_sent];
1226 qla2x00_remove_iodesc_timer(iodesc);
1227 handle_to_abort = iodesc->signature;
1228 iodesc->signature = qla2x00_iodesc_to_handle(iodesc);
1229 iodesc->cb_idx = ABORT_IOCB_CB;
1230 iodesc->d_id.b24 = remote_fcport->d_id.b24;
1231 iodesc->remote_fcport = remote_fcport;
1232 remote_fcport->iodesc_idx_sent = iodesc->idx;
1233
1234 DEBUG14(printk("scsi(%ld): Handle RSCN -- issuing "
1235 "abort to outstanding Adisc [%x/%02x%02x%02x].\n",
1236 ha->host_no, remote_fcport->loop_id,
1237 iodesc->d_id.b.domain, iodesc->d_id.b.area,
1238 iodesc->d_id.b.al_pa));
1239
1240 qla2x00_send_abort_iocb(ha, iodesc, handle_to_abort,
1241 ha_locked);
1242 }
1243 }
1244
1245 /* We need to login to the remote port, find it. */
1246 if (known_fcport) {
1247 remote_fcport = known_fcport;
1248 } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
1249 rscn_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS &&
1250 ha->io_descriptors[rscn_fcport->iodesc_idx_sent].cb_idx ==
1251 LOGIN_PORT_IOCB_CB) {
1252 /*
1253 * Ignore duplicate RSCN on fcport which has already
1254 * initiated a login IOCB.
1255 */
1256 DEBUG14(printk("scsi(%ld): Handle RSCN -- ignoring, login "
1257 "already sent to [%02x%02x%02x].\n", ha->host_no,
1258 rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
1259 rscn_fcport->d_id.b.al_pa));
1260
1261 return (QLA_SUCCESS);
1262 } else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
1263 rscn_fcport != remote_fcport) {
1264 /* Reuse same rscn fcport. */
1265 DEBUG14(printk("scsi(%ld): Handle RSCN -- reusing RSCN fcport "
1266 "[%02x%02x%02x].\n", ha->host_no,
1267 rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
1268 rscn_fcport->d_id.b.al_pa));
1269
1270 remote_fcport = rscn_fcport;
1271 } else {
1272 /* Create new fcport for later login. */
1273 remote_fcport = qla2x00_alloc_rscn_fcport(ha,
1274 ha_locked ? GFP_ATOMIC: GFP_KERNEL);
1275 list_add_tail(&remote_fcport->list, &ha->rscn_fcports);
1276 }
1277 if (remote_fcport == NULL)
1278 return (QLA_SUCCESS);
1279
1280 /* Prepare fcport for login. */
1281 atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
1282 remote_fcport->login_retry = 3; /* ha->login_retry_count; */
1283 remote_fcport->d_id.b24 = rscn_pid.b24;
1284
1285 iodesc = qla2x00_alloc_iodesc(ha);
1286 if (iodesc == NULL) {
1287 /* Mark fcport for later adisc processing. */
1288 DEBUG14(printk("scsi(%ld): Handle RSCN -- not enough IO "
1289 "descriptors for Login, flag for later processing.\n",
1290 ha->host_no));
1291
1292 remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED;
1293 set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1294
1295 return (QLA_SUCCESS);
1296 }
1297
1298 if (known_fcport == NULL || rscn_pid.b24 != INVALID_PORT_ID) {
1299 remote_fcport->loop_id = ha->min_external_loopid;
1300
1301 rval = qla2x00_find_new_loop_id(ha, remote_fcport);
1302 if (rval == QLA_FUNCTION_FAILED) {
1303 /* No more loop ids, failed. */
1304 DEBUG14(printk("scsi(%ld): Handle RSCN -- no available "
1305 "loop id to perform Login, failed.\n",
1306 ha->host_no));
1307
1308 return (rval);
1309 }
1310 }
1311
1312 iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
1313 iodesc->d_id.b24 = rscn_pid.b24;
1314 iodesc->remote_fcport = remote_fcport;
1315 remote_fcport->iodesc_idx_sent = iodesc->idx;
1316
1317 DEBUG14(printk("scsi(%ld): Handle RSCN -- attempting login to "
1318 "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id,
1319 iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa));
1320
1321 qla2x00_send_login_iocb(ha, iodesc, &rscn_pid, ha_locked);
1322
1323 return (QLA_SUCCESS);
1324}
1325
1326/**
1327 * qla2x00_process_iodesc() - Complete IO descriptor processing.
1328 * @ha: HA context
1329 * @mbxstat: Mailbox IOCB status
1330 */
1331void
1332qla2x00_process_iodesc(scsi_qla_host_t *ha, struct mbx_entry *mbxstat)
1333{
1334 int rval;
1335 uint32_t signature;
1336 fc_port_t *fcport;
1337 struct io_descriptor *iodesc;
1338
1339 signature = mbxstat->handle;
1340
1341 DEBUG14(printk("scsi(%ld): Process IODesc -- processing %08x.\n",
1342 ha->host_no, signature));
1343
1344 /* Retrieve proper IO descriptor. */
1345 iodesc = qla2x00_handle_to_iodesc(ha, signature);
1346 if (iodesc == NULL) {
1347 DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
1348 "incorrect signature %08x.\n", ha->host_no, signature));
1349
1350 return;
1351 }
1352
1353 /* Stop IO descriptor timer. */
1354 qla2x00_remove_iodesc_timer(iodesc);
1355
1356 /* Verify signature match. */
1357 if (iodesc->signature != signature) {
1358 DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
1359 "signature mismatch, sent %08x, received %08x.\n",
1360 ha->host_no, iodesc->signature, signature));
1361
1362 return;
1363 }
1364
1365 /* Go with IOCB callback. */
1366 rval = iocb_function_cb_list[iodesc->cb_idx](ha, iodesc, mbxstat);
1367 if (rval != QLA_SUCCESS) {
1368 /* IO descriptor reused by callback. */
1369 return;
1370 }
1371
1372 qla2x00_free_iodesc(iodesc);
1373
1374 if (test_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags)) {
1375 /* Scan our fcports list for any RSCN requests. */
1376 list_for_each_entry(fcport, &ha->fcports, list) {
1377 if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1378 fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
1379 qla2x00_handle_port_rscn(ha, 0, fcport, 1);
1380 return;
1381 }
1382 }
1383
1384 /* Scan our RSCN fcports list for any RSCN requests. */
1385 list_for_each_entry(fcport, &ha->rscn_fcports, list) {
1386 if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
1387 fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
1388 qla2x00_handle_port_rscn(ha, 0, fcport, 1);
1389 return;
1390 }
1391 }
1392 }
1393 clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1394}
1395
1396/**
1397 * qla2x00_cancel_io_descriptors() - Cancel all outstanding io descriptors.
1398 * @ha: HA context
1399 *
1400 * This routine will also delete any RSCN entries related to the outstanding
1401 * IO descriptors.
1402 */
1403void
1404qla2x00_cancel_io_descriptors(scsi_qla_host_t *ha)
1405{
1406 fc_port_t *fcport, *fcptemp;
1407
1408 clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
1409
1410 /* Abort all IO descriptors. */
1411 qla2x00_init_io_descriptors(ha);
1412
1413 /* Reset all pending IO descriptors in fcports list. */
1414 list_for_each_entry(fcport, &ha->fcports, list) {
1415 fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
1416 }
1417
1418 /* Reset all pending IO descriptors in rscn fcports list. */
1419 list_for_each_entry_safe(fcport, fcptemp, &ha->rscn_fcports, list) {
1420 DEBUG14(printk("scsi(%ld): Cancel IOs -- Freeing RSCN fcport "
1421 "%p [%x/%02x%02x%02x].\n", ha->host_no, fcport,
1422 fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
1423 fcport->d_id.b.al_pa));
1424
1425 list_del(&fcport->list);
1426 kfree(fcport);
1427 }
1428}