aboutsummaryrefslogtreecommitdiff
path: root/drivers/scsi/bfa/bfad_im.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/bfa/bfad_im.c')
-rw-r--r--drivers/scsi/bfa/bfad_im.c479
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;
}
-
-