diff options
Diffstat (limited to 'drivers/scsi/bfa/bfad_im.c')
| -rw-r--r-- | drivers/scsi/bfa/bfad_im.c | 479 |
1 files changed, 288 insertions, 191 deletions
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 5b7cf539e50..f067332bf76 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. * All rights reserved * www.brocade.com * @@ -15,16 +15,15 @@ * General Public License for more details. */ -/** +/* * bfad_im.c Linux driver IM module. */ -#include <linux/slab.h> +#include <linux/export.h> + #include "bfad_drv.h" #include "bfad_im.h" -#include "bfad_trcmod.h" -#include "bfa_cb_ioim_macros.h" -#include <fcb/bfa_fcb_fcpim.h> +#include "bfa_fcs.h" BFA_TRC_FILE(LDRV, IM); @@ -32,9 +31,10 @@ DEFINE_IDR(bfad_im_port_index); struct scsi_transport_template *bfad_im_scsi_transport_template; struct scsi_transport_template *bfad_im_scsi_vport_transport_template; static void bfad_im_itnim_work_handler(struct work_struct *work); -static int bfad_im_queuecommand(struct scsi_cmnd *cmnd, - void (*done)(struct scsi_cmnd *)); +static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd); static int bfad_im_slave_alloc(struct scsi_device *sdev); +static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, + struct bfad_itnim_s *itnim); void bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, @@ -58,6 +58,7 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, sns_len = SCSI_SENSE_BUFFERSIZE; memcpy(cmnd->sense_buffer, sns_info, sns_len); } + if (residue > 0) { bfa_trc(bfad, residue); scsi_set_resid(cmnd, residue); @@ -72,11 +73,17 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, break; - case BFI_IOIM_STS_ABORTED: case BFI_IOIM_STS_TIMEDOUT: + host_status = DID_TIME_OUT; + cmnd->result = ScsiResult(host_status, 0); + break; case BFI_IOIM_STS_PATHTOV: + host_status = DID_TRANSPORT_DISRUPTED; + cmnd->result = ScsiResult(host_status, 0); + break; default: - cmnd->result = ScsiResult(DID_ERROR, 0); + host_status = DID_ERROR; + cmnd->result = ScsiResult(host_status, 0); } /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ @@ -92,10 +99,10 @@ bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, if (!cmnd->result && itnim && (bfa_lun_queue_depth > cmnd->device->queue_depth)) { /* Queue depth adjustment for good status completion */ - bfad_os_ramp_up_qdepth(itnim, cmnd->device); + bfad_ramp_up_qdepth(itnim, cmnd->device); } else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) { /* qfull handling */ - bfad_os_handle_qfull(itnim, cmnd->device); + bfad_handle_qfull(itnim, cmnd->device); } } @@ -123,7 +130,7 @@ bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio) if (itnim_data) { itnim = itnim_data->itnim; if (itnim) - bfad_os_ramp_up_qdepth(itnim, cmnd->device); + bfad_ramp_up_qdepth(itnim, cmnd->device); } } @@ -162,15 +169,10 @@ bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, wake_up(wq); } -void -bfa_cb_ioim_resfree(void *drv) -{ -} - -/** +/* * Scsi_Host_template SCSI host template */ -/** +/* * Scsi_Host template entry, returns BFAD PCI info. */ static const char * @@ -179,19 +181,17 @@ bfad_im_info(struct Scsi_Host *shost) static char bfa_buf[256]; struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - - bfa_get_adapter_model(&bfad->bfa, model); + struct bfad_s *bfad = im_port->bfad; memset(bfa_buf, 0, sizeof(bfa_buf)); snprintf(bfa_buf, sizeof(bfa_buf), - "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s", - model, bfad->pci_name, BFAD_DRIVER_VERSION); + "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s", + bfad->pci_name, BFAD_DRIVER_VERSION); + return bfa_buf; } -/** +/* * Scsi_Host template entry, aborts the specified SCSI command. * * Returns: SUCCESS or FAILED. @@ -211,7 +211,7 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) spin_lock_irqsave(&bfad->bfad_lock, flags); hal_io = (struct bfa_ioim_s *) cmnd->host_scribble; if (!hal_io) { - /* IO has been completed, retrun success */ + /* IO has been completed, return success */ rc = SUCCESS; goto out; } @@ -221,9 +221,10 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) } bfa_trc(bfad, hal_io->iotag); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "scsi%d: abort cmnd %p iotag %x\n", im_port->shost->host_no, cmnd, hal_io->iotag); - bfa_ioim_abort(hal_io); + (void) bfa_ioim_abort(hal_io); spin_unlock_irqrestore(&bfad->bfad_lock, flags); /* Need to wait until the command get aborted */ @@ -237,7 +238,8 @@ bfad_im_abort_handler(struct scsi_cmnd *cmnd) cmnd->scsi_done(cmnd); bfa_trc(bfad, hal_io->iotag); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT_COMP, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "scsi%d: complete abort 0x%p iotag 0x%x\n", im_port->shost->host_no, cmnd, hal_io->iotag); return SUCCESS; out: @@ -252,11 +254,12 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, struct bfa_tskim_s *tskim; struct bfa_itnim_s *bfa_itnim; bfa_status_t rc = BFA_STATUS_OK; + struct scsi_lun scsilun; tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_DEV_PRINTF(bfad, BFA_ERR, - "target reset, fail to allocate tskim\n"); + BFA_LOG(KERN_ERR, bfad, bfa_log_level, + "target reset, fail to allocate tskim\n"); rc = BFA_STATUS_FAILED; goto out; } @@ -268,13 +271,14 @@ bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, cmnd->host_scribble = NULL; cmnd->SCp.Status = 0; bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim); - bfa_tskim_start(tskim, bfa_itnim, (lun_t)0, + memset(&scsilun, 0, sizeof(scsilun)); + bfa_tskim_start(tskim, bfa_itnim, scsilun, FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO); out: return rc; } -/** +/* * Scsi_Host template entry, resets a LUN and abort its all commands. * * Returns: SUCCESS or FAILED. @@ -291,10 +295,11 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) struct bfa_tskim_s *tskim; struct bfad_itnim_s *itnim; struct bfa_itnim_s *bfa_itnim; - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); int rc = SUCCESS; unsigned long flags; enum bfi_tskim_status task_status; + struct scsi_lun scsilun; spin_lock_irqsave(&bfad->bfad_lock, flags); itnim = itnim_data->itnim; @@ -306,14 +311,14 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); if (!tskim) { - BFA_DEV_PRINTF(bfad, BFA_ERR, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "LUN reset, fail to allocate tskim"); spin_unlock_irqrestore(&bfad->bfad_lock, flags); rc = FAILED; goto out; } - /** + /* * Set host_scribble to NULL to avoid aborting a task command * if happens. */ @@ -321,8 +326,8 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) cmnd->SCp.ptr = (char *)&wq; cmnd->SCp.Status = 0; bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim); - bfa_tskim_start(tskim, bfa_itnim, - bfad_int_to_lun(cmnd->device->lun), + int_to_scsilun(cmnd->device->lun, &scsilun); + bfa_tskim_start(tskim, bfa_itnim, scsilun, FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -331,8 +336,8 @@ bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_DEV_PRINTF(bfad, BFA_ERR, "LUN reset failure, status: %d\n", - task_status); + BFA_LOG(KERN_ERR, bfad, bfa_log_level, + "LUN reset failure, status: %d\n", task_status); rc = FAILED; } @@ -340,7 +345,7 @@ out: return rc; } -/** +/* * Scsi_Host template entry, resets the bus and abort all commands. */ static int @@ -353,12 +358,12 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) struct bfad_itnim_s *itnim; unsigned long flags; u32 i, rc, err_cnt = 0; - DECLARE_WAIT_QUEUE_HEAD(wq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); enum bfi_tskim_status task_status; spin_lock_irqsave(&bfad->bfad_lock, flags); for (i = 0; i < MAX_FCP_TARGET; i++) { - itnim = bfad_os_get_itnim(im_port, i); + itnim = bfad_get_itnim(im_port, i); if (itnim) { cmnd->SCp.ptr = (char *)&wq; rc = bfad_im_target_reset_send(bfad, cmnd, itnim); @@ -375,7 +380,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) task_status = cmnd->SCp.Status >> 1; if (task_status != BFI_TSKIM_STS_OK) { - BFA_DEV_PRINTF(bfad, BFA_ERR, + BFA_LOG(KERN_ERR, bfad, bfa_log_level, "target reset failure," " status: %d\n", task_status); err_cnt++; @@ -390,7 +395,7 @@ bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) return SUCCESS; } -/** +/* * Scsi_Host template entry slave_destroy. */ static void @@ -400,11 +405,11 @@ bfad_im_slave_destroy(struct scsi_device *sdev) return; } -/** +/* * BFA FCS itnim callbacks */ -/** +/* * BFA FCS itnim alloc callback, after successful PRLI * Context: Interrupt */ @@ -427,7 +432,7 @@ bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, bfad->bfad_flags |= BFAD_RPORT_ONLINE; } -/** +/* * BFA FCS itnim free callback. * Context: Interrupt. bfad_lock is held */ @@ -438,9 +443,10 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) wwn_t wwpn; u32 fcid; char wwpn_str[32], fcid_str[16]; + struct bfad_im_s *im = itnim_drv->im; /* online to free state transtion should not happen */ - bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE); + WARN_ON(itnim_drv->state == ITNIM_STATE_ONLINE); itnim_drv->queue_work = 1; /* offline request is not yet done, use the same request to free */ @@ -454,13 +460,17 @@ bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim); wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_FREE, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "ITNIM FREE scsi%d: FCID: %s WWPN: %s\n", port->im_port->shost->host_no, fcid_str, wwpn_str); - bfad_os_itnim_process(itnim_drv); + + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } -/** +/* * BFA FCS itnim online callback. * Context: Interrupt. bfad_lock is held */ @@ -468,16 +478,20 @@ void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv) { struct bfad_port_s *port; + struct bfad_im_s *im = itnim_drv->im; itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim); port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); itnim_drv->state = ITNIM_STATE_ONLINE; itnim_drv->queue_work = 1; itnim_drv->im_port = port->im_port; - bfad_os_itnim_process(itnim_drv); + + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } -/** +/* * BFA FCS itnim offline callback. * Context: Interrupt. bfad_lock is held */ @@ -486,6 +500,7 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) { struct bfad_port_s *port; struct bfad_s *bfad; + struct bfad_im_s *im = itnim_drv->im; port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); bfad = port->bfad; @@ -497,45 +512,32 @@ bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) itnim_drv->im_port = port->im_port; itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING; itnim_drv->queue_work = 1; - bfad_os_itnim_process(itnim_drv); -} -/** - * BFA FCS itnim timeout callback. - * Context: Interrupt. bfad_lock is held - */ -void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim) -{ - itnim->state = ITNIM_STATE_TIMEOUT; + /* ITNIM processing */ + if (itnim_drv->queue_work) + queue_work(im->drv_workq, &itnim_drv->itnim_work); } -/** +/* * Allocate a Scsi_Host for a port. */ int bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, - struct device *dev) + struct device *dev) { int error = 1; mutex_lock(&bfad_mutex); - if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) { + error = idr_alloc(&bfad_im_port_index, im_port, 0, 0, GFP_KERNEL); + if (error < 0) { mutex_unlock(&bfad_mutex); - printk(KERN_WARNING "idr_pre_get failure\n"); + printk(KERN_WARNING "idr_alloc failure\n"); goto out; } - - error = idr_get_new(&bfad_im_port_index, im_port, - &im_port->idr_id); - if (error) { - mutex_unlock(&bfad_mutex); - printk(KERN_WARNING "idr_get_new failure\n"); - goto out; - } - + im_port->idr_id = error; mutex_unlock(&bfad_mutex); - im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad); + im_port->shost = bfad_scsi_host_alloc(im_port, bfad); if (!im_port->shost) { error = 1; goto out_free_idr; @@ -554,19 +556,17 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, im_port->shost->transportt = bfad_im_scsi_vport_transport_template; - error = scsi_add_host(im_port->shost, dev); + error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev); if (error) { printk(KERN_WARNING "scsi_add_host failure %d\n", error); goto out_fc_rel; } - /* setup host fixed attribute if the lk supports */ - bfad_os_fc_host_init(im_port); - return 0; out_fc_rel: scsi_host_put(im_port->shost); + im_port->shost = NULL; out_free_idr: mutex_lock(&bfad_mutex); idr_remove(&bfad_im_port_index, im_port->idr_id); @@ -579,7 +579,7 @@ void bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) { bfa_trc(bfad, bfad->inst_no); - bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n", im_port->shost->host_no); fc_remove_host(im_port->shost); @@ -602,7 +602,6 @@ bfad_im_port_delete_handler(struct work_struct *work) im_port->flags |= BFAD_PORT_DELETE; fc_vport_terminate(im_port->fc_vport); } - } bfa_status_t @@ -652,57 +651,69 @@ bfad_im_port_clean(struct bfad_im_port_s *im_port) } /* the itnim_mapped_list must be empty at this time */ - bfa_assert(list_empty(&im_port->itnim_mapped_list)); + WARN_ON(!list_empty(&im_port->itnim_mapped_list)); spin_unlock_irqrestore(&bfad->bfad_lock, flags); } -void -bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port) +static void bfad_aen_im_notify_handler(struct work_struct *work) { -} + struct bfad_im_s *im = + container_of(work, struct bfad_im_s, aen_im_notify_work); + struct bfa_aen_entry_s *aen_entry; + struct bfad_s *bfad = im->bfad; + struct Scsi_Host *shost = bfad->pport.im_port->shost; + void *event_data; + unsigned long flags; -void -bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port) -{ + while (!list_empty(&bfad->active_aen_q)) { + spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags); + bfa_q_deq(&bfad->active_aen_q, &aen_entry); + spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags); + event_data = (char *)aen_entry + sizeof(struct list_head); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(struct bfa_aen_entry_s) - + sizeof(struct list_head), + (char *)event_data, BFAD_NL_VENDOR_ID); + spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags); + list_add_tail(&aen_entry->qe, &bfad->free_aen_q); + spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags); + } } bfa_status_t bfad_im_probe(struct bfad_s *bfad) { struct bfad_im_s *im; - bfa_status_t rc = BFA_STATUS_OK; im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL); - if (im == NULL) { - rc = BFA_STATUS_ENOMEM; - goto ext; - } + if (im == NULL) + return BFA_STATUS_ENOMEM; bfad->im = im; im->bfad = bfad; - if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) { + if (bfad_thread_workq(bfad) != BFA_STATUS_OK) { kfree(im); - rc = BFA_STATUS_FAILED; + return BFA_STATUS_FAILED; } -ext: - return rc; + INIT_WORK(&im->aen_im_notify_work, bfad_aen_im_notify_handler); + return BFA_STATUS_OK; } void bfad_im_probe_undo(struct bfad_s *bfad) { if (bfad->im) { - bfad_os_destroy_workq(bfad->im); + bfad_destroy_workq(bfad->im); kfree(bfad->im); bfad->im = NULL; } } struct Scsi_Host * -bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) +bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) { struct scsi_host_template *sht; @@ -711,13 +722,16 @@ bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) else sht = &bfad_im_vport_template; + if (max_xfer_size != BFAD_MAX_SECTORS >> 1) + sht->max_sectors = max_xfer_size << 1; + sht->sg_tablesize = bfad->cfg_data.io_max_sge; return scsi_host_alloc(sht, sizeof(unsigned long)); } void -bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) +bfad_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) { if (!(im_port->flags & BFAD_PORT_DELETE)) flush_workqueue(bfad->im->drv_workq); @@ -727,21 +741,22 @@ bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) } void -bfad_os_destroy_workq(struct bfad_im_s *im) +bfad_destroy_workq(struct bfad_im_s *im) { if (im && im->drv_workq) { + flush_workqueue(im->drv_workq); destroy_workqueue(im->drv_workq); im->drv_workq = NULL; } } bfa_status_t -bfad_os_thread_workq(struct bfad_s *bfad) +bfad_thread_workq(struct bfad_s *bfad) { struct bfad_im_s *im = bfad->im; bfa_trc(bfad, 0); - snprintf(im->drv_workq_name, BFAD_KOBJ_NAME_LEN, "bfad_wq_%d", + snprintf(im->drv_workq_name, KOBJ_NAME_LEN, "bfad_wq_%d", bfad->inst_no); im->drv_workq = create_singlethread_workqueue(im->drv_workq_name); if (!im->drv_workq) @@ -750,7 +765,7 @@ bfad_os_thread_workq(struct bfad_s *bfad) return BFA_STATUS_OK; } -/** +/* * Scsi_Host template entry. * * Description: @@ -787,7 +802,8 @@ struct scsi_host_template bfad_im_scsi_host_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_host_attrs, - .max_sectors = 0xFFFF, + .max_sectors = BFAD_MAX_SECTORS, + .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, }; struct scsi_host_template bfad_im_vport_template = { @@ -808,15 +824,9 @@ struct scsi_host_template bfad_im_vport_template = { .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, - .max_sectors = 0xFFFF, + .max_sectors = BFAD_MAX_SECTORS, }; -void -bfad_im_probe_post(struct bfad_im_s *im) -{ - flush_workqueue(im->drv_workq); -} - bfa_status_t bfad_im_module_init(void) { @@ -840,21 +850,13 @@ bfad_im_module_exit(void) { if (bfad_im_scsi_transport_template) fc_release_transport(bfad_im_scsi_transport_template); + if (bfad_im_scsi_vport_transport_template) fc_release_transport(bfad_im_scsi_vport_transport_template); } void -bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv) -{ - struct bfad_im_s *im = itnim_drv->im; - - if (itnim_drv->queue_work) - queue_work(im->drv_workq, &itnim_drv->itnim_work); -} - -void -bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) +bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) { struct scsi_device *tmp_sdev; @@ -882,7 +884,7 @@ bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) } void -bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) +bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) { struct scsi_device *tmp_sdev; @@ -895,11 +897,8 @@ bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) } } - - - struct bfad_itnim_s * -bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id) +bfad_get_itnim(struct bfad_im_port_s *im_port, int id) { struct bfad_itnim_s *itnim = NULL; @@ -912,63 +911,143 @@ bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id) return NULL; } -/** +/* + * Function is invoked from the SCSI Host Template slave_alloc() entry point. + * Has the logic to query the LUN Mask database to check if this LUN needs to + * be made visible to the SCSI mid-layer or not. + * + * Returns BFA_STATUS_OK if this LUN needs to be added to the OS stack. + * Returns -ENXIO to notify SCSI mid-layer to not add this LUN to the OS stack. + */ +static int +bfad_im_check_if_make_lun_visible(struct scsi_device *sdev, + struct fc_rport *rport) +{ + struct bfad_itnim_data_s *itnim_data = + (struct bfad_itnim_data_s *) rport->dd_data; + struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; + struct bfa_rport_s *bfa_rport = itnim_data->itnim->bfa_itnim->rport; + struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(bfa); + int i = 0, ret = -ENXIO; + + for (i = 0; i < MAX_LUN_MASK_CFG; i++) { + if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE && + scsilun_to_int(&lun_list[i].lun) == sdev->lun && + lun_list[i].rp_tag == bfa_rport->rport_tag && + lun_list[i].lp_tag == (u8)bfa_rport->rport_info.lp_tag) { + ret = BFA_STATUS_OK; + break; + } + } + return ret; +} + +/* * Scsi_Host template entry slave_alloc */ static int bfad_im_slave_alloc(struct scsi_device *sdev) { struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); + struct bfad_itnim_data_s *itnim_data; + struct bfa_s *bfa; if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; + itnim_data = (struct bfad_itnim_data_s *) rport->dd_data; + bfa = itnim_data->itnim->bfa_itnim->bfa; + + if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) { + /* + * We should not mask LUN 0 - since this will translate + * to no LUN / TARGET for SCSI ml resulting no scan. + */ + if (sdev->lun == 0) { + sdev->sdev_bflags |= BLIST_NOREPORTLUN | + BLIST_SPARSELUN; + goto done; + } + + /* + * Query LUN Mask configuration - to expose this LUN + * to the SCSI mid-layer or to mask it. + */ + if (bfad_im_check_if_make_lun_visible(sdev, rport) != + BFA_STATUS_OK) + return -ENXIO; + } +done: sdev->hostdata = rport->dd_data; return 0; } +u32 +bfad_im_supported_speeds(struct bfa_s *bfa) +{ + struct bfa_ioc_attr_s *ioc_attr; + u32 supported_speed = 0; + + ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL); + if (!ioc_attr) + return 0; + + bfa_ioc_get_attr(&bfa->ioc, ioc_attr); + if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_16GBPS) + supported_speed |= FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT; + else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { + if (ioc_attr->adapter_attr.is_mezz) { + supported_speed |= FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + } else { + supported_speed |= FC_PORTSPEED_8GBIT | + FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT; + } + } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) { + supported_speed |= FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | + FC_PORTSPEED_1GBIT; + } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) { + supported_speed |= FC_PORTSPEED_10GBIT; + } + kfree(ioc_attr); + return supported_speed; +} + void -bfad_os_fc_host_init(struct bfad_im_port_s *im_port) +bfad_fc_host_init(struct bfad_im_port_s *im_port) { struct Scsi_Host *host = im_port->shost; struct bfad_s *bfad = im_port->bfad; struct bfad_port_s *port = im_port->port; - struct bfa_pport_attr_s pattr; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char fw_ver[BFA_VERSION_LEN]; + char symname[BFA_SYMNAME_MAXLEN]; + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); fc_host_node_name(host) = - bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port))); + cpu_to_be64((bfa_fcs_lport_get_nwwn(port->fcs_port))); fc_host_port_name(host) = - bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port))); + cpu_to_be64((bfa_fcs_lport_get_pwwn(port->fcs_port))); fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa); fc_host_supported_classes(host) = FC_COS_CLASS3; memset(fc_host_supported_fc4s(host), 0, sizeof(fc_host_supported_fc4s(host))); - if (bfad_supported_fc4s & (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM)) + if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM) /* For FCP type 0x08 */ fc_host_supported_fc4s(host)[2] = 1; - if (bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IPFC) - /* For LLC/SNAP type 0x05 */ - fc_host_supported_fc4s(host)[3] = 0x20; /* For fibre channel services type 0x20 */ fc_host_supported_fc4s(host)[7] = 1; - bfa_get_adapter_model(&bfad->bfa, model); - bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); - sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s", - model, fw_ver, BFAD_DRIVER_VERSION); + strlcpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname, + BFA_SYMNAME_MAXLEN); + sprintf(fc_host_symbolic_name(host), "%s", symname); - fc_host_supported_speeds(host) = 0; - fc_host_supported_speeds(host) |= - FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | - FC_PORTSPEED_1GBIT; - - bfa_fcport_get_attr(&bfad->bfa, &pattr); - fc_host_maxframe_size(host) = pattr.pport_cfg.maxfrsize; + fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa); + fc_host_maxframe_size(host) = fcport->cfg.maxfrsize; } static void @@ -979,11 +1058,11 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) struct bfad_itnim_data_s *itnim_data; rport_ids.node_name = - bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim)); + cpu_to_be64(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim)); rport_ids.port_name = - bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); + cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); rport_ids.port_id = - bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim)); + bfa_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim)); rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; itnim->fc_rport = fc_rport = @@ -1008,10 +1087,12 @@ bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) && (fc_rport->scsi_target_id < MAX_FCP_TARGET)) itnim->scsi_tgt_id = fc_rport->scsi_target_id; + itnim->channel = fc_rport->channel; + return; } -/** +/* * Work queue handler using FC transport service * Context: kernel */ @@ -1044,7 +1125,9 @@ bfad_im_itnim_work_handler(struct work_struct *work) fcid2str(fcid_str, fcid); list_add_tail(&itnim->list_entry, &im_port->itnim_mapped_list); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_ONLINE, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "ITNIM ONLINE Target: %d:0:%d " + "FCID: %s WWPN: %s\n", im_port->shost->host_no, itnim->scsi_tgt_id, fcid_str, wwpn_str); @@ -1075,7 +1158,9 @@ bfad_im_itnim_work_handler(struct work_struct *work) wwn2str(wwpn_str, wwpn); fcid2str(fcid_str, fcid); list_del(&itnim->list_entry); - bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_OFFLINE, + BFA_LOG(KERN_INFO, bfad, bfa_log_level, + "ITNIM OFFLINE Target: %d:0:%d " + "FCID: %s WWPN: %s\n", im_port->shost->host_no, itnim->scsi_tgt_id, fcid_str, wwpn_str); @@ -1100,18 +1185,18 @@ bfad_im_itnim_work_handler(struct work_struct *work) kfree(itnim); break; default: - bfa_assert(0); + WARN_ON(1); break; } spin_unlock_irqrestore(&bfad->bfad_lock, flags); } -/** +/* * Scsi_Host template entry, queue a SCSI command to the BFAD. */ static int -bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) +bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) { struct bfad_im_port_s *im_port = (struct bfad_im_port_s *) cmnd->device->host->hostdata[0]; @@ -1121,7 +1206,7 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct bfa_ioim_s *hal_io; unsigned long flags; int rc; - s16 sg_cnt = 0; + int sg_cnt = 0; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); rc = fc_remote_port_chkready(rport); @@ -1131,8 +1216,16 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return 0; } - sg_cnt = scsi_dma_map(cmnd); + if (bfad->bfad_flags & BFAD_EEH_BUSY) { + if (bfad->bfad_flags & BFAD_EEH_PCI_CHANNEL_IO_PERM_FAILURE) + cmnd->result = DID_NO_CONNECT << 16; + else + cmnd->result = DID_REQUEUE << 16; + done(cmnd); + return 0; + } + sg_cnt = scsi_dma_map(cmnd); if (sg_cnt < 0) return SCSI_MLQUEUE_HOST_BUSY; @@ -1147,6 +1240,7 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_fail_cmd; } + itnim = itnim_data->itnim; if (!itnim) { cmnd->result = ScsiResult(DID_IMM_RETRY, 0); @@ -1163,7 +1257,6 @@ bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) } cmnd->host_scribble = (char *)hal_io; - bfa_trc_fp(bfad, hal_io->iotag); bfa_ioim_start(hal_io); spin_unlock_irqrestore(&bfad->bfad_lock, flags); @@ -1178,54 +1271,58 @@ out_fail_cmd: return 0; } +static DEF_SCSI_QCMD(bfad_im_queuecommand) + void -bfad_os_rport_online_wait(struct bfad_s *bfad) +bfad_rport_online_wait(struct bfad_s *bfad) { int i; int rport_delay = 10; for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE) - && i < bfa_linkup_delay; i++) - schedule_timeout_uninterruptible(HZ); + && i < bfa_linkup_delay; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } if (bfad->bfad_flags & BFAD_PORT_ONLINE) { rport_delay = rport_delay < bfa_linkup_delay ? - rport_delay : bfa_linkup_delay; + rport_delay : bfa_linkup_delay; for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE) - && i < rport_delay; i++) - schedule_timeout_uninterruptible(HZ); + && i < rport_delay; i++) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + } - if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) - schedule_timeout_uninterruptible(rport_delay * HZ); + if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(rport_delay * HZ); + } } } int -bfad_os_get_linkup_delay(struct bfad_s *bfad) +bfad_get_linkup_delay(struct bfad_s *bfad) { - - u8 nwwns = 0; - wwn_t *wwns; - int ldelay; + u8 nwwns = 0; + wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; + int linkup_delay; /* * Querying for the boot target port wwns * -- read from boot information in flash. - * If nwwns > 0 => boot over SAN and set bfa_linkup_delay = 30 - * else => local boot machine set bfa_linkup_delay = 10 + * If nwwns > 0 => boot over SAN and set linkup_delay = 30 + * else => local boot machine set linkup_delay = 0 */ - bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns); + bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns); - if (nwwns > 0) { - /* If boot over SAN; linkup_delay = 30sec */ - ldelay = 30; - } else { - /* If local boot; linkup_delay = 10sec */ - ldelay = 0; - } + if (nwwns > 0) + /* If Boot over SAN set linkup_delay = 30sec */ + linkup_delay = 30; + else + /* If local boot; no linkup_delay */ + linkup_delay = 0; - return ldelay; + return linkup_delay; } - - |
