Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[pandora-kernel.git] / drivers / scsi / bfa / bfad_im.c
1 /*
2  * Copyright (c) 2005-2010 Brocade Communications Systems, Inc.
3  * All rights reserved
4  * www.brocade.com
5  *
6  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License (GPL) Version 2 as
10  * published by the Free Software Foundation
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  */
17
18 /*
19  *  bfad_im.c Linux driver IM module.
20  */
21
22 #include "bfad_drv.h"
23 #include "bfad_im.h"
24 #include "bfa_cb_ioim.h"
25 #include "bfa_fcs.h"
26
27 BFA_TRC_FILE(LDRV, IM);
28
29 DEFINE_IDR(bfad_im_port_index);
30 struct scsi_transport_template *bfad_im_scsi_transport_template;
31 struct scsi_transport_template *bfad_im_scsi_vport_transport_template;
32 static void bfad_im_itnim_work_handler(struct work_struct *work);
33 static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
34                                 void (*done)(struct scsi_cmnd *));
35 static int bfad_im_slave_alloc(struct scsi_device *sdev);
36 static void bfad_im_fc_rport_add(struct bfad_im_port_s  *im_port,
37                                 struct bfad_itnim_s *itnim);
38
39 void
40 bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
41                         enum bfi_ioim_status io_status, u8 scsi_status,
42                         int sns_len, u8 *sns_info, s32 residue)
43 {
44         struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
45         struct bfad_s         *bfad = drv;
46         struct bfad_itnim_data_s *itnim_data;
47         struct bfad_itnim_s *itnim;
48         u8         host_status = DID_OK;
49
50         switch (io_status) {
51         case BFI_IOIM_STS_OK:
52                 bfa_trc(bfad, scsi_status);
53                 scsi_set_resid(cmnd, 0);
54
55                 if (sns_len > 0) {
56                         bfa_trc(bfad, sns_len);
57                         if (sns_len > SCSI_SENSE_BUFFERSIZE)
58                                 sns_len = SCSI_SENSE_BUFFERSIZE;
59                         memcpy(cmnd->sense_buffer, sns_info, sns_len);
60                 }
61
62                 if (residue > 0) {
63                         bfa_trc(bfad, residue);
64                         scsi_set_resid(cmnd, residue);
65                         if (!sns_len && (scsi_status == SAM_STAT_GOOD) &&
66                                 (scsi_bufflen(cmnd) - residue) <
67                                         cmnd->underflow) {
68                                 bfa_trc(bfad, 0);
69                                 host_status = DID_ERROR;
70                         }
71                 }
72                 cmnd->result = ScsiResult(host_status, scsi_status);
73
74                 break;
75
76         case BFI_IOIM_STS_ABORTED:
77         case BFI_IOIM_STS_TIMEDOUT:
78         case BFI_IOIM_STS_PATHTOV:
79         default:
80                 host_status = DID_ERROR;
81                 cmnd->result = ScsiResult(host_status, 0);
82         }
83
84         /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
85         if (cmnd->device->host != NULL)
86                 scsi_dma_unmap(cmnd);
87
88         cmnd->host_scribble = NULL;
89         bfa_trc(bfad, cmnd->result);
90
91         itnim_data = cmnd->device->hostdata;
92         if (itnim_data) {
93                 itnim = itnim_data->itnim;
94                 if (!cmnd->result && itnim &&
95                          (bfa_lun_queue_depth > cmnd->device->queue_depth)) {
96                         /* Queue depth adjustment for good status completion */
97                         bfad_os_ramp_up_qdepth(itnim, cmnd->device);
98                 } else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) {
99                         /* qfull handling */
100                         bfad_os_handle_qfull(itnim, cmnd->device);
101                 }
102         }
103
104         cmnd->scsi_done(cmnd);
105 }
106
107 void
108 bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio)
109 {
110         struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
111         struct bfad_itnim_data_s *itnim_data;
112         struct bfad_itnim_s *itnim;
113
114         cmnd->result = ScsiResult(DID_OK, SCSI_STATUS_GOOD);
115
116         /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
117         if (cmnd->device->host != NULL)
118                 scsi_dma_unmap(cmnd);
119
120         cmnd->host_scribble = NULL;
121
122         /* Queue depth adjustment */
123         if (bfa_lun_queue_depth > cmnd->device->queue_depth) {
124                 itnim_data = cmnd->device->hostdata;
125                 if (itnim_data) {
126                         itnim = itnim_data->itnim;
127                         if (itnim)
128                                 bfad_os_ramp_up_qdepth(itnim, cmnd->device);
129                 }
130         }
131
132         cmnd->scsi_done(cmnd);
133 }
134
135 void
136 bfa_cb_ioim_abort(void *drv, struct bfad_ioim_s *dio)
137 {
138         struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
139         struct bfad_s         *bfad = drv;
140
141         cmnd->result = ScsiResult(DID_ERROR, 0);
142
143         /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
144         if (cmnd->device->host != NULL)
145                 scsi_dma_unmap(cmnd);
146
147         bfa_trc(bfad, cmnd->result);
148         cmnd->host_scribble = NULL;
149 }
150
151 void
152 bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
153                    enum bfi_tskim_status tsk_status)
154 {
155         struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dtsk;
156         wait_queue_head_t *wq;
157
158         cmnd->SCp.Status |= tsk_status << 1;
159         set_bit(IO_DONE_BIT, (unsigned long *)&cmnd->SCp.Status);
160         wq = (wait_queue_head_t *) cmnd->SCp.ptr;
161         cmnd->SCp.ptr = NULL;
162
163         if (wq)
164                 wake_up(wq);
165 }
166
167 /*
168  *  Scsi_Host_template SCSI host template
169  */
170 /*
171  * Scsi_Host template entry, returns BFAD PCI info.
172  */
173 static const char *
174 bfad_im_info(struct Scsi_Host *shost)
175 {
176         static char     bfa_buf[256];
177         struct bfad_im_port_s *im_port =
178                         (struct bfad_im_port_s *) shost->hostdata[0];
179         struct bfad_s *bfad = im_port->bfad;
180         struct bfa_s *bfa = &bfad->bfa;
181         struct bfa_ioc_s *ioc = &bfa->ioc;
182         char model[BFA_ADAPTER_MODEL_NAME_LEN];
183
184         bfa_get_adapter_model(bfa, model);
185
186         memset(bfa_buf, 0, sizeof(bfa_buf));
187         if (ioc->ctdev)
188                 snprintf(bfa_buf, sizeof(bfa_buf),
189                 "Brocade FCOE Adapter, " "model: %s hwpath: %s driver: %s",
190                  model, bfad->pci_name, BFAD_DRIVER_VERSION);
191         else
192                 snprintf(bfa_buf, sizeof(bfa_buf),
193                 "Brocade FC Adapter, " "model: %s hwpath: %s driver: %s",
194                 model, bfad->pci_name, BFAD_DRIVER_VERSION);
195
196         return bfa_buf;
197 }
198
199 /*
200  * Scsi_Host template entry, aborts the specified SCSI command.
201  *
202  * Returns: SUCCESS or FAILED.
203  */
204 static int
205 bfad_im_abort_handler(struct scsi_cmnd *cmnd)
206 {
207         struct Scsi_Host *shost = cmnd->device->host;
208         struct bfad_im_port_s *im_port =
209                         (struct bfad_im_port_s *) shost->hostdata[0];
210         struct bfad_s         *bfad = im_port->bfad;
211         struct bfa_ioim_s *hal_io;
212         unsigned long   flags;
213         u32        timeout;
214         int             rc = FAILED;
215
216         spin_lock_irqsave(&bfad->bfad_lock, flags);
217         hal_io = (struct bfa_ioim_s *) cmnd->host_scribble;
218         if (!hal_io) {
219                 /* IO has been completed, retrun success */
220                 rc = SUCCESS;
221                 goto out;
222         }
223         if (hal_io->dio != (struct bfad_ioim_s *) cmnd) {
224                 rc = FAILED;
225                 goto out;
226         }
227
228         bfa_trc(bfad, hal_io->iotag);
229         BFA_LOG(KERN_INFO, bfad, log_level, "scsi%d: abort cmnd %p iotag %x\n",
230                 im_port->shost->host_no, cmnd, hal_io->iotag);
231         (void) bfa_ioim_abort(hal_io);
232         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
233
234         /* Need to wait until the command get aborted */
235         timeout = 10;
236         while ((struct bfa_ioim_s *) cmnd->host_scribble == hal_io) {
237                 set_current_state(TASK_UNINTERRUPTIBLE);
238                 schedule_timeout(timeout);
239                 if (timeout < 4 * HZ)
240                         timeout *= 2;
241         }
242
243         cmnd->scsi_done(cmnd);
244         bfa_trc(bfad, hal_io->iotag);
245         BFA_LOG(KERN_INFO, bfad, log_level,
246                 "scsi%d: complete abort 0x%p iotag 0x%x\n",
247                 im_port->shost->host_no, cmnd, hal_io->iotag);
248         return SUCCESS;
249 out:
250         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
251         return rc;
252 }
253
254 static bfa_status_t
255 bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
256                      struct bfad_itnim_s *itnim)
257 {
258         struct bfa_tskim_s *tskim;
259         struct bfa_itnim_s *bfa_itnim;
260         bfa_status_t    rc = BFA_STATUS_OK;
261
262         tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
263         if (!tskim) {
264                 BFA_LOG(KERN_ERR, bfad, log_level,
265                         "target reset, fail to allocate tskim\n");
266                 rc = BFA_STATUS_FAILED;
267                 goto out;
268         }
269
270         /*
271          * Set host_scribble to NULL to avoid aborting a task command if
272          * happens.
273          */
274         cmnd->host_scribble = NULL;
275         cmnd->SCp.Status = 0;
276         bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
277         bfa_tskim_start(tskim, bfa_itnim, (lun_t)0,
278                             FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
279 out:
280         return rc;
281 }
282
283 /*
284  * Scsi_Host template entry, resets a LUN and abort its all commands.
285  *
286  * Returns: SUCCESS or FAILED.
287  *
288  */
289 static int
290 bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
291 {
292         struct Scsi_Host *shost = cmnd->device->host;
293         struct bfad_im_port_s *im_port =
294                         (struct bfad_im_port_s *) shost->hostdata[0];
295         struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
296         struct bfad_s         *bfad = im_port->bfad;
297         struct bfa_tskim_s *tskim;
298         struct bfad_itnim_s   *itnim;
299         struct bfa_itnim_s *bfa_itnim;
300         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
301         int             rc = SUCCESS;
302         unsigned long   flags;
303         enum bfi_tskim_status task_status;
304
305         spin_lock_irqsave(&bfad->bfad_lock, flags);
306         itnim = itnim_data->itnim;
307         if (!itnim) {
308                 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
309                 rc = FAILED;
310                 goto out;
311         }
312
313         tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
314         if (!tskim) {
315                 BFA_LOG(KERN_ERR, bfad, log_level,
316                                 "LUN reset, fail to allocate tskim");
317                 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
318                 rc = FAILED;
319                 goto out;
320         }
321
322         /*
323          * Set host_scribble to NULL to avoid aborting a task command
324          * if happens.
325          */
326         cmnd->host_scribble = NULL;
327         cmnd->SCp.ptr = (char *)&wq;
328         cmnd->SCp.Status = 0;
329         bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
330         bfa_tskim_start(tskim, bfa_itnim,
331                             bfad_int_to_lun(cmnd->device->lun),
332                             FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
333         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
334
335         wait_event(wq, test_bit(IO_DONE_BIT,
336                         (unsigned long *)&cmnd->SCp.Status));
337
338         task_status = cmnd->SCp.Status >> 1;
339         if (task_status != BFI_TSKIM_STS_OK) {
340                 BFA_LOG(KERN_ERR, bfad, log_level,
341                         "LUN reset failure, status: %d\n", task_status);
342                 rc = FAILED;
343         }
344
345 out:
346         return rc;
347 }
348
349 /*
350  * Scsi_Host template entry, resets the bus and abort all commands.
351  */
352 static int
353 bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
354 {
355         struct Scsi_Host *shost = cmnd->device->host;
356         struct bfad_im_port_s *im_port =
357                                 (struct bfad_im_port_s *) shost->hostdata[0];
358         struct bfad_s         *bfad = im_port->bfad;
359         struct bfad_itnim_s   *itnim;
360         unsigned long   flags;
361         u32        i, rc, err_cnt = 0;
362         DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
363         enum bfi_tskim_status task_status;
364
365         spin_lock_irqsave(&bfad->bfad_lock, flags);
366         for (i = 0; i < MAX_FCP_TARGET; i++) {
367                 itnim = bfad_os_get_itnim(im_port, i);
368                 if (itnim) {
369                         cmnd->SCp.ptr = (char *)&wq;
370                         rc = bfad_im_target_reset_send(bfad, cmnd, itnim);
371                         if (rc != BFA_STATUS_OK) {
372                                 err_cnt++;
373                                 continue;
374                         }
375
376                         /* wait target reset to complete */
377                         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
378                         wait_event(wq, test_bit(IO_DONE_BIT,
379                                         (unsigned long *)&cmnd->SCp.Status));
380                         spin_lock_irqsave(&bfad->bfad_lock, flags);
381
382                         task_status = cmnd->SCp.Status >> 1;
383                         if (task_status != BFI_TSKIM_STS_OK) {
384                                 BFA_LOG(KERN_ERR, bfad, log_level,
385                                         "target reset failure,"
386                                         " status: %d\n", task_status);
387                                 err_cnt++;
388                         }
389                 }
390         }
391         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
392
393         if (err_cnt)
394                 return FAILED;
395
396         return SUCCESS;
397 }
398
399 /*
400  * Scsi_Host template entry slave_destroy.
401  */
402 static void
403 bfad_im_slave_destroy(struct scsi_device *sdev)
404 {
405         sdev->hostdata = NULL;
406         return;
407 }
408
409 /*
410  *  BFA FCS itnim callbacks
411  */
412
413 /*
414  * BFA FCS itnim alloc callback, after successful PRLI
415  * Context: Interrupt
416  */
417 void
418 bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
419                     struct bfad_itnim_s **itnim_drv)
420 {
421         *itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC);
422         if (*itnim_drv == NULL)
423                 return;
424
425         (*itnim_drv)->im = bfad->im;
426         *itnim = &(*itnim_drv)->fcs_itnim;
427         (*itnim_drv)->state = ITNIM_STATE_NONE;
428
429         /*
430          * Initiaze the itnim_work
431          */
432         INIT_WORK(&(*itnim_drv)->itnim_work, bfad_im_itnim_work_handler);
433         bfad->bfad_flags |= BFAD_RPORT_ONLINE;
434 }
435
436 /*
437  * BFA FCS itnim free callback.
438  * Context: Interrupt. bfad_lock is held
439  */
440 void
441 bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
442 {
443         struct bfad_port_s    *port;
444         wwn_t wwpn;
445         u32 fcid;
446         char wwpn_str[32], fcid_str[16];
447         struct bfad_im_s        *im = itnim_drv->im;
448
449         /* online to free state transtion should not happen */
450         bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE);
451
452         itnim_drv->queue_work = 1;
453         /* offline request is not yet done, use the same request to free */
454         if (itnim_drv->state == ITNIM_STATE_OFFLINE_PENDING)
455                 itnim_drv->queue_work = 0;
456
457         itnim_drv->state = ITNIM_STATE_FREE;
458         port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
459         itnim_drv->im_port = port->im_port;
460         wwpn = bfa_fcs_itnim_get_pwwn(&itnim_drv->fcs_itnim);
461         fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
462         wwn2str(wwpn_str, wwpn);
463         fcid2str(fcid_str, fcid);
464         BFA_LOG(KERN_INFO, bfad, log_level,
465                 "ITNIM FREE scsi%d: FCID: %s WWPN: %s\n",
466                 port->im_port->shost->host_no,
467                 fcid_str, wwpn_str);
468
469         /* ITNIM processing */
470         if (itnim_drv->queue_work)
471                 queue_work(im->drv_workq, &itnim_drv->itnim_work);
472 }
473
474 /*
475  * BFA FCS itnim online callback.
476  * Context: Interrupt. bfad_lock is held
477  */
478 void
479 bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv)
480 {
481         struct bfad_port_s    *port;
482         struct bfad_im_s        *im = itnim_drv->im;
483
484         itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim);
485         port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
486         itnim_drv->state = ITNIM_STATE_ONLINE;
487         itnim_drv->queue_work = 1;
488         itnim_drv->im_port = port->im_port;
489
490         /* ITNIM processing */
491         if (itnim_drv->queue_work)
492                 queue_work(im->drv_workq, &itnim_drv->itnim_work);
493 }
494
495 /*
496  * BFA FCS itnim offline callback.
497  * Context: Interrupt. bfad_lock is held
498  */
499 void
500 bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv)
501 {
502         struct bfad_port_s    *port;
503         struct bfad_s *bfad;
504         struct bfad_im_s        *im = itnim_drv->im;
505
506         port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
507         bfad = port->bfad;
508         if ((bfad->pport.flags & BFAD_PORT_DELETE) ||
509                  (port->flags & BFAD_PORT_DELETE)) {
510                 itnim_drv->state = ITNIM_STATE_OFFLINE;
511                 return;
512         }
513         itnim_drv->im_port = port->im_port;
514         itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING;
515         itnim_drv->queue_work = 1;
516
517         /* ITNIM processing */
518         if (itnim_drv->queue_work)
519                 queue_work(im->drv_workq, &itnim_drv->itnim_work);
520 }
521
522 /*
523  * Allocate a Scsi_Host for a port.
524  */
525 int
526 bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port,
527                         struct device *dev)
528 {
529         int error = 1;
530
531         mutex_lock(&bfad_mutex);
532         if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
533                 mutex_unlock(&bfad_mutex);
534                 printk(KERN_WARNING "idr_pre_get failure\n");
535                 goto out;
536         }
537
538         error = idr_get_new(&bfad_im_port_index, im_port,
539                                          &im_port->idr_id);
540         if (error) {
541                 mutex_unlock(&bfad_mutex);
542                 printk(KERN_WARNING "idr_get_new failure\n");
543                 goto out;
544         }
545
546         mutex_unlock(&bfad_mutex);
547
548         im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
549         if (!im_port->shost) {
550                 error = 1;
551                 goto out_free_idr;
552         }
553
554         im_port->shost->hostdata[0] = (unsigned long)im_port;
555         im_port->shost->unique_id = im_port->idr_id;
556         im_port->shost->this_id = -1;
557         im_port->shost->max_id = MAX_FCP_TARGET;
558         im_port->shost->max_lun = MAX_FCP_LUN;
559         im_port->shost->max_cmd_len = 16;
560         im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
561         if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
562                 im_port->shost->transportt = bfad_im_scsi_transport_template;
563         else
564                 im_port->shost->transportt =
565                                 bfad_im_scsi_vport_transport_template;
566
567         error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev);
568         if (error) {
569                 printk(KERN_WARNING "scsi_add_host failure %d\n", error);
570                 goto out_fc_rel;
571         }
572
573         /* setup host fixed attribute if the lk supports */
574         bfad_os_fc_host_init(im_port);
575
576         return 0;
577
578 out_fc_rel:
579         scsi_host_put(im_port->shost);
580         im_port->shost = NULL;
581 out_free_idr:
582         mutex_lock(&bfad_mutex);
583         idr_remove(&bfad_im_port_index, im_port->idr_id);
584         mutex_unlock(&bfad_mutex);
585 out:
586         return error;
587 }
588
589 void
590 bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
591 {
592         bfa_trc(bfad, bfad->inst_no);
593         BFA_LOG(KERN_INFO, bfad, log_level, "Free scsi%d\n",
594                         im_port->shost->host_no);
595
596         fc_remove_host(im_port->shost);
597
598         scsi_remove_host(im_port->shost);
599         scsi_host_put(im_port->shost);
600
601         mutex_lock(&bfad_mutex);
602         idr_remove(&bfad_im_port_index, im_port->idr_id);
603         mutex_unlock(&bfad_mutex);
604 }
605
606 static void
607 bfad_im_port_delete_handler(struct work_struct *work)
608 {
609         struct bfad_im_port_s *im_port =
610                 container_of(work, struct bfad_im_port_s, port_delete_work);
611
612         if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) {
613                 im_port->flags |= BFAD_PORT_DELETE;
614                 fc_vport_terminate(im_port->fc_vport);
615         }
616 }
617
618 bfa_status_t
619 bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port)
620 {
621         int             rc = BFA_STATUS_OK;
622         struct bfad_im_port_s *im_port;
623
624         im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC);
625         if (im_port == NULL) {
626                 rc = BFA_STATUS_ENOMEM;
627                 goto ext;
628         }
629         port->im_port = im_port;
630         im_port->port = port;
631         im_port->bfad = bfad;
632
633         INIT_WORK(&im_port->port_delete_work, bfad_im_port_delete_handler);
634         INIT_LIST_HEAD(&im_port->itnim_mapped_list);
635         INIT_LIST_HEAD(&im_port->binding_list);
636
637 ext:
638         return rc;
639 }
640
641 void
642 bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
643 {
644         struct bfad_im_port_s *im_port = port->im_port;
645
646         queue_work(bfad->im->drv_workq,
647                                 &im_port->port_delete_work);
648 }
649
650 void
651 bfad_im_port_clean(struct bfad_im_port_s *im_port)
652 {
653         struct bfad_fcp_binding *bp, *bp_new;
654         unsigned long flags;
655         struct bfad_s *bfad =  im_port->bfad;
656
657         spin_lock_irqsave(&bfad->bfad_lock, flags);
658         list_for_each_entry_safe(bp, bp_new, &im_port->binding_list,
659                                         list_entry) {
660                 list_del(&bp->list_entry);
661                 kfree(bp);
662         }
663
664         /* the itnim_mapped_list must be empty at this time */
665         bfa_assert(list_empty(&im_port->itnim_mapped_list));
666
667         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
668 }
669
670 bfa_status_t
671 bfad_im_probe(struct bfad_s *bfad)
672 {
673         struct bfad_im_s      *im;
674         bfa_status_t    rc = BFA_STATUS_OK;
675
676         im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL);
677         if (im == NULL) {
678                 rc = BFA_STATUS_ENOMEM;
679                 goto ext;
680         }
681
682         bfad->im = im;
683         im->bfad = bfad;
684
685         if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) {
686                 kfree(im);
687                 rc = BFA_STATUS_FAILED;
688         }
689
690 ext:
691         return rc;
692 }
693
694 void
695 bfad_im_probe_undo(struct bfad_s *bfad)
696 {
697         if (bfad->im) {
698                 bfad_os_destroy_workq(bfad->im);
699                 kfree(bfad->im);
700                 bfad->im = NULL;
701         }
702 }
703
704 struct Scsi_Host *
705 bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
706 {
707         struct scsi_host_template *sht;
708
709         if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
710                 sht = &bfad_im_scsi_host_template;
711         else
712                 sht = &bfad_im_vport_template;
713
714         sht->sg_tablesize = bfad->cfg_data.io_max_sge;
715
716         return scsi_host_alloc(sht, sizeof(unsigned long));
717 }
718
719 void
720 bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
721 {
722         if (!(im_port->flags & BFAD_PORT_DELETE))
723                 flush_workqueue(bfad->im->drv_workq);
724         bfad_im_scsi_host_free(im_port->bfad, im_port);
725         bfad_im_port_clean(im_port);
726         kfree(im_port);
727 }
728
729 void
730 bfad_os_destroy_workq(struct bfad_im_s *im)
731 {
732         if (im && im->drv_workq) {
733                 flush_workqueue(im->drv_workq);
734                 destroy_workqueue(im->drv_workq);
735                 im->drv_workq = NULL;
736         }
737 }
738
739 bfa_status_t
740 bfad_os_thread_workq(struct bfad_s *bfad)
741 {
742         struct bfad_im_s      *im = bfad->im;
743
744         bfa_trc(bfad, 0);
745         snprintf(im->drv_workq_name, KOBJ_NAME_LEN, "bfad_wq_%d",
746                  bfad->inst_no);
747         im->drv_workq = create_singlethread_workqueue(im->drv_workq_name);
748         if (!im->drv_workq)
749                 return BFA_STATUS_FAILED;
750
751         return BFA_STATUS_OK;
752 }
753
754 /*
755  * Scsi_Host template entry.
756  *
757  * Description:
758  * OS entry point to adjust the queue_depths on a per-device basis.
759  * Called once per device during the bus scan.
760  * Return non-zero if fails.
761  */
762 static int
763 bfad_im_slave_configure(struct scsi_device *sdev)
764 {
765         if (sdev->tagged_supported)
766                 scsi_activate_tcq(sdev, bfa_lun_queue_depth);
767         else
768                 scsi_deactivate_tcq(sdev, bfa_lun_queue_depth);
769
770         return 0;
771 }
772
773 struct scsi_host_template bfad_im_scsi_host_template = {
774         .module = THIS_MODULE,
775         .name = BFAD_DRIVER_NAME,
776         .info = bfad_im_info,
777         .queuecommand = bfad_im_queuecommand,
778         .eh_abort_handler = bfad_im_abort_handler,
779         .eh_device_reset_handler = bfad_im_reset_lun_handler,
780         .eh_bus_reset_handler = bfad_im_reset_bus_handler,
781
782         .slave_alloc = bfad_im_slave_alloc,
783         .slave_configure = bfad_im_slave_configure,
784         .slave_destroy = bfad_im_slave_destroy,
785
786         .this_id = -1,
787         .sg_tablesize = BFAD_IO_MAX_SGE,
788         .cmd_per_lun = 3,
789         .use_clustering = ENABLE_CLUSTERING,
790         .shost_attrs = bfad_im_host_attrs,
791         .max_sectors = 0xFFFF,
792 };
793
794 struct scsi_host_template bfad_im_vport_template = {
795         .module = THIS_MODULE,
796         .name = BFAD_DRIVER_NAME,
797         .info = bfad_im_info,
798         .queuecommand = bfad_im_queuecommand,
799         .eh_abort_handler = bfad_im_abort_handler,
800         .eh_device_reset_handler = bfad_im_reset_lun_handler,
801         .eh_bus_reset_handler = bfad_im_reset_bus_handler,
802
803         .slave_alloc = bfad_im_slave_alloc,
804         .slave_configure = bfad_im_slave_configure,
805         .slave_destroy = bfad_im_slave_destroy,
806
807         .this_id = -1,
808         .sg_tablesize = BFAD_IO_MAX_SGE,
809         .cmd_per_lun = 3,
810         .use_clustering = ENABLE_CLUSTERING,
811         .shost_attrs = bfad_im_vport_attrs,
812         .max_sectors = 0xFFFF,
813 };
814
815 bfa_status_t
816 bfad_im_module_init(void)
817 {
818         bfad_im_scsi_transport_template =
819                 fc_attach_transport(&bfad_im_fc_function_template);
820         if (!bfad_im_scsi_transport_template)
821                 return BFA_STATUS_ENOMEM;
822
823         bfad_im_scsi_vport_transport_template =
824                 fc_attach_transport(&bfad_im_vport_fc_function_template);
825         if (!bfad_im_scsi_vport_transport_template) {
826                 fc_release_transport(bfad_im_scsi_transport_template);
827                 return BFA_STATUS_ENOMEM;
828         }
829
830         return BFA_STATUS_OK;
831 }
832
833 void
834 bfad_im_module_exit(void)
835 {
836         if (bfad_im_scsi_transport_template)
837                 fc_release_transport(bfad_im_scsi_transport_template);
838
839         if (bfad_im_scsi_vport_transport_template)
840                 fc_release_transport(bfad_im_scsi_vport_transport_template);
841 }
842
843 void
844 bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
845 {
846         struct scsi_device *tmp_sdev;
847
848         if (((jiffies - itnim->last_ramp_up_time) >
849                 BFA_QUEUE_FULL_RAMP_UP_TIME * HZ) &&
850                 ((jiffies - itnim->last_queue_full_time) >
851                 BFA_QUEUE_FULL_RAMP_UP_TIME * HZ)) {
852                 shost_for_each_device(tmp_sdev, sdev->host) {
853                         if (bfa_lun_queue_depth > tmp_sdev->queue_depth) {
854                                 if (tmp_sdev->id != sdev->id)
855                                         continue;
856                                 if (tmp_sdev->ordered_tags)
857                                         scsi_adjust_queue_depth(tmp_sdev,
858                                                 MSG_ORDERED_TAG,
859                                                 tmp_sdev->queue_depth + 1);
860                                 else
861                                         scsi_adjust_queue_depth(tmp_sdev,
862                                                 MSG_SIMPLE_TAG,
863                                                 tmp_sdev->queue_depth + 1);
864
865                                 itnim->last_ramp_up_time = jiffies;
866                         }
867                 }
868         }
869 }
870
871 void
872 bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
873 {
874         struct scsi_device *tmp_sdev;
875
876         itnim->last_queue_full_time = jiffies;
877
878         shost_for_each_device(tmp_sdev, sdev->host) {
879                 if (tmp_sdev->id != sdev->id)
880                         continue;
881                 scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
882         }
883 }
884
885 struct bfad_itnim_s *
886 bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
887 {
888         struct bfad_itnim_s   *itnim = NULL;
889
890         /* Search the mapped list for this target ID */
891         list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) {
892                 if (id == itnim->scsi_tgt_id)
893                         return itnim;
894         }
895
896         return NULL;
897 }
898
899 /*
900  * Scsi_Host template entry slave_alloc
901  */
902 static int
903 bfad_im_slave_alloc(struct scsi_device *sdev)
904 {
905         struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
906
907         if (!rport || fc_remote_port_chkready(rport))
908                 return -ENXIO;
909
910         sdev->hostdata = rport->dd_data;
911
912         return 0;
913 }
914
915 static u32
916 bfad_im_supported_speeds(struct bfa_s *bfa)
917 {
918         struct bfa_ioc_attr_s *ioc_attr;
919         u32 supported_speed = 0;
920
921         ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL);
922         if (!ioc_attr)
923                 return 0;
924
925         bfa_get_attr(bfa, ioc_attr);
926         if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) {
927                 if (ioc_attr->adapter_attr.is_mezz) {
928                         supported_speed |= FC_PORTSPEED_8GBIT |
929                                 FC_PORTSPEED_4GBIT |
930                                 FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
931                 } else {
932                         supported_speed |= FC_PORTSPEED_8GBIT |
933                                 FC_PORTSPEED_4GBIT |
934                                 FC_PORTSPEED_2GBIT;
935                 }
936         } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) {
937                 supported_speed |=  FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
938                                 FC_PORTSPEED_1GBIT;
939         } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) {
940                 supported_speed |= FC_PORTSPEED_10GBIT;
941         }
942         kfree(ioc_attr);
943         return supported_speed;
944 }
945
946 void
947 bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
948 {
949         struct Scsi_Host *host = im_port->shost;
950         struct bfad_s         *bfad = im_port->bfad;
951         struct bfad_port_s    *port = im_port->port;
952         char symname[BFA_SYMNAME_MAXLEN];
953         struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa);
954
955         fc_host_node_name(host) =
956                 cpu_to_be64((bfa_fcs_lport_get_nwwn(port->fcs_port)));
957         fc_host_port_name(host) =
958                 cpu_to_be64((bfa_fcs_lport_get_pwwn(port->fcs_port)));
959         fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa);
960
961         fc_host_supported_classes(host) = FC_COS_CLASS3;
962
963         memset(fc_host_supported_fc4s(host), 0,
964                sizeof(fc_host_supported_fc4s(host)));
965         if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM)
966                 /* For FCP type 0x08 */
967                 fc_host_supported_fc4s(host)[2] = 1;
968         /* For fibre channel services type 0x20 */
969         fc_host_supported_fc4s(host)[7] = 1;
970
971         strncpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname,
972                 BFA_SYMNAME_MAXLEN);
973         sprintf(fc_host_symbolic_name(host), "%s", symname);
974
975         fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa);
976         fc_host_maxframe_size(host) = fcport->cfg.maxfrsize;
977 }
978
979 static void
980 bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
981 {
982         struct fc_rport_identifiers rport_ids;
983         struct fc_rport *fc_rport;
984         struct bfad_itnim_data_s *itnim_data;
985
986         rport_ids.node_name =
987                 cpu_to_be64(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
988         rport_ids.port_name =
989                 cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
990         rport_ids.port_id =
991                 bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
992         rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
993
994         itnim->fc_rport = fc_rport =
995                 fc_remote_port_add(im_port->shost, 0, &rport_ids);
996
997         if (!fc_rport)
998                 return;
999
1000         fc_rport->maxframe_size =
1001                 bfa_fcs_itnim_get_maxfrsize(&itnim->fcs_itnim);
1002         fc_rport->supported_classes = bfa_fcs_itnim_get_cos(&itnim->fcs_itnim);
1003
1004         itnim_data = fc_rport->dd_data;
1005         itnim_data->itnim = itnim;
1006
1007         rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
1008
1009         if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN)
1010                 fc_remote_port_rolechg(fc_rport, rport_ids.roles);
1011
1012         if ((fc_rport->scsi_target_id != -1)
1013             && (fc_rport->scsi_target_id < MAX_FCP_TARGET))
1014                 itnim->scsi_tgt_id = fc_rport->scsi_target_id;
1015
1016         return;
1017 }
1018
1019 /*
1020  * Work queue handler using FC transport service
1021 * Context: kernel
1022  */
1023 static void
1024 bfad_im_itnim_work_handler(struct work_struct *work)
1025 {
1026         struct bfad_itnim_s   *itnim = container_of(work, struct bfad_itnim_s,
1027                                                         itnim_work);
1028         struct bfad_im_s      *im = itnim->im;
1029         struct bfad_s         *bfad = im->bfad;
1030         struct bfad_im_port_s *im_port;
1031         unsigned long   flags;
1032         struct fc_rport *fc_rport;
1033         wwn_t wwpn;
1034         u32 fcid;
1035         char wwpn_str[32], fcid_str[16];
1036
1037         spin_lock_irqsave(&bfad->bfad_lock, flags);
1038         im_port = itnim->im_port;
1039         bfa_trc(bfad, itnim->state);
1040         switch (itnim->state) {
1041         case ITNIM_STATE_ONLINE:
1042                 if (!itnim->fc_rport) {
1043                         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1044                         bfad_im_fc_rport_add(im_port, itnim);
1045                         spin_lock_irqsave(&bfad->bfad_lock, flags);
1046                         wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
1047                         fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
1048                         wwn2str(wwpn_str, wwpn);
1049                         fcid2str(fcid_str, fcid);
1050                         list_add_tail(&itnim->list_entry,
1051                                 &im_port->itnim_mapped_list);
1052                         BFA_LOG(KERN_INFO, bfad, log_level,
1053                                 "ITNIM ONLINE Target: %d:0:%d "
1054                                 "FCID: %s WWPN: %s\n",
1055                                 im_port->shost->host_no,
1056                                 itnim->scsi_tgt_id,
1057                                 fcid_str, wwpn_str);
1058                 } else {
1059                         printk(KERN_WARNING
1060                                 "%s: itnim %llx is already in online state\n",
1061                                 __func__,
1062                                 bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
1063                 }
1064
1065                 break;
1066         case ITNIM_STATE_OFFLINE_PENDING:
1067                 itnim->state = ITNIM_STATE_OFFLINE;
1068                 if (itnim->fc_rport) {
1069                         fc_rport = itnim->fc_rport;
1070                         ((struct bfad_itnim_data_s *)
1071                                 fc_rport->dd_data)->itnim = NULL;
1072                         itnim->fc_rport = NULL;
1073                         if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
1074                                 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1075                                 fc_rport->dev_loss_tmo =
1076                                         bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
1077                                 fc_remote_port_delete(fc_rport);
1078                                 spin_lock_irqsave(&bfad->bfad_lock, flags);
1079                         }
1080                         wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
1081                         fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
1082                         wwn2str(wwpn_str, wwpn);
1083                         fcid2str(fcid_str, fcid);
1084                         list_del(&itnim->list_entry);
1085                         BFA_LOG(KERN_INFO, bfad, log_level,
1086                                 "ITNIM OFFLINE Target: %d:0:%d "
1087                                 "FCID: %s WWPN: %s\n",
1088                                 im_port->shost->host_no,
1089                                 itnim->scsi_tgt_id,
1090                                 fcid_str, wwpn_str);
1091                 }
1092                 break;
1093         case ITNIM_STATE_FREE:
1094                 if (itnim->fc_rport) {
1095                         fc_rport = itnim->fc_rport;
1096                         ((struct bfad_itnim_data_s *)
1097                                 fc_rport->dd_data)->itnim = NULL;
1098                         itnim->fc_rport = NULL;
1099                         if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
1100                                 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1101                                 fc_rport->dev_loss_tmo =
1102                                         bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
1103                                 fc_remote_port_delete(fc_rport);
1104                                 spin_lock_irqsave(&bfad->bfad_lock, flags);
1105                         }
1106                         list_del(&itnim->list_entry);
1107                 }
1108
1109                 kfree(itnim);
1110                 break;
1111         default:
1112                 bfa_assert(0);
1113                 break;
1114         }
1115
1116         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1117 }
1118
1119 /*
1120  * Scsi_Host template entry, queue a SCSI command to the BFAD.
1121  */
1122 static int
1123 bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
1124 {
1125         struct bfad_im_port_s *im_port =
1126                 (struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
1127         struct bfad_s         *bfad = im_port->bfad;
1128         struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
1129         struct bfad_itnim_s   *itnim;
1130         struct bfa_ioim_s *hal_io;
1131         unsigned long   flags;
1132         int             rc;
1133         int       sg_cnt = 0;
1134         struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
1135
1136         rc = fc_remote_port_chkready(rport);
1137         if (rc) {
1138                 cmnd->result = rc;
1139                 done(cmnd);
1140                 return 0;
1141         }
1142
1143         sg_cnt = scsi_dma_map(cmnd);
1144         if (sg_cnt < 0)
1145                 return SCSI_MLQUEUE_HOST_BUSY;
1146
1147         cmnd->scsi_done = done;
1148
1149         spin_lock_irqsave(&bfad->bfad_lock, flags);
1150         if (!(bfad->bfad_flags & BFAD_HAL_START_DONE)) {
1151                 printk(KERN_WARNING
1152                         "bfad%d, queuecommand %p %x failed, BFA stopped\n",
1153                        bfad->inst_no, cmnd, cmnd->cmnd[0]);
1154                 cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
1155                 goto out_fail_cmd;
1156         }
1157
1158
1159         itnim = itnim_data->itnim;
1160         if (!itnim) {
1161                 cmnd->result = ScsiResult(DID_IMM_RETRY, 0);
1162                 goto out_fail_cmd;
1163         }
1164
1165         hal_io = bfa_ioim_alloc(&bfad->bfa, (struct bfad_ioim_s *) cmnd,
1166                                     itnim->bfa_itnim, sg_cnt);
1167         if (!hal_io) {
1168                 printk(KERN_WARNING "hal_io failure\n");
1169                 spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1170                 scsi_dma_unmap(cmnd);
1171                 return SCSI_MLQUEUE_HOST_BUSY;
1172         }
1173
1174         cmnd->host_scribble = (char *)hal_io;
1175         bfa_trc_fp(bfad, hal_io->iotag);
1176         bfa_ioim_start(hal_io);
1177         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1178
1179         return 0;
1180
1181 out_fail_cmd:
1182         spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1183         scsi_dma_unmap(cmnd);
1184         if (done)
1185                 done(cmnd);
1186
1187         return 0;
1188 }
1189
1190 void
1191 bfad_os_rport_online_wait(struct bfad_s *bfad)
1192 {
1193         int i;
1194         int rport_delay = 10;
1195
1196         for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE)
1197                 && i < bfa_linkup_delay; i++) {
1198                 set_current_state(TASK_UNINTERRUPTIBLE);
1199                 schedule_timeout(HZ);
1200         }
1201
1202         if (bfad->bfad_flags & BFAD_PORT_ONLINE) {
1203                 rport_delay = rport_delay < bfa_linkup_delay ?
1204                         rport_delay : bfa_linkup_delay;
1205                 for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE)
1206                         && i < rport_delay; i++) {
1207                         set_current_state(TASK_UNINTERRUPTIBLE);
1208                         schedule_timeout(HZ);
1209                 }
1210
1211                 if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) {
1212                         set_current_state(TASK_UNINTERRUPTIBLE);
1213                         schedule_timeout(rport_delay * HZ);
1214                 }
1215         }
1216 }
1217
1218 int
1219 bfad_os_get_linkup_delay(struct bfad_s *bfad)
1220 {
1221         u8              nwwns = 0;
1222         wwn_t           wwns[BFA_PREBOOT_BOOTLUN_MAX];
1223         int             linkup_delay;
1224
1225         /*
1226          * Querying for the boot target port wwns
1227          * -- read from boot information in flash.
1228          * If nwwns > 0 => boot over SAN and set linkup_delay = 30
1229          * else => local boot machine set linkup_delay = 0
1230          */
1231
1232         bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns);
1233
1234         if (nwwns > 0)
1235                 /* If Boot over SAN set linkup_delay = 30sec */
1236                 linkup_delay = 30;
1237         else
1238                 /* If local boot; no linkup_delay */
1239                 linkup_delay = 0;
1240
1241         return linkup_delay;
1242 }