diff options
259 files changed, 58442 insertions, 666 deletions
diff --git a/Documentation/scsi/hptiop.txt b/Documentation/scsi/hptiop.txt index a6eb4add1be..9605179711f 100644 --- a/Documentation/scsi/hptiop.txt +++ b/Documentation/scsi/hptiop.txt @@ -3,6 +3,25 @@ HIGHPOINT ROCKETRAID 3xxx/4xxx ADAPTER DRIVER (hptiop)  Controller Register Map  ------------------------- +For RR44xx Intel IOP based adapters, the controller IOP is accessed via PCI BAR0 and BAR2: + +     BAR0 offset    Register +            0x11C5C Link Interface IRQ Set +            0x11C60 Link Interface IRQ Clear + +     BAR2 offset    Register +            0x10    Inbound Message Register 0 +            0x14    Inbound Message Register 1 +            0x18    Outbound Message Register 0 +            0x1C    Outbound Message Register 1 +            0x20    Inbound Doorbell Register +            0x24    Inbound Interrupt Status Register +            0x28    Inbound Interrupt Mask Register +            0x30    Outbound Interrupt Status Register +            0x34    Outbound Interrupt Mask Register +            0x40    Inbound Queue Port +            0x44    Outbound Queue Port +  For Intel IOP based adapters, the controller IOP is accessed via PCI BAR0:       BAR0 offset    Register @@ -93,7 +112,7 @@ The driver exposes following sysfs attributes:  ----------------------------------------------------------------------------- -Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. +Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.    This file is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/MAINTAINERS b/MAINTAINERS index e1da925b38c..6141bdff359 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1231,6 +1231,13 @@ L:	netdev@vger.kernel.org  S:	Supported  F:	drivers/net/tg3.* +BROCADE BFA FC SCSI DRIVER +P:      Jing Huang +M:      huangj@brocade.com +L:      linux-scsi@vger.kernel.org +S:      Supported +F:      drivers/scsi/bfa/ +  BSG (block layer generic sg v4 driver)  M:	FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>  L:	linux-scsi@vger.kernel.org @@ -4646,6 +4653,14 @@ F:	drivers/ata/  F:	include/linux/ata.h  F:	include/linux/libata.h +SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER +P:     Jayamohan Kallickal +M:     jayamohank@serverengines.com +L:     linux-scsi@vger.kernel.org +W:     http://www.serverengines.com +S:     Supported +F:     drivers/scsi/be2iscsi/ +  SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER  M:	Sathya Perla <sathyap@serverengines.com>  M:	Subbu Seetharaman <subbus@serverengines.com> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 0ba6ec87629..add9188663f 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -426,7 +426,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,  	 * because we preallocate so many resources  	 */  	cls_session = iscsi_session_setup(&iscsi_iser_transport, shost, -					  ISCSI_DEF_XMIT_CMDS_MAX, +					  ISCSI_DEF_XMIT_CMDS_MAX, 0,  					  sizeof(struct iscsi_iser_task),  					  initial_cmdsn, 0);  	if (!cls_session) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 1be6bf7e8ce..0f79f3af4f5 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -80,28 +80,35 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)  static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)  { +	struct ccw_device *ccwdev;  	struct zfcp_adapter *adapter;  	struct zfcp_port *port;  	struct zfcp_unit *unit; -	mutex_lock(&zfcp_data.config_mutex); -	read_lock_irq(&zfcp_data.config_lock); -	adapter = zfcp_get_adapter_by_busid(busid); -	if (adapter) -		zfcp_adapter_get(adapter); -	read_unlock_irq(&zfcp_data.config_lock); +	ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); +	if (!ccwdev) +		return; + +	if (ccw_device_set_online(ccwdev)) +		goto out_ccwdev; +	mutex_lock(&zfcp_data.config_mutex); +	adapter = dev_get_drvdata(&ccwdev->dev);  	if (!adapter) -		goto out_adapter; -	port = zfcp_port_enqueue(adapter, wwpn, 0, 0); -	if (IS_ERR(port)) +		goto out_unlock; +	zfcp_adapter_get(adapter); + +	port = zfcp_get_port_by_wwpn(adapter, wwpn); +	if (!port)  		goto out_port; + +	zfcp_port_get(port);  	unit = zfcp_unit_enqueue(port, lun);  	if (IS_ERR(unit))  		goto out_unit;  	mutex_unlock(&zfcp_data.config_mutex); -	ccw_device_set_online(adapter->ccw_device); +	zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);  	zfcp_erp_wait(adapter);  	flush_work(&unit->scsi_work); @@ -111,8 +118,10 @@ out_unit:  	zfcp_port_put(port);  out_port:  	zfcp_adapter_put(adapter); -out_adapter: +out_unlock:  	mutex_unlock(&zfcp_data.config_mutex); +out_ccwdev: +	put_device(&ccwdev->dev);  	return;  } @@ -593,10 +602,8 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)  	int retval = 0;  	unsigned long flags; -	cancel_work_sync(&adapter->scan_work);  	cancel_work_sync(&adapter->stat_work);  	zfcp_fc_wka_ports_force_offline(adapter->gs); -	zfcp_adapter_scsi_unregister(adapter);  	sysfs_remove_group(&adapter->ccw_device->dev.kobj,  			   &zfcp_sysfs_adapter_attrs);  	dev_set_drvdata(&adapter->ccw_device->dev, NULL); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 0c90f8e7160..e08339428ec 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -102,6 +102,14 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)  	adapter = dev_get_drvdata(&ccw_device->dev);  	if (!adapter)  		goto out; +	mutex_unlock(&zfcp_data.config_mutex); + +	cancel_work_sync(&adapter->scan_work); + +	mutex_lock(&zfcp_data.config_mutex); + +	/* this also removes the scsi devices, so call it first */ +	zfcp_adapter_scsi_unregister(adapter);  	write_lock_irq(&zfcp_data.config_lock);  	list_for_each_entry_safe(port, p, &adapter->port_list_head, list) { @@ -117,11 +125,8 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)  	write_unlock_irq(&zfcp_data.config_lock);  	list_for_each_entry_safe(port, p, &port_remove_lh, list) { -		list_for_each_entry_safe(unit, u, &unit_remove_lh, list) { -			if (unit->device) -				scsi_remove_device(unit->device); +		list_for_each_entry_safe(unit, u, &unit_remove_lh, list)  			zfcp_unit_dequeue(unit); -		}  		zfcp_port_dequeue(port);  	}  	wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0); @@ -192,13 +197,9 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)  	mutex_lock(&zfcp_data.config_mutex);  	adapter = dev_get_drvdata(&ccw_device->dev); -	if (!adapter) -		goto out; -  	zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);  	zfcp_erp_wait(adapter);  	mutex_unlock(&zfcp_data.config_mutex); -out:  	return 0;  } @@ -253,13 +254,17 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)  	mutex_lock(&zfcp_data.config_mutex);  	adapter = dev_get_drvdata(&cdev->dev); +	if (!adapter) +		goto out; +  	zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);  	zfcp_erp_wait(adapter);  	zfcp_erp_thread_kill(adapter); +out:  	mutex_unlock(&zfcp_data.config_mutex);  } -static struct ccw_driver zfcp_ccw_driver = { +struct ccw_driver zfcp_ccw_driver = {  	.owner       = THIS_MODULE,  	.name        = "zfcp",  	.ids         = zfcp_ccw_device_id, @@ -284,20 +289,3 @@ int __init zfcp_ccw_register(void)  {  	return ccw_driver_register(&zfcp_ccw_driver);  } - -/** - * zfcp_get_adapter_by_busid - find zfcp_adapter struct - * @busid: bus id string of zfcp adapter to find - */ -struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid) -{ -	struct ccw_device *ccw_device; -	struct zfcp_adapter *adapter = NULL; - -	ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); -	if (ccw_device) { -		adapter = dev_get_drvdata(&ccw_device->dev); -		put_device(&ccw_device->dev); -	} -	return adapter; -} diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 8305c874e86..ef681dfed0c 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -86,8 +86,23 @@ static int zfcp_cfdc_copy_to_user(void __user  *user_buffer,  static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)  {  	char busid[9]; +	struct ccw_device *ccwdev; +	struct zfcp_adapter *adapter = NULL; +  	snprintf(busid, sizeof(busid), "0.0.%04x", devno); -	return zfcp_get_adapter_by_busid(busid); +	ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid); +	if (!ccwdev) +		goto out; + +	adapter = dev_get_drvdata(&ccwdev->dev); +	if (!adapter) +		goto out_put; + +	zfcp_adapter_get(adapter); +out_put: +	put_device(&ccwdev->dev); +out: +	return adapter;  }  static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 36935bc0818..629edec7040 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -28,7 +28,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int);  /* zfcp_ccw.c */  extern int zfcp_ccw_register(void);  extern int zfcp_ccw_priv_sch(struct zfcp_adapter *); -extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *); +extern struct ccw_driver zfcp_ccw_driver;  /* zfcp_cfdc.c */  extern struct miscdevice zfcp_cfdc_misc; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f09c863dc6b..38a7e4a6b63 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1058,11 +1058,25 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,  	bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,  					SBAL_FLAGS0_TYPE_WRITE_READ,  					sg_resp, max_sbals); +	req->qtcb->bottom.support.resp_buf_length = bytes;  	if (bytes <= 0)  		return -EIO; +	return 0; +} + +static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, +				 struct scatterlist *sg_req, +				 struct scatterlist *sg_resp, +				 int max_sbals) +{ +	int ret; + +	ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals); +	if (ret) +		return ret; +  	/* common settings for ct/gs and els requests */ -	req->qtcb->bottom.support.resp_buf_length = bytes;  	req->qtcb->bottom.support.service_class = FSF_CLASS_3;  	req->qtcb->bottom.support.timeout = 2 * R_A_TOV;  	zfcp_fsf_start_timer(req, 2 * R_A_TOV + 10); @@ -1094,8 +1108,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, -					  FSF_MAX_SBALS_PER_REQ); +	ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, +				    FSF_MAX_SBALS_PER_REQ);  	if (ret)  		goto failed_send; @@ -1192,7 +1206,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)  	}  	req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; -	ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); +	ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2);  	if (ret)  		goto failed_send; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 82bb3b2d207..e11cca4c784 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -366,6 +366,7 @@ config ISCSI_TCP  source "drivers/scsi/cxgb3i/Kconfig"  source "drivers/scsi/bnx2i/Kconfig" +source "drivers/scsi/be2iscsi/Kconfig"  config SGIWD93_SCSI  	tristate "SGI WD93C93 SCSI Driver" @@ -1827,6 +1828,16 @@ config SCSI_SRP  	  To compile this driver as a module, choose M here: the  	  module will be called libsrp. +config SCSI_BFA_FC +	tristate "Brocade BFA Fibre Channel Support" +	depends on PCI && SCSI +	select SCSI_FC_ATTRS +	help +	  This bfa driver supports all Brocade PCIe FC/FCOE host adapters. + +	  To compile this driver as a module, choose M here. The module will +	  be called bfa. +  endif # SCSI_LOWLEVEL  source "drivers/scsi/pcmcia/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 61a94af3cee..3ad61db5e3f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o  obj-$(CONFIG_SCSI_QLA_FC)	+= qla2xxx/  obj-$(CONFIG_SCSI_QLA_ISCSI)	+= qla4xxx/  obj-$(CONFIG_SCSI_LPFC)		+= lpfc/ +obj-$(CONFIG_SCSI_BFA_FC)	+= bfa/  obj-$(CONFIG_SCSI_PAS16)	+= pas16.o  obj-$(CONFIG_SCSI_T128)		+= t128.o  obj-$(CONFIG_SCSI_DMX3191D)	+= dmx3191d.o @@ -130,6 +131,7 @@ obj-$(CONFIG_SCSI_MVSAS)	+= mvsas/  obj-$(CONFIG_PS3_ROM)		+= ps3rom.o  obj-$(CONFIG_SCSI_CXGB3_ISCSI)	+= libiscsi.o libiscsi_tcp.o cxgb3i/  obj-$(CONFIG_SCSI_BNX2_ISCSI)	+= libiscsi.o bnx2i/ +obj-$(CONFIG_BE2ISCSI)		+= libiscsi.o be2iscsi/  obj-$(CONFIG_SCSI_PMCRAID)	+= pmcraid.o  obj-$(CONFIG_ARM)		+= arm/ diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig new file mode 100644 index 00000000000..2952fcd008e --- /dev/null +++ b/drivers/scsi/be2iscsi/Kconfig @@ -0,0 +1,8 @@ +config BE2ISCSI +	tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" +	depends on PCI && SCSI +	select SCSI_ISCSI_ATTRS + +	help +	This driver implements the iSCSI functionality for ServerEngines' +	10Gbps Storage adapter - BladeEngine 2. diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile new file mode 100644 index 00000000000..c11f443e3f8 --- /dev/null +++ b/drivers/scsi/be2iscsi/Makefile @@ -0,0 +1,8 @@ +# +# Makefile to build the iSCSI driver for ServerEngine's BladeEngine. +# +# + +obj-$(CONFIG_BE2ISCSI) += be2iscsi.o + +be2iscsi-y := be_iscsi.o be_main.o be_mgmt.o be_cmds.o diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h new file mode 100644 index 00000000000..b36020dcf01 --- /dev/null +++ b/drivers/scsi/be2iscsi/be.h @@ -0,0 +1,183 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + */ + +#ifndef BEISCSI_H +#define BEISCSI_H + +#include <linux/pci.h> +#include <linux/if_vlan.h> + +#define FW_VER_LEN 32 + +struct be_dma_mem { +	void *va; +	dma_addr_t dma; +	u32 size; +}; + +struct be_queue_info { +	struct be_dma_mem dma_mem; +	u16 len; +	u16 entry_size;		/* Size of an element in the queue */ +	u16 id; +	u16 tail, head; +	bool created; +	atomic_t used;		/* Number of valid elements in the queue */ +}; + +static inline u32 MODULO(u16 val, u16 limit) +{ +	WARN_ON(limit & (limit - 1)); +	return val & (limit - 1); +} + +static inline void index_inc(u16 *index, u16 limit) +{ +	*index = MODULO((*index + 1), limit); +} + +static inline void *queue_head_node(struct be_queue_info *q) +{ +	return q->dma_mem.va + q->head * q->entry_size; +} + +static inline void *queue_tail_node(struct be_queue_info *q) +{ +	return q->dma_mem.va + q->tail * q->entry_size; +} + +static inline void queue_head_inc(struct be_queue_info *q) +{ +	index_inc(&q->head, q->len); +} + +static inline void queue_tail_inc(struct be_queue_info *q) +{ +	index_inc(&q->tail, q->len); +} + +/*ISCSI */ + +struct be_eq_obj { +	struct be_queue_info q; +	char desc[32]; + +	/* Adaptive interrupt coalescing (AIC) info */ +	bool enable_aic; +	u16 min_eqd;		/* in usecs */ +	u16 max_eqd;		/* in usecs */ +	u16 cur_eqd;		/* in usecs */ +}; + +struct be_mcc_obj { +	struct be_queue_info *q; +	struct be_queue_info *cq; +}; + +struct be_ctrl_info { +	u8 __iomem *csr; +	u8 __iomem *db;		/* Door Bell */ +	u8 __iomem *pcicfg;	/* PCI config space */ +	struct pci_dev *pdev; + +	/* Mbox used for cmd request/response */ +	spinlock_t mbox_lock;	/* For serializing mbox cmds to BE card */ +	struct be_dma_mem mbox_mem; +	/* Mbox mem is adjusted to align to 16 bytes. The allocated addr +	 * is stored for freeing purpose */ +	struct be_dma_mem mbox_mem_alloced; + +	/* MCC Rings */ +	struct be_mcc_obj mcc_obj; +	spinlock_t mcc_lock;	/* For serializing mcc cmds to BE card */ +	spinlock_t mcc_cq_lock; + +	/* MCC Async callback */ +	void (*async_cb) (void *adapter, bool link_up); +	void *adapter_ctxt; +}; + +#include "be_cmds.h" + +#define PAGE_SHIFT_4K 12 +#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) + +/* Returns number of pages spanned by the data starting at the given addr */ +#define PAGES_4K_SPANNED(_address, size) 				\ +		((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + 	\ +			(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) + +/* Byte offset into the page corresponding to given address */ +#define OFFSET_IN_PAGE(addr)						\ +		((size_t)(addr) & (PAGE_SIZE_4K-1)) + +/* Returns bit offset within a DWORD of a bitfield */ +#define AMAP_BIT_OFFSET(_struct, field)  				\ +		(((size_t)&(((_struct *)0)->field))%32) + +/* Returns the bit mask of the field that is NOT shifted into location. */ +static inline u32 amap_mask(u32 bitsize) +{ +	return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1); +} + +static inline void amap_set(void *ptr, u32 dw_offset, u32 mask, +					u32 offset, u32 value) +{ +	u32 *dw = (u32 *) ptr + dw_offset; +	*dw &= ~(mask << offset); +	*dw |= (mask & value) << offset; +} + +#define AMAP_SET_BITS(_struct, field, ptr, val)				\ +		amap_set(ptr,						\ +			offsetof(_struct, field)/32,			\ +			amap_mask(sizeof(((_struct *)0)->field)),	\ +			AMAP_BIT_OFFSET(_struct, field),		\ +			val) + +static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset) +{ +	u32 *dw = ptr; +	return mask & (*(dw + dw_offset) >> offset); +} + +#define AMAP_GET_BITS(_struct, field, ptr)				\ +		amap_get(ptr,						\ +			offsetof(_struct, field)/32,			\ +			amap_mask(sizeof(((_struct *)0)->field)),	\ +			AMAP_BIT_OFFSET(_struct, field)) + +#define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len) +#define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len) +static inline void swap_dws(void *wrb, int len) +{ +#ifdef __BIG_ENDIAN +	u32 *dw = wrb; +	WARN_ON(len % 4); +	do { +		*dw = cpu_to_le32(*dw); +		dw++; +		len -= 4; +	} while (len); +#endif /* __BIG_ENDIAN */ +} + +extern void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, +			      u16 num_popped); + +#endif /* BEISCSI_H */ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c new file mode 100644 index 00000000000..08007b6e42d --- /dev/null +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -0,0 +1,523 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + */ + +#include "be.h" +#include "be_mgmt.h" +#include "be_main.h" + +static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) +{ +	if (compl->flags != 0) { +		compl->flags = le32_to_cpu(compl->flags); +		WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0); +		return true; +	} else +		return false; +} + +static inline void be_mcc_compl_use(struct be_mcc_compl *compl) +{ +	compl->flags = 0; +} + +static int be_mcc_compl_process(struct be_ctrl_info *ctrl, +				struct be_mcc_compl *compl) +{ +	u16 compl_status, extd_status; + +	be_dws_le_to_cpu(compl, 4); + +	compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & +					CQE_STATUS_COMPL_MASK; +	if (compl_status != MCC_STATUS_SUCCESS) { +		extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & +						CQE_STATUS_EXTD_MASK; +		dev_err(&ctrl->pdev->dev, +			"error in cmd completion: status(compl/extd)=%d/%d\n", +			compl_status, extd_status); +		return -1; +	} +	return 0; +} + +static inline bool is_link_state_evt(u32 trailer) +{ +	return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & +		ASYNC_TRAILER_EVENT_CODE_MASK) == ASYNC_EVENT_CODE_LINK_STATE); +} + +void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm, +		       u16 num_popped) +{ +	u32 val = 0; +	val |= qid & DB_CQ_RING_ID_MASK; +	if (arm) +		val |= 1 << DB_CQ_REARM_SHIFT; +	val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; +	iowrite32(val, ctrl->db + DB_CQ_OFFSET); +} + +static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl) +{ +#define long_delay 2000 +	void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; +	int cnt = 0, wait = 5;	/* in usecs */ +	u32 ready; + +	do { +		ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK; +		if (ready) +			break; + +		if (cnt > 6000000) { +			dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n"); +			return -1; +		} + +		if (cnt > 50) { +			wait = long_delay; +			mdelay(long_delay / 1000); +		} else +			udelay(wait); +		cnt += wait; +	} while (true); +	return 0; +} + +int be_mbox_notify(struct be_ctrl_info *ctrl) +{ +	int status; +	u32 val = 0; +	void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; +	struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; +	struct be_mcc_mailbox *mbox = mbox_mem->va; +	struct be_mcc_compl *compl = &mbox->compl; + +	val &= ~MPU_MAILBOX_DB_RDY_MASK; +	val |= MPU_MAILBOX_DB_HI_MASK; +	val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; +	iowrite32(val, db); + +	status = be_mbox_db_ready_wait(ctrl); +	if (status != 0) { +		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n"); +		return status; +	} +	val = 0; +	val &= ~MPU_MAILBOX_DB_RDY_MASK; +	val &= ~MPU_MAILBOX_DB_HI_MASK; +	val |= (u32) (mbox_mem->dma >> 4) << 2; +	iowrite32(val, db); + +	status = be_mbox_db_ready_wait(ctrl); +	if (status != 0) { +		SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n"); +		return status; +	} +	if (be_mcc_compl_is_new(compl)) { +		status = be_mcc_compl_process(ctrl, &mbox->compl); +		be_mcc_compl_use(compl); +		if (status) { +			SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n"); +			return status; +		} +	} else { +		dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n"); +		return -1; +	} +	return 0; +} + +void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, +				bool embedded, u8 sge_cnt) +{ +	if (embedded) +		wrb->embedded |= MCC_WRB_EMBEDDED_MASK; +	else +		wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << +						MCC_WRB_SGE_CNT_SHIFT; +	wrb->payload_length = payload_len; +	be_dws_cpu_to_le(wrb, 8); +} + +void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, +			u8 subsystem, u8 opcode, int cmd_len) +{ +	req_hdr->opcode = opcode; +	req_hdr->subsystem = subsystem; +	req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); +} + +static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, +							struct be_dma_mem *mem) +{ +	int i, buf_pages; +	u64 dma = (u64) mem->dma; + +	buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); +	for (i = 0; i < buf_pages; i++) { +		pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); +		pages[i].hi = cpu_to_le32(upper_32_bits(dma)); +		dma += PAGE_SIZE_4K; +	} +} + +static u32 eq_delay_to_mult(u32 usec_delay) +{ +#define MAX_INTR_RATE 651042 +	const u32 round = 10; +	u32 multiplier; + +	if (usec_delay == 0) +		multiplier = 0; +	else { +		u32 interrupt_rate = 1000000 / usec_delay; +		if (interrupt_rate == 0) +			multiplier = 1023; +		else { +			multiplier = (MAX_INTR_RATE - interrupt_rate) * round; +			multiplier /= interrupt_rate; +			multiplier = (multiplier + round / 2) / round; +			multiplier = min(multiplier, (u32) 1023); +		} +	} +	return multiplier; +} + +struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem) +{ +	return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; +} + +int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, +			  struct be_queue_info *eq, int eq_delay) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_cmd_req_eq_create *req = embedded_payload(wrb); +	struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); +	struct be_dma_mem *q_mem = &eq->dma_mem; +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +			OPCODE_COMMON_EQ_CREATE, sizeof(*req)); + +	req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + +	AMAP_SET_BITS(struct amap_eq_context, func, req->context, +						PCI_FUNC(ctrl->pdev->devfn)); +	AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); +	AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); +	AMAP_SET_BITS(struct amap_eq_context, count, req->context, +					__ilog2_u32(eq->len / 256)); +	AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context, +					eq_delay_to_mult(eq_delay)); +	be_dws_cpu_to_le(req->context, sizeof(req->context)); + +	be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		eq->id = le16_to_cpu(resp->eq_id); +		eq->created = true; +	} +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int be_cmd_fw_initialize(struct be_ctrl_info *ctrl) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	int status; +	u8 *endian_check; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	endian_check = (u8 *) wrb; +	*endian_check++ = 0xFF; +	*endian_check++ = 0x12; +	*endian_check++ = 0x34; +	*endian_check++ = 0xFF; +	*endian_check++ = 0xFF; +	*endian_check++ = 0x56; +	*endian_check++ = 0x78; +	*endian_check++ = 0xFF; +	be_dws_cpu_to_le(wrb, sizeof(*wrb)); + +	status = be_mbox_notify(ctrl); +	if (status) +		SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n"); + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, +			  struct be_queue_info *cq, struct be_queue_info *eq, +			  bool sol_evts, bool no_delay, int coalesce_wm) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_cmd_req_cq_create *req = embedded_payload(wrb); +	struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); +	struct be_dma_mem *q_mem = &cq->dma_mem; +	void *ctxt = &req->context; +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +			OPCODE_COMMON_CQ_CREATE, sizeof(*req)); + +	if (!q_mem->va) +		SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n"); + +	req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + +	AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm); +	AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay); +	AMAP_SET_BITS(struct amap_cq_context, count, ctxt, +		      __ilog2_u32(cq->len / 256)); +	AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1); +	AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts); +	AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); +	AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); +	AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); +	AMAP_SET_BITS(struct amap_cq_context, func, ctxt, +		      PCI_FUNC(ctrl->pdev->devfn)); +	be_dws_cpu_to_le(ctxt, sizeof(req->context)); + +	be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		cq->id = le16_to_cpu(resp->cq_id); +		cq->created = true; +	} else +		SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n", +			status); +	spin_unlock(&ctrl->mbox_lock); + +	return status; +} + +static u32 be_encoded_q_len(int q_len) +{ +	u32 len_encoded = fls(q_len);	/* log2(len) + 1 */ +	if (len_encoded == 16) +		len_encoded = 0; +	return len_encoded; +} +int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +			  int queue_type) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_cmd_req_q_destroy *req = embedded_payload(wrb); +	u8 subsys = 0, opcode = 0; +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	switch (queue_type) { +	case QTYPE_EQ: +		subsys = CMD_SUBSYSTEM_COMMON; +		opcode = OPCODE_COMMON_EQ_DESTROY; +		break; +	case QTYPE_CQ: +		subsys = CMD_SUBSYSTEM_COMMON; +		opcode = OPCODE_COMMON_CQ_DESTROY; +		break; +	case QTYPE_WRBQ: +		subsys = CMD_SUBSYSTEM_ISCSI; +		opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY; +		break; +	case QTYPE_DPDUQ: +		subsys = CMD_SUBSYSTEM_ISCSI; +		opcode = OPCODE_COMMON_ISCSI_DEFQ_DESTROY; +		break; +	case QTYPE_SGL: +		subsys = CMD_SUBSYSTEM_ISCSI; +		opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES; +		break; +	default: +		spin_unlock(&ctrl->mbox_lock); +		BUG(); +		return -1; +	} +	be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); +	if (queue_type != QTYPE_SGL) +		req->id = cpu_to_le16(q->id); + +	status = be_mbox_notify(ctrl); + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb); +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +			   OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, +			   sizeof(*req)); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb); + +		memcpy(mac_addr, resp->mac_address, ETH_ALEN); +	} + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl, +				    struct be_queue_info *cq, +				    struct be_queue_info *dq, int length, +				    int entry_size) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_defq_create_req *req = embedded_payload(wrb); +	struct be_dma_mem *q_mem = &dq->dma_mem; +	void *ctxt = &req->context; +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +			   OPCODE_COMMON_ISCSI_DEFQ_CREATE, sizeof(*req)); + +	req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid, ctxt, 0); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid_valid, ctxt, +		      1); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, pci_func_id, ctxt, +		      PCI_FUNC(ctrl->pdev->devfn)); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, ring_size, ctxt, +		      be_encoded_q_len(length / sizeof(struct phys_addr))); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, default_buffer_size, +		      ctxt, entry_size); +	AMAP_SET_BITS(struct amap_be_default_pdu_context, cq_id_recv, ctxt, +		      cq->id); + +	be_dws_cpu_to_le(ctxt, sizeof(req->context)); + +	be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		struct be_defq_create_resp *resp = embedded_payload(wrb); + +		dq->id = le16_to_cpu(resp->id); +		dq->created = true; +	} +	spin_unlock(&ctrl->mbox_lock); + +	return status; +} + +int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, +		       struct be_queue_info *wrbq) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_wrbq_create_req *req = embedded_payload(wrb); +	struct be_wrbq_create_resp *resp = embedded_payload(wrb); +	int status; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +		OPCODE_COMMON_ISCSI_WRBQ_CREATE, sizeof(*req)); +	req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); +	be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + +	status = be_mbox_notify(ctrl); +	if (!status) +		wrbq->id = le16_to_cpu(resp->cid); +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, +				struct be_dma_mem *q_mem, +				u32 page_offset, u32 num_pages) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_post_sgl_pages_req *req = embedded_payload(wrb); +	int status; +	unsigned int curr_pages; +	u32 internal_page_offset = 0; +	u32 temp_num_pages = num_pages; + +	if (num_pages == 0xff) +		num_pages = 1; + +	spin_lock(&ctrl->mbox_lock); +	do { +		memset(wrb, 0, sizeof(*wrb)); +		be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +		be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +				   OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES, +				   sizeof(*req)); +		curr_pages = BE_NUMBER_OF_FIELD(struct be_post_sgl_pages_req, +						pages); +		req->num_pages = min(num_pages, curr_pages); +		req->page_offset = page_offset; +		be_cmd_page_addrs_prepare(req->pages, req->num_pages, q_mem); +		q_mem->dma = q_mem->dma + (req->num_pages * PAGE_SIZE); +		internal_page_offset += req->num_pages; +		page_offset += req->num_pages; +		num_pages -= req->num_pages; + +		if (temp_num_pages == 0xff) +			req->num_pages = temp_num_pages; + +		status = be_mbox_notify(ctrl); +		if (status) { +			SE_DEBUG(DBG_LVL_1, +				 "FW CMD to map iscsi frags failed.\n"); +			goto error; +		} +	} while (num_pages > 0); +error: +	spin_unlock(&ctrl->mbox_lock); +	if (status != 0) +		beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); +	return status; +} diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h new file mode 100644 index 00000000000..c20d686cbb4 --- /dev/null +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -0,0 +1,877 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + */ + +#ifndef BEISCSI_CMDS_H +#define BEISCSI_CMDS_H + +/** + * The driver sends configuration and managements command requests to the + * firmware in the BE. These requests are communicated to the processor + * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one + * WRB inside a MAILBOX. + * The commands are serviced by the ARM processor in the BladeEngine's MPU. + */ +struct be_sge { +	u32 pa_lo; +	u32 pa_hi; +	u32 len; +}; + +#define MCC_WRB_SGE_CNT_SHIFT 3	/* bits 3 - 7 of dword 0 */ +#define MCC_WRB_SGE_CNT_MASK 0x1F	/* bits 3 - 7 of dword 0 */ +struct be_mcc_wrb { +	u32 embedded;		/* dword 0 */ +	u32 payload_length;	/* dword 1 */ +	u32 tag0;		/* dword 2 */ +	u32 tag1;		/* dword 3 */ +	u32 rsvd;		/* dword 4 */ +	union { +		u8 embedded_payload[236];	/* used by embedded cmds */ +		struct be_sge sgl[19];	/* used by non-embedded cmds */ +	} payload; +}; + +#define CQE_FLAGS_VALID_MASK (1 << 31) +#define CQE_FLAGS_ASYNC_MASK (1 << 30) + +/* Completion Status */ +#define MCC_STATUS_SUCCESS 0x0 + +#define CQE_STATUS_COMPL_MASK 0xFFFF +#define CQE_STATUS_COMPL_SHIFT 0	/* bits 0 - 15 */ +#define CQE_STATUS_EXTD_MASK 0xFFFF +#define CQE_STATUS_EXTD_SHIFT 0		/* bits 0 - 15 */ + +struct be_mcc_compl { +	u32 status;		/* dword 0 */ +	u32 tag0;		/* dword 1 */ +	u32 tag1;		/* dword 2 */ +	u32 flags;		/* dword 3 */ +}; + +/********* Mailbox door bell *************/ +/** + * Used for driver communication with the FW. + * The software must write this register twice to post any command. First, + * it writes the register with hi=1 and the upper bits of the physical address + * for the MAILBOX structure. Software must poll the ready bit until this + * is acknowledged. Then, sotware writes the register with hi=0 with the lower + * bits in the address. It must poll the ready bit until the command is + * complete. Upon completion, the MAILBOX will contain a valid completion + * queue entry. + */ +#define MPU_MAILBOX_DB_OFFSET	0x160 +#define MPU_MAILBOX_DB_RDY_MASK	0x1	/* bit 0 */ +#define MPU_MAILBOX_DB_HI_MASK	0x2	/* bit 1 */ + +/********** MPU semphore ******************/ +#define MPU_EP_SEMAPHORE_OFFSET 0xac +#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF +#define EP_SEMAPHORE_POST_ERR_MASK 0x1 +#define EP_SEMAPHORE_POST_ERR_SHIFT 31 + +/********** MCC door bell ************/ +#define DB_MCCQ_OFFSET 0x140 +#define DB_MCCQ_RING_ID_MASK 0x7FF		/* bits 0 - 10 */ +/* Number of entries posted */ +#define DB_MCCQ_NUM_POSTED_SHIFT 16		/* bits 16 - 29 */ + +/* MPU semphore POST stage values */ +#define POST_STAGE_ARMFW_RDY		0xc000	/* FW is done with POST */ + +/** + * When the async bit of mcc_compl is set, the last 4 bytes of + * mcc_compl is interpreted as follows: + */ +#define ASYNC_TRAILER_EVENT_CODE_SHIFT	8	/* bits 8 - 15 */ +#define ASYNC_TRAILER_EVENT_CODE_MASK	0xFF +#define ASYNC_EVENT_CODE_LINK_STATE	0x1 +struct be_async_event_trailer { +	u32 code; +}; + +enum { +	ASYNC_EVENT_LINK_DOWN = 0x0, +	ASYNC_EVENT_LINK_UP = 0x1 +}; + +/** + * When the event code of an async trailer is link-state, the mcc_compl + * must be interpreted as follows + */ +struct be_async_event_link_state { +	u8 physical_port; +	u8 port_link_status; +	u8 port_duplex; +	u8 port_speed; +	u8 port_fault; +	u8 rsvd0[7]; +	struct be_async_event_trailer trailer; +} __packed; + +struct be_mcc_mailbox { +	struct be_mcc_wrb wrb; +	struct be_mcc_compl compl; +}; + +/* Type of subsystems supported by FW */ +#define CMD_SUBSYSTEM_COMMON    0x1 +#define CMD_SUBSYSTEM_ISCSI     0x2 +#define CMD_SUBSYSTEM_ETH       0x3 +#define CMD_SUBSYSTEM_ISCSI_INI 0x6 +#define CMD_COMMON_TCP_UPLOAD   0x1 + +/** + * List of common opcodes subsystem  CMD_SUBSYSTEM_COMMON + * These opcodes are unique for each subsystem defined above + */ +#define OPCODE_COMMON_CQ_CREATE				12 +#define OPCODE_COMMON_EQ_CREATE				13 +#define OPCODE_COMMON_MCC_CREATE        		21 +#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES               32 +#define OPCODE_COMMON_GET_FW_VERSION			35 +#define OPCODE_COMMON_MODIFY_EQ_DELAY			41 +#define OPCODE_COMMON_FIRMWARE_CONFIG			42 +#define OPCODE_COMMON_MCC_DESTROY        		53 +#define OPCODE_COMMON_CQ_DESTROY        		54 +#define OPCODE_COMMON_EQ_DESTROY        		55 +#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG		58 +#define OPCODE_COMMON_FUNCTION_RESET			61 + +/** + * LIST of opcodes that are common between Initiator and Target + * used by CMD_SUBSYSTEM_ISCSI + * These opcodes are unique for each subsystem defined above + */ +#define OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES		2 +#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES        3 +#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG		7 +#define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61 +#define OPCODE_COMMON_ISCSI_DEFQ_CREATE                 64 +#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 		65 +#define OPCODE_COMMON_ISCSI_WRBQ_CREATE			66 +#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 		67 + +struct be_cmd_req_hdr { +	u8 opcode;		/* dword 0 */ +	u8 subsystem;		/* dword 0 */ +	u8 port_number;		/* dword 0 */ +	u8 domain;		/* dword 0 */ +	u32 timeout;		/* dword 1 */ +	u32 request_length;	/* dword 2 */ +	u32 rsvd;		/* dword 3 */ +}; + +struct be_cmd_resp_hdr { +	u32 info;		/* dword 0 */ +	u32 status;		/* dword 1 */ +	u32 response_length;	/* dword 2 */ +	u32 actual_resp_len;	/* dword 3 */ +}; + +struct phys_addr { +	u32 lo; +	u32 hi; +}; + +/************************** + * BE Command definitions * + **************************/ + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte - used to calculate offset/shift/mask of each field + */ +struct amap_eq_context { +	u8 cidx[13];		/* dword 0 */ +	u8 rsvd0[3];		/* dword 0 */ +	u8 epidx[13];		/* dword 0 */ +	u8 valid;		/* dword 0 */ +	u8 rsvd1;		/* dword 0 */ +	u8 size;		/* dword 0 */ +	u8 pidx[13];		/* dword 1 */ +	u8 rsvd2[3];		/* dword 1 */ +	u8 pd[10];		/* dword 1 */ +	u8 count[3];		/* dword 1 */ +	u8 solevent;		/* dword 1 */ +	u8 stalled;		/* dword 1 */ +	u8 armed;		/* dword 1 */ +	u8 rsvd3[4];		/* dword 2 */ +	u8 func[8];		/* dword 2 */ +	u8 rsvd4;		/* dword 2 */ +	u8 delaymult[10];	/* dword 2 */ +	u8 rsvd5[2];		/* dword 2 */ +	u8 phase[2];		/* dword 2 */ +	u8 nodelay;		/* dword 2 */ +	u8 rsvd6[4];		/* dword 2 */ +	u8 rsvd7[32];		/* dword 3 */ +} __packed; + +struct be_cmd_req_eq_create { +	struct be_cmd_req_hdr hdr;	/* dw[4] */ +	u16 num_pages;		/* sword */ +	u16 rsvd0;		/* sword */ +	u8 context[sizeof(struct amap_eq_context) / 8];	/* dw[4] */ +	struct phys_addr pages[8]; +} __packed; + +struct be_cmd_resp_eq_create { +	struct be_cmd_resp_hdr resp_hdr; +	u16 eq_id;		/* sword */ +	u16 rsvd0;		/* sword */ +} __packed; + +struct mac_addr { +	u16 size_of_struct; +	u8 addr[ETH_ALEN]; +} __packed; + +struct be_cmd_req_mac_query { +	struct be_cmd_req_hdr hdr; +	u8 type; +	u8 permanent; +	u16 if_id; +} __packed; + +struct be_cmd_resp_mac_query { +	struct be_cmd_resp_hdr hdr; +	struct mac_addr mac; +}; + +/******************** Create CQ ***************************/ +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte - used to calculate offset/shift/mask of each field + */ +struct amap_cq_context { +	u8 cidx[11];		/* dword 0 */ +	u8 rsvd0;		/* dword 0 */ +	u8 coalescwm[2];	/* dword 0 */ +	u8 nodelay;		/* dword 0 */ +	u8 epidx[11];		/* dword 0 */ +	u8 rsvd1;		/* dword 0 */ +	u8 count[2];		/* dword 0 */ +	u8 valid;		/* dword 0 */ +	u8 solevent;		/* dword 0 */ +	u8 eventable;		/* dword 0 */ +	u8 pidx[11];		/* dword 1 */ +	u8 rsvd2;		/* dword 1 */ +	u8 pd[10];		/* dword 1 */ +	u8 eqid[8];		/* dword 1 */ +	u8 stalled;		/* dword 1 */ +	u8 armed;		/* dword 1 */ +	u8 rsvd3[4];		/* dword 2 */ +	u8 func[8];		/* dword 2 */ +	u8 rsvd4[20];		/* dword 2 */ +	u8 rsvd5[32];		/* dword 3 */ +} __packed; + +struct be_cmd_req_cq_create { +	struct be_cmd_req_hdr hdr; +	u16 num_pages; +	u16 rsvd0; +	u8 context[sizeof(struct amap_cq_context) / 8]; +	struct phys_addr pages[4]; +} __packed; + +struct be_cmd_resp_cq_create { +	struct be_cmd_resp_hdr hdr; +	u16 cq_id; +	u16 rsvd0; +} __packed; + +/******************** Create MCCQ ***************************/ +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte - used to calculate offset/shift/mask of each field + */ +struct amap_mcc_context { +	u8 con_index[14]; +	u8 rsvd0[2]; +	u8 ring_size[4]; +	u8 fetch_wrb; +	u8 fetch_r2t; +	u8 cq_id[10]; +	u8 prod_index[14]; +	u8 fid[8]; +	u8 pdid[9]; +	u8 valid; +	u8 rsvd1[32]; +	u8 rsvd2[32]; +} __packed; + +struct be_cmd_req_mcc_create { +	struct be_cmd_req_hdr hdr; +	u16 num_pages; +	u16 rsvd0; +	u8 context[sizeof(struct amap_mcc_context) / 8]; +	struct phys_addr pages[8]; +} __packed; + +struct be_cmd_resp_mcc_create { +	struct be_cmd_resp_hdr hdr; +	u16 id; +	u16 rsvd0; +} __packed; + +/******************** Q Destroy  ***************************/ +/* Type of Queue to be destroyed */ +enum { +	QTYPE_EQ = 1, +	QTYPE_CQ, +	QTYPE_MCCQ, +	QTYPE_WRBQ, +	QTYPE_DPDUQ, +	QTYPE_SGL +}; + +struct be_cmd_req_q_destroy { +	struct be_cmd_req_hdr hdr; +	u16 id; +	u16 bypass_flush;	/* valid only for rx q destroy */ +} __packed; + +struct macaddr { +	u8 byte[ETH_ALEN]; +}; + +struct be_cmd_req_mcast_mac_config { +	struct be_cmd_req_hdr hdr; +	u16 num_mac; +	u8 promiscuous; +	u8 interface_id; +	struct macaddr mac[32]; +} __packed; + +static inline void *embedded_payload(struct be_mcc_wrb *wrb) +{ +	return wrb->payload.embedded_payload; +} + +static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) +{ +	return &wrb->payload.sgl[0]; +} + +/******************** Modify EQ Delay *******************/ +struct be_cmd_req_modify_eq_delay { +	struct be_cmd_req_hdr hdr; +	u32 num_eq; +	struct { +		u32 eq_id; +		u32 phase; +		u32 delay_multiplier; +	} delay[8]; +} __packed; + +/******************** Get MAC ADDR *******************/ + +#define ETH_ALEN	6 + + +struct be_cmd_req_get_mac_addr { +	struct be_cmd_req_hdr hdr; +	u32 nic_port_count; +	u32 speed; +	u32 max_speed; +	u32 link_state; +	u32 max_frame_size; +	u16 size_of_structure; +	u8 mac_address[ETH_ALEN]; +	u32 rsvd[23]; +}; + +struct be_cmd_resp_get_mac_addr { +	struct be_cmd_resp_hdr hdr; +	u32 nic_port_count; +	u32 speed; +	u32 max_speed; +	u32 link_state; +	u32 max_frame_size; +	u16 size_of_structure; +	u8 mac_address[6]; +	u32 rsvd[23]; +}; + +int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, +			  struct be_queue_info *eq, int eq_delay); + +int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, +			  struct be_queue_info *cq, struct be_queue_info *eq, +			  bool sol_evts, bool no_delay, +			  int num_cqe_dma_coalesce); + +int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, +			  int type); +int be_poll_mcc(struct be_ctrl_info *ctrl); +unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl); +int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr); + +/*ISCSI Functuions */ +int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); + +struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); + +int be_mbox_notify(struct be_ctrl_info *ctrl); + +int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl, +				    struct be_queue_info *cq, +				    struct be_queue_info *dq, int length, +				    int entry_size); + +int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, +				struct be_dma_mem *q_mem, u32 page_offset, +				u32 num_pages); + +int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, +		       struct be_queue_info *wrbq); + +struct be_default_pdu_context { +	u32 dw[4]; +} __packed; + +struct amap_be_default_pdu_context { +	u8 dbuf_cindex[13];	/* dword 0 */ +	u8 rsvd0[3];		/* dword 0 */ +	u8 ring_size[4];	/* dword 0 */ +	u8 ring_state[4];	/* dword 0 */ +	u8 rsvd1[8];		/* dword 0 */ +	u8 dbuf_pindex[13];	/* dword 1 */ +	u8 rsvd2;		/* dword 1 */ +	u8 pci_func_id[8];	/* dword 1 */ +	u8 rx_pdid[9];		/* dword 1 */ +	u8 rx_pdid_valid;	/* dword 1 */ +	u8 default_buffer_size[16];	/* dword 2 */ +	u8 cq_id_recv[10];	/* dword 2 */ +	u8 rx_pdid_not_valid;	/* dword 2 */ +	u8 rsvd3[5];		/* dword 2 */ +	u8 rsvd4[32];		/* dword 3 */ +} __packed; + +struct be_defq_create_req { +	struct be_cmd_req_hdr hdr; +	u16 num_pages; +	u8 ulp_num; +	u8 rsvd0; +	struct be_default_pdu_context context; +	struct phys_addr pages[8]; +} __packed; + +struct be_defq_create_resp { +	struct be_cmd_req_hdr hdr; +	u16 id; +	u16 rsvd0; +} __packed; + +struct be_post_sgl_pages_req { +	struct be_cmd_req_hdr hdr; +	u16 num_pages; +	u16 page_offset; +	u32 rsvd0; +	struct phys_addr pages[26]; +	u32 rsvd1; +} __packed; + +struct be_wrbq_create_req { +	struct be_cmd_req_hdr hdr; +	u16 num_pages; +	u8 ulp_num; +	u8 rsvd0; +	struct phys_addr pages[8]; +} __packed; + +struct be_wrbq_create_resp { +	struct be_cmd_resp_hdr resp_hdr; +	u16 cid; +	u16 rsvd0; +} __packed; + +#define SOL_CID_MASK		0x0000FFC0 +#define SOL_CODE_MASK		0x0000003F +#define SOL_WRB_INDEX_MASK	0x00FF0000 +#define SOL_CMD_WND_MASK	0xFF000000 +#define SOL_RES_CNT_MASK	0x7FFFFFFF +#define SOL_EXP_CMD_SN_MASK	0xFFFFFFFF +#define SOL_HW_STS_MASK		0x000000FF +#define SOL_STS_MASK		0x0000FF00 +#define SOL_RESP_MASK		0x00FF0000 +#define SOL_FLAGS_MASK		0x7F000000 +#define SOL_S_MASK		0x80000000 + +struct sol_cqe { +	u32 dw[4]; +}; + +struct amap_sol_cqe { +	u8 hw_sts[8];		/* dword 0 */ +	u8 i_sts[8];		/* dword 0 */ +	u8 i_resp[8];		/* dword 0 */ +	u8 i_flags[7];		/* dword 0 */ +	u8 s;			/* dword 0 */ +	u8 i_exp_cmd_sn[32];	/* dword 1 */ +	u8 code[6];		/* dword 2 */ +	u8 cid[10];		/* dword 2 */ +	u8 wrb_index[8];	/* dword 2 */ +	u8 i_cmd_wnd[8];	/* dword 2 */ +	u8 i_res_cnt[31];	/* dword 3 */ +	u8 valid;		/* dword 3 */ +} __packed; + + +/** + * Post WRB Queue Doorbell Register used by the host Storage + * stack to notify the + * controller of a posted Work Request Block + */ +#define DB_WRB_POST_CID_MASK		0x3FF	/* bits 0 - 9 */ +#define DB_DEF_PDU_WRB_INDEX_MASK	0xFF	/* bits 0 - 9 */ + +#define DB_DEF_PDU_WRB_INDEX_SHIFT	16 +#define DB_DEF_PDU_NUM_POSTED_SHIFT	24 + +struct fragnum_bits_for_sgl_cra_in { +	struct be_cmd_req_hdr hdr; +	u32 num_bits; +} __packed; + +struct iscsi_cleanup_req { +	struct be_cmd_req_hdr hdr; +	u16 chute; +	u8 hdr_ring_id; +	u8 data_ring_id; + +} __packed; + +struct eq_delay { +	u32 eq_id; +	u32 phase; +	u32 delay_multiplier; +} __packed; + +struct be_eq_delay_params_in { +	struct be_cmd_req_hdr hdr; +	u32 num_eq; +	struct eq_delay delay[8]; +} __packed; + +struct ip_address_format { +	u16 size_of_structure; +	u8 reserved; +	u8 ip_type; +	u8 ip_address[16]; +	u32 rsvd0; +} __packed; + +struct tcp_connect_and_offload_in { +	struct be_cmd_req_hdr hdr; +	struct ip_address_format ip_address; +	u16 tcp_port; +	u16 cid; +	u16 cq_id; +	u16 defq_id; +	struct phys_addr dataout_template_pa; +	u16 hdr_ring_id; +	u16 data_ring_id; +	u8 do_offload; +	u8 rsvd0[3]; +} __packed; + +struct tcp_connect_and_offload_out { +	struct be_cmd_resp_hdr hdr; +	u32 connection_handle; +	u16 cid; +	u16 rsvd0; + +} __packed; + +struct be_mcc_wrb_context { +	struct MCC_WRB *wrb; +	int *users_final_status; +} __packed; + +#define DB_DEF_PDU_RING_ID_MASK		0x3FF	/* bits 0 - 9 */ +#define DB_DEF_PDU_CQPROC_MASK		0x3FFF	/* bits 0 - 9 */ +#define DB_DEF_PDU_REARM_SHIFT		14 +#define DB_DEF_PDU_EVENT_SHIFT		15 +#define DB_DEF_PDU_CQPROC_SHIFT		16 + +struct dmsg_cqe { +	u32 dw[4]; +} __packed; + +struct tcp_upload_params_in { +	struct be_cmd_req_hdr hdr; +	u16 id; +	u16 upload_type; +	u32 reset_seq; +} __packed; + +struct tcp_upload_params_out { +	u32 dw[32]; +} __packed; + +union tcp_upload_params { +	struct tcp_upload_params_in request; +	struct tcp_upload_params_out response; +} __packed; + +struct be_ulp_fw_cfg { +	u32 ulp_mode; +	u32 etx_base; +	u32 etx_count; +	u32 sq_base; +	u32 sq_count; +	u32 rq_base; +	u32 rq_count; +	u32 dq_base; +	u32 dq_count; +	u32 lro_base; +	u32 lro_count; +	u32 icd_base; +	u32 icd_count; +}; + +struct be_fw_cfg { +	struct be_cmd_req_hdr hdr; +	u32 be_config_number; +	u32 asic_revision; +	u32 phys_port; +	u32 function_mode; +	struct be_ulp_fw_cfg ulp[2]; +	u32 function_caps; +} __packed; + +#define CMD_ISCSI_COMMAND_INVALIDATE  1 +#define ISCSI_OPCODE_SCSI_DATA_OUT      5 +#define OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD 70 +#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41 +#define OPCODE_COMMON_MODIFY_EQ_DELAY	41 +#define OPCODE_COMMON_ISCSI_CLEANUP	59 +#define	OPCODE_COMMON_TCP_UPLOAD	56 +#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1 +/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ +#define CMD_ISCSI_CONNECTION_INVALIDATE 1 +#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 2 +#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42 + +#define INI_WR_CMD			1	/* Initiator write command */ +#define INI_TMF_CMD			2	/* Initiator TMF command */ +#define INI_NOPOUT_CMD			3	/* Initiator; Send a NOP-OUT */ +#define INI_RD_CMD			5	/* Initiator requesting to send +						 * a read command +						 */ +#define TGT_CTX_UPDT_CMD		7	/* Target context update */ +#define TGT_STS_CMD			8	/* Target R2T and other BHS +						 * where only the status number +						 * need to be updated +						 */ +#define TGT_DATAIN_CMD			9	/* Target Data-Ins in response +						 * to read command +						 */ +#define TGT_SOS_PDU			10	/* Target:standalone status +						 * response +						 */ +#define TGT_DM_CMD			11	/* Indicates that the bhs +						 *  preparedby +						 * driver should not be touched +						 */ +/* --- CMD_CHUTE_TYPE --- */ +#define CMD_CONNECTION_CHUTE_0		1 +#define CMD_CONNECTION_CHUTE_1		2 +#define CMD_CONNECTION_CHUTE_2		3 + +#define EQ_MAJOR_CODE_COMPLETION	0 + +#define CMD_ISCSI_SESSION_DEL_CFG_FROM_FLASH 0 +#define CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH 1 + +/* --- CONNECTION_UPLOAD_PARAMS --- */ +/* These parameters are used to define the type of upload desired.  */ +#define CONNECTION_UPLOAD_GRACEFUL      1	/* Graceful upload  */ +#define CONNECTION_UPLOAD_ABORT_RESET   2	/* Abortive upload with +						 * reset +						 */ +#define CONNECTION_UPLOAD_ABORT		3	/* Abortive upload without +						 * reset +						 */ +#define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4	/* Abortive upload with reset, +						 * sequence number by driver  */ + +/* Returns byte size of given field with a structure. */ + +/* Returns the number of items in the field array. */ +#define BE_NUMBER_OF_FIELD(_type_, _field_)	\ +	(FIELD_SIZEOF(_type_, _field_)/sizeof((((_type_ *)0)->_field_[0])))\ + +/** + * Different types of iSCSI completions to host driver for both initiator + * and taget mode + * of operation. + */ +#define SOL_CMD_COMPLETE		1	/* Solicited command completed +						 * normally +						 */ +#define SOL_CMD_KILLED_DATA_DIGEST_ERR  2	/* Solicited command got +						 * invalidated internally due +						 * to Data Digest error +						 */ +#define CXN_KILLED_PDU_SIZE_EXCEEDS_DSL 3	/* Connection got invalidated +						 * internally +						 * due to a recieved PDU +						 * size > DSL +						 */ +#define CXN_KILLED_BURST_LEN_MISMATCH   4	/* Connection got invalidated +						 * internally due ti received +						 * PDU sequence size > +						 * FBL/MBL. +						 */ +#define CXN_KILLED_AHS_RCVD		5	/* Connection got invalidated +						 * internally due to a recieved +						 * PDU Hdr that has +						 * AHS */ +#define CXN_KILLED_HDR_DIGEST_ERR	6	/* Connection got invalidated +						 * internally due to Hdr Digest +						 * error +						 */ +#define CXN_KILLED_UNKNOWN_HDR		7	/* Connection got invalidated +						 *  internally +						 * due to a bad opcode in the +						 * pdu hdr +						 */ +#define CXN_KILLED_STALE_ITT_TTT_RCVD	8	/* Connection got invalidated +						 * internally due to a recieved +						 * ITT/TTT that does not belong +						 * to this Connection +						 */ +#define CXN_KILLED_INVALID_ITT_TTT_RCVD 9	/* Connection got invalidated +						 * internally due to recieved +						 * ITT/TTT value > Max +						 * Supported ITTs/TTTs +						 */ +#define CXN_KILLED_RST_RCVD		10	/* Connection got invalidated +						 * internally due to an +						 * incoming TCP RST +						 */ +#define CXN_KILLED_TIMED_OUT		11	/* Connection got invalidated +						 * internally due to timeout on +						 * tcp segment 12 retransmit +						 * attempts failed +						 */ +#define CXN_KILLED_RST_SENT		12	/* Connection got invalidated +						 * internally due to TCP RST +						 * sent by the Tx side +						 */ +#define CXN_KILLED_FIN_RCVD		13	/* Connection got invalidated +						 * internally due to an +						 * incoming TCP FIN. +						 */ +#define CXN_KILLED_BAD_UNSOL_PDU_RCVD	14	/* Connection got invalidated +						 * internally due to bad +						 * unsolicited PDU Unsolicited +						 * PDUs are PDUs with +						 * ITT=0xffffffff +						 */ +#define CXN_KILLED_BAD_WRB_INDEX_ERROR	15	/* Connection got invalidated +						 * internally due to bad WRB +						 * index. +						 */ +#define CXN_KILLED_OVER_RUN_RESIDUAL	16	/* Command got invalidated +						 * internally due to recived +						 * command has residual +						 * over run bytes. +						 */ +#define CXN_KILLED_UNDER_RUN_RESIDUAL	17	/* Command got invalidated +						 * internally due to recived +						 * command has residual under +						 * run bytes. +						 */ +#define CMD_KILLED_INVALID_STATSN_RCVD	18	/* Command got invalidated +						 * internally due to a recieved +						 * PDU has an invalid StatusSN +						 */ +#define CMD_KILLED_INVALID_R2T_RCVD	19	/* Command got invalidated +						 * internally due to a recieved +						 * an R2T with some invalid +						 * fields in it +						 */ +#define CMD_CXN_KILLED_LUN_INVALID	20	/* Command got invalidated +						 * internally due to received +						 * PDU has an invalid LUN. +						 */ +#define CMD_CXN_KILLED_ICD_INVALID	21	/* Command got invalidated +						 * internally due to the +						 * corresponding ICD not in a +						 * valid state +						 */ +#define CMD_CXN_KILLED_ITT_INVALID	22	/* Command got invalidated due +						 *  to received PDU has an +						 *  invalid ITT. +						 */ +#define CMD_CXN_KILLED_SEQ_OUTOFORDER	23	/* Command got invalidated due +						 * to received sequence buffer +						 * offset is out of order. +						 */ +#define CMD_CXN_KILLED_INVALID_DATASN_RCVD 24	/* Command got invalidated +						 * internally due to a +						 * recieved PDU has an invalid +						 * DataSN +						 */ +#define CXN_INVALIDATE_NOTIFY		25	/* Connection invalidation +						 * completion notify. +						 */ +#define CXN_INVALIDATE_INDEX_NOTIFY	26	/* Connection invalidation +						 * completion +						 * with data PDU index. +						 */ +#define CMD_INVALIDATED_NOTIFY		27	/* Command invalidation +						 * completionnotifify. +						 */ +#define UNSOL_HDR_NOTIFY		28	/* Unsolicited header notify.*/ +#define UNSOL_DATA_NOTIFY		29	/* Unsolicited data notify.*/ +#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 	30	/* Unsolicited data digest +						 * error notify. +						 */ +#define DRIVERMSG_NOTIFY		31	/* TCP acknowledge based +						 * notification. +						 */ +#define CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN 32 /* Connection got invalidated +						  * internally due to command +						  * and data are not on same +						  * connection. +						  */ +#define SOL_CMD_KILLED_DIF_ERR		33	/* Solicited command got +						 *  invalidated internally due +						 *  to DIF error +						 */ +#define CXN_KILLED_SYN_RCVD		34	/* Connection got invalidated +						 * internally due to incoming +						 * TCP SYN +						 */ +#define CXN_KILLED_IMM_DATA_RCVD	35	/* Connection got invalidated +						 * internally due to an +						 * incoming Unsolicited PDU +						 * that has immediate data on +						 * the cxn +						 */ + +void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, +			bool embedded, u8 sge_cnt); + +void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, +			u8 subsystem, u8 opcode, int cmd_len); + +#endif /* !BEISCSI_CMDS_H */ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c new file mode 100644 index 00000000000..2fd25442cfa --- /dev/null +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -0,0 +1,638 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#include <scsi/libiscsi.h> +#include <scsi/scsi_transport_iscsi.h> +#include <scsi/scsi_transport.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi.h> + +#include "be_iscsi.h" + +extern struct iscsi_transport beiscsi_iscsi_transport; + +/** + * beiscsi_session_create - creates a new iscsi session + * @cmds_max: max commands supported + * @qdepth: max queue depth supported + * @initial_cmdsn: initial iscsi CMDSN + */ +struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, +						 u16 cmds_max, +						 u16 qdepth, +						 u32 initial_cmdsn) +{ +	struct Scsi_Host *shost; +	struct beiscsi_endpoint *beiscsi_ep; +	struct iscsi_cls_session *cls_session; +	struct beiscsi_hba *phba; +	struct iscsi_session *sess; +	struct beiscsi_session *beiscsi_sess; +	struct beiscsi_io_task *io_task; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n"); + +	if (!ep) { +		SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n"); +		return NULL; +	} +	beiscsi_ep = ep->dd_data; +	phba = beiscsi_ep->phba; +	shost = phba->shost; +	if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) { +		shost_printk(KERN_ERR, shost, "Cannot handle %d cmds." +			     "Max cmds per session supported is %d. Using %d. " +			     "\n", cmds_max, +			      beiscsi_ep->phba->params.wrbs_per_cxn, +			      beiscsi_ep->phba->params.wrbs_per_cxn); +		cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn; +	} + +	 cls_session = iscsi_session_setup(&beiscsi_iscsi_transport, +					   shost, cmds_max, +					   sizeof(*beiscsi_sess), +					   sizeof(*io_task), +					   initial_cmdsn, ISCSI_MAX_TARGET); +	if (!cls_session) +		return NULL; +	sess = cls_session->dd_data; +	beiscsi_sess = sess->dd_data; +	beiscsi_sess->bhs_pool =  pci_pool_create("beiscsi_bhs_pool", +						   phba->pcidev, +						   sizeof(struct be_cmd_bhs), +						   64, 0); +	if (!beiscsi_sess->bhs_pool) +		goto destroy_sess; + +	return cls_session; +destroy_sess: +	iscsi_session_teardown(cls_session); +	return NULL; +} + +/** + * beiscsi_session_destroy - destroys iscsi session + * @cls_session:	pointer to iscsi cls session + * + * Destroys iSCSI session instance and releases + * resources allocated for it. + */ +void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) +{ +	struct iscsi_session *sess = cls_session->dd_data; +	struct beiscsi_session *beiscsi_sess = sess->dd_data; + +	pci_pool_destroy(beiscsi_sess->bhs_pool); +	iscsi_session_teardown(cls_session); +} + +/** + * beiscsi_conn_create - create an instance of iscsi connection + * @cls_session: ptr to iscsi_cls_session + * @cid: iscsi cid + */ +struct iscsi_cls_conn * +beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) +{ +	struct beiscsi_hba *phba; +	struct Scsi_Host *shost; +	struct iscsi_cls_conn *cls_conn; +	struct beiscsi_conn *beiscsi_conn; +	struct iscsi_conn *conn; +	struct iscsi_session *sess; +	struct beiscsi_session *beiscsi_sess; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid" +		 "from iscsi layer=%d\n", cid); +	shost = iscsi_session_to_shost(cls_session); +	phba = iscsi_host_priv(shost); + +	cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid); +	if (!cls_conn) +		return NULL; + +	conn = cls_conn->dd_data; +	beiscsi_conn = conn->dd_data; +	beiscsi_conn->ep = NULL; +	beiscsi_conn->phba = phba; +	beiscsi_conn->conn = conn; +	sess = cls_session->dd_data; +	beiscsi_sess = sess->dd_data; +	beiscsi_conn->beiscsi_sess = beiscsi_sess; +	return cls_conn; +} + +/** + * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table + * @beiscsi_conn: The pointer to  beiscsi_conn structure + * @phba: The phba instance + * @cid: The cid to free + */ +static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, +				struct beiscsi_conn *beiscsi_conn, +				unsigned int cid) +{ +	if (phba->conn_table[cid]) { +		SE_DEBUG(DBG_LVL_1, +			 "Connection table already occupied. Detected clash\n"); +		return -EINVAL; +	} else { +		SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n", +			 cid, beiscsi_conn); +		phba->conn_table[cid] = beiscsi_conn; +	} +	return 0; +} + +/** + * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection + * @cls_session: pointer to iscsi cls session + * @cls_conn: pointer to iscsi cls conn + * @transport_fd: EP handle(64 bit) + * + * This function binds the TCP Conn with iSCSI Connection and Session. + */ +int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, +		      struct iscsi_cls_conn *cls_conn, +		      u64 transport_fd, int is_leading) +{ +	struct iscsi_conn *conn = cls_conn->dd_data; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct Scsi_Host *shost = +		(struct Scsi_Host *)iscsi_session_to_shost(cls_session); +	struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); +	struct beiscsi_endpoint *beiscsi_ep; +	struct iscsi_endpoint *ep; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n"); +	ep = iscsi_lookup_endpoint(transport_fd); +	if (!ep) +		return -EINVAL; + +	beiscsi_ep = ep->dd_data; + +	if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) +		return -EINVAL; + +	if (beiscsi_ep->phba != phba) { +		SE_DEBUG(DBG_LVL_8, +			 "beiscsi_ep->hba=%p not equal to phba=%p \n", +			 beiscsi_ep->phba, phba); +		return -EEXIST; +	} + +	beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; +	beiscsi_conn->ep = beiscsi_ep; +	beiscsi_ep->conn = beiscsi_conn; +	SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n", +		 beiscsi_conn, conn, beiscsi_ep->ep_cid); +	return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); +} + +/** + * beiscsi_conn_get_param - get the iscsi parameter + * @cls_conn: pointer to iscsi cls conn + * @param: parameter type identifier + * @buf: buffer pointer + * + * returns iscsi parameter + */ +int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, +			   enum iscsi_param param, char *buf) +{ +	struct beiscsi_endpoint *beiscsi_ep; +	struct iscsi_conn *conn = cls_conn->dd_data; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	int len = 0; + +	beiscsi_ep = beiscsi_conn->ep; +	if (!beiscsi_ep) { +		SE_DEBUG(DBG_LVL_1, +			 "In beiscsi_conn_get_param , no beiscsi_ep\n"); +		return -1; +	} + +	switch (param) { +	case ISCSI_PARAM_CONN_PORT: +		len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport); +		break; +	case ISCSI_PARAM_CONN_ADDRESS: +		if (beiscsi_ep->ip_type == BE2_IPV4) +			len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr); +		else +			len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr); +		break; +	default: +		return iscsi_conn_get_param(cls_conn, param, buf); +	} +	return len; +} + +int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, +		      enum iscsi_param param, char *buf, int buflen) +{ +	struct iscsi_conn *conn = cls_conn->dd_data; +	struct iscsi_session *session = conn->session; +	int ret; + +	ret = iscsi_set_param(cls_conn, param, buf, buflen); +	if (ret) +		return ret; +	/* +	 * If userspace tried to set the value to higher than we can +	 * support override here. +	 */ +	switch (param) { +	case ISCSI_PARAM_FIRST_BURST: +		if (session->first_burst > 8192) +			session->first_burst = 8192; +		break; +	case ISCSI_PARAM_MAX_RECV_DLENGTH: +		if (conn->max_recv_dlength > 65536) +			conn->max_recv_dlength = 65536; +		break; +	case ISCSI_PARAM_MAX_BURST: +		if (session->first_burst > 262144) +			session->first_burst = 262144; +		break; +	default: +		return 0; +	} + +	return 0; +} + +/** + * beiscsi_get_host_param - get the iscsi parameter + * @shost: pointer to scsi_host structure + * @param: parameter type identifier + * @buf: buffer pointer + * + * returns host parameter + */ +int beiscsi_get_host_param(struct Scsi_Host *shost, +			   enum iscsi_host_param param, char *buf) +{ +	struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost); +	int len = 0; + +	switch (param) { +	case ISCSI_HOST_PARAM_HWADDRESS: +		be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address); +		len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN); +		break; +	default: +		return iscsi_host_get_param(shost, param, buf); +	} +	return len; +} + +/** + * beiscsi_conn_get_stats - get the iscsi stats + * @cls_conn: pointer to iscsi cls conn + * @stats: pointer to iscsi_stats structure + * + * returns iscsi stats + */ +void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, +			    struct iscsi_stats *stats) +{ +	struct iscsi_conn *conn = cls_conn->dd_data; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n"); +	stats->txdata_octets = conn->txdata_octets; +	stats->rxdata_octets = conn->rxdata_octets; +	stats->dataout_pdus = conn->dataout_pdus_cnt; +	stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; +	stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; +	stats->datain_pdus = conn->datain_pdus_cnt; +	stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; +	stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; +	stats->r2t_pdus = conn->r2t_pdus_cnt; +	stats->digest_err = 0; +	stats->timeout_err = 0; +	stats->custom_length = 0; +	strcpy(stats->custom[0].desc, "eh_abort_cnt"); +	stats->custom[0].value = conn->eh_abort_cnt; +} + +/** + * beiscsi_set_params_for_offld - get the parameters for offload + * @beiscsi_conn: pointer to beiscsi_conn + * @params: pointer to offload_params structure + */ +static void  beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn, +					  struct beiscsi_offload_params *params) +{ +	struct iscsi_conn *conn = beiscsi_conn->conn; +	struct iscsi_session *session = conn->session; + +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length, +		      params, session->max_burst); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, +		      max_send_data_segment_length, params, +		      conn->max_xmit_dlength); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length, +		      params, session->first_burst); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params, +		      session->erl); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params, +		      conn->datadgst_en); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params, +		      conn->hdrdgst_en); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params, +		      session->initial_r2t_en); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params, +		      session->imm_data_en); +	AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params, +		      (conn->exp_statsn - 1)); +} + +/** + * beiscsi_conn_start - offload of session to chip + * @cls_conn: pointer to beiscsi_conn + */ +int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) +{ +	struct iscsi_conn *conn = cls_conn->dd_data; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_endpoint *beiscsi_ep; +	struct beiscsi_offload_params params; +	struct iscsi_session *session = conn->session; +	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); +	struct beiscsi_hba *phba = iscsi_host_priv(shost); + +	memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); +	beiscsi_ep = beiscsi_conn->ep; +	if (!beiscsi_ep) +		SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n"); + +	free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle); +	beiscsi_conn->login_in_progress = 0; +	beiscsi_set_params_for_offld(beiscsi_conn, ¶ms); +	beiscsi_offload_connection(beiscsi_conn, ¶ms); +	iscsi_conn_start(cls_conn); +	return 0; +} + +/** + * beiscsi_get_cid - Allocate a cid + * @phba: The phba instance + */ +static int beiscsi_get_cid(struct beiscsi_hba *phba) +{ +	unsigned short cid = 0xFFFF; + +	if (!phba->avlbl_cids) +		return cid; + +	cid = phba->cid_array[phba->cid_alloc++]; +	if (phba->cid_alloc == phba->params.cxns_per_ctrl) +		phba->cid_alloc = 0; +	phba->avlbl_cids--; +	return cid; +} + +/** + * beiscsi_open_conn - Ask FW to open a TCP connection + * @ep:	endpoint to be used + * @src_addr: The source IP address + * @dst_addr: The Destination  IP address + * + * Asks the FW to open a TCP connection + */ +static int beiscsi_open_conn(struct iscsi_endpoint *ep, +			     struct sockaddr *src_addr, +			     struct sockaddr *dst_addr, int non_blocking) +{ +	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; +	struct beiscsi_hba *phba = beiscsi_ep->phba; +	int ret = -1; + +	beiscsi_ep->ep_cid = beiscsi_get_cid(phba); +	if (beiscsi_ep->ep_cid == 0xFFFF) { +		SE_DEBUG(DBG_LVL_1, "No free cid available\n"); +		return ret; +	} +	SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ", +		 beiscsi_ep->ep_cid); +	phba->ep_array[beiscsi_ep->ep_cid] = ep; +	if (beiscsi_ep->ep_cid > +	    (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) { +		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); +		return ret; +	} + +	beiscsi_ep->cid_vld = 0; +	return mgmt_open_connection(phba, dst_addr, beiscsi_ep); +} + +/** + * beiscsi_put_cid - Free the cid + * @phba: The phba for which the cid is being freed + * @cid: The cid to free + */ +static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) +{ +	phba->avlbl_cids++; +	phba->cid_array[phba->cid_free++] = cid; +	if (phba->cid_free == phba->params.cxns_per_ctrl) +		phba->cid_free = 0; +} + +/** + * beiscsi_free_ep - free endpoint + * @ep:	pointer to iscsi endpoint structure + */ +static void beiscsi_free_ep(struct iscsi_endpoint *ep) +{ +	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; +	struct beiscsi_hba *phba = beiscsi_ep->phba; + +	beiscsi_put_cid(phba, beiscsi_ep->ep_cid); +	beiscsi_ep->phba = NULL; +	iscsi_destroy_endpoint(ep); +} + +/** + * beiscsi_ep_connect - Ask chip to create TCP Conn + * @scsi_host: Pointer to scsi_host structure + * @dst_addr: The IP address of Target + * @non_blocking: blocking or non-blocking call + * + * This routines first asks chip to create a connection and then allocates an EP + */ +struct iscsi_endpoint * +beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, +		   int non_blocking) +{ +	struct beiscsi_hba *phba; +	struct beiscsi_endpoint *beiscsi_ep; +	struct iscsi_endpoint *ep; +	int ret; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n"); +	if (shost) +		phba = iscsi_host_priv(shost); +	else { +		ret = -ENXIO; +		SE_DEBUG(DBG_LVL_1, "shost is NULL \n"); +		return ERR_PTR(ret); +	} +	ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint)); +	if (!ep) { +		ret = -ENOMEM; +		return ERR_PTR(ret); +	} + +	beiscsi_ep = ep->dd_data; +	beiscsi_ep->phba = phba; + +	if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { +		SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); +		ret = -ENOMEM; +		goto free_ep; +	} + +	return ep; + +free_ep: +	beiscsi_free_ep(ep); +	return ERR_PTR(ret); +} + +/** + * beiscsi_ep_poll - Poll to see if connection is established + * @ep:	endpoint to be used + * @timeout_ms: timeout specified in millisecs + * + * Poll to see if TCP connection established + */ +int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) +{ +	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; + +	SE_DEBUG(DBG_LVL_8, "In  beiscsi_ep_poll\n"); +	if (beiscsi_ep->cid_vld == 1) +		return 1; +	else +		return 0; +} + +/** + * beiscsi_close_conn - Upload the  connection + * @ep: The iscsi endpoint + * @flag: The type of connection closure + */ +static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag) +{ +	int ret = 0; +	struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; +	struct beiscsi_hba *phba = beiscsi_ep->phba; + +	if (MGMT_STATUS_SUCCESS != +	    mgmt_upload_connection(phba, beiscsi_ep->ep_cid, +		CONNECTION_UPLOAD_GRACEFUL)) { +		SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", +			 beiscsi_ep->ep_cid); +		ret = -1; +	} + +	return ret; +} + +/** + * beiscsi_ep_disconnect - Tears down the TCP connection + * @ep:	endpoint to be used + * + * Tears down the TCP connection + */ +void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) +{ +	struct beiscsi_conn *beiscsi_conn; +	struct beiscsi_endpoint *beiscsi_ep; +	struct beiscsi_hba *phba; +	int flag = 0; + +	beiscsi_ep = ep->dd_data; +	phba = beiscsi_ep->phba; +	SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n"); + +	if (beiscsi_ep->conn) { +		beiscsi_conn = beiscsi_ep->conn; +		iscsi_suspend_queue(beiscsi_conn->conn); +		beiscsi_close_conn(ep, flag); +	} + +	beiscsi_free_ep(ep); +} + +/** + * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table + * @phba: The phba instance + * @cid: The cid to free + */ +static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, +				      unsigned int cid) +{ +	if (phba->conn_table[cid]) +		phba->conn_table[cid] = NULL; +	else { +		SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n"); +		return -EINVAL; +	} +	return 0; +} + +/** + * beiscsi_conn_stop - Invalidate and stop the connection + * @cls_conn: pointer to get iscsi_conn + * @flag: The type of connection closure + */ +void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +{ +	struct iscsi_conn *conn = cls_conn->dd_data; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_endpoint *beiscsi_ep; +	struct iscsi_session *session = conn->session; +	struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); +	struct beiscsi_hba *phba = iscsi_host_priv(shost); +	unsigned int status; +	unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; + +	SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n"); +	beiscsi_ep = beiscsi_conn->ep; +	if (!beiscsi_ep) { +		SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); +		return; +	} +	status = mgmt_invalidate_connection(phba, beiscsi_ep, +					    beiscsi_ep->ep_cid, 1, +					    savecfg_flag); +	if (status != MGMT_STATUS_SUCCESS) { +		SE_DEBUG(DBG_LVL_1, +			 "mgmt_invalidate_connection Failed for cid=%d \n", +			 beiscsi_ep->ep_cid); +	} +	beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); +	iscsi_conn_stop(cls_conn, flag); +} diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h new file mode 100644 index 00000000000..f92ffc5349f --- /dev/null +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#ifndef _BE_ISCSI_ +#define _BE_ISCSI_ + +#include "be_main.h" +#include "be_mgmt.h" + +#define BE2_IPV4  0x1 +#define BE2_IPV6  0x10 + +void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, +				struct beiscsi_offload_params *params); + +void beiscsi_offload_iscsi(struct beiscsi_hba *phba, struct iscsi_conn *conn, +			   struct beiscsi_conn *beiscsi_conn, +			   unsigned int fw_handle); + +struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, +						 uint16_t cmds_max, +						 uint16_t qdepth, +						 uint32_t initial_cmdsn); + +void beiscsi_session_destroy(struct iscsi_cls_session *cls_session); + +struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session +					   *cls_session, uint32_t cid); + +int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, +		      struct iscsi_cls_conn *cls_conn, +		      uint64_t transport_fd, int is_leading); + +int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, +			   enum iscsi_param param, char *buf); + +int beiscsi_get_host_param(struct Scsi_Host *shost, +			   enum iscsi_host_param param, char *buf); + +int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, +		      enum iscsi_param param, char *buf, int buflen); + +int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn); + +void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag); + +struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost, +					  struct sockaddr *dst_addr, +					  int non_blocking); + +int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); + +void beiscsi_ep_disconnect(struct iscsi_endpoint *ep); + +void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, +			    struct iscsi_stats *stats); + +#endif diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c new file mode 100644 index 00000000000..4f1aca346e3 --- /dev/null +++ b/drivers/scsi/be2iscsi/be_main.c @@ -0,0 +1,3390 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + *  ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ +#include <linux/reboot.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/blkdev.h> +#include <linux/pci.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/semaphore.h> + +#include <scsi/libiscsi.h> +#include <scsi/scsi_transport_iscsi.h> +#include <scsi/scsi_transport.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi.h> +#include "be_main.h" +#include "be_iscsi.h" +#include "be_mgmt.h" + +static unsigned int be_iopoll_budget = 10; +static unsigned int be_max_phys_size = 64; +static unsigned int enable_msix; + +MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); +MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); +MODULE_AUTHOR("ServerEngines Corporation"); +MODULE_LICENSE("GPL"); +module_param(be_iopoll_budget, int, 0); +module_param(enable_msix, int, 0); +module_param(be_max_phys_size, uint, S_IRUGO); +MODULE_PARM_DESC(be_max_phys_size, "Maximum Size (In Kilobytes) of physically" +				   "contiguous memory that can be allocated." +				   "Range is 16 - 128"); + +static int beiscsi_slave_configure(struct scsi_device *sdev) +{ +	blk_queue_max_segment_size(sdev->request_queue, 65536); +	return 0; +} + +static struct scsi_host_template beiscsi_sht = { +	.module = THIS_MODULE, +	.name = "ServerEngines 10Gbe open-iscsi Initiator Driver", +	.proc_name = DRV_NAME, +	.queuecommand = iscsi_queuecommand, +	.eh_abort_handler = iscsi_eh_abort, +	.change_queue_depth = iscsi_change_queue_depth, +	.slave_configure = beiscsi_slave_configure, +	.target_alloc = iscsi_target_alloc, +	.eh_device_reset_handler = iscsi_eh_device_reset, +	.eh_target_reset_handler = iscsi_eh_target_reset, +	.sg_tablesize = BEISCSI_SGLIST_ELEMENTS, +	.can_queue = BE2_IO_DEPTH, +	.this_id = -1, +	.max_sectors = BEISCSI_MAX_SECTORS, +	.cmd_per_lun = BEISCSI_CMD_PER_LUN, +	.use_clustering = ENABLE_CLUSTERING, +}; +static struct scsi_transport_template *beiscsi_scsi_transport; + +/*------------------- PCI Driver operations and data ----------------- */ +static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { +	{ PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, +	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, +	{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, +	{ 0 } +}; +MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); + +static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) +{ +	struct beiscsi_hba *phba; +	struct Scsi_Host *shost; + +	shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0); +	if (!shost) { +		dev_err(&pcidev->dev, "beiscsi_hba_alloc -" +			"iscsi_host_alloc failed \n"); +		return NULL; +	} +	shost->dma_boundary = pcidev->dma_mask; +	shost->max_id = BE2_MAX_SESSIONS; +	shost->max_channel = 0; +	shost->max_cmd_len = BEISCSI_MAX_CMD_LEN; +	shost->max_lun = BEISCSI_NUM_MAX_LUN; +	shost->transportt = beiscsi_scsi_transport; + +	phba = iscsi_host_priv(shost); +	memset(phba, 0, sizeof(*phba)); +	phba->shost = shost; +	phba->pcidev = pci_dev_get(pcidev); + +	if (iscsi_host_add(shost, &phba->pcidev->dev)) +		goto free_devices; +	return phba; + +free_devices: +	pci_dev_put(phba->pcidev); +	iscsi_host_free(phba->shost); +	return NULL; +} + +static void beiscsi_unmap_pci_function(struct beiscsi_hba *phba) +{ +	if (phba->csr_va) { +		iounmap(phba->csr_va); +		phba->csr_va = NULL; +	} +	if (phba->db_va) { +		iounmap(phba->db_va); +		phba->db_va = NULL; +	} +	if (phba->pci_va) { +		iounmap(phba->pci_va); +		phba->pci_va = NULL; +	} +} + +static int beiscsi_map_pci_bars(struct beiscsi_hba *phba, +				struct pci_dev *pcidev) +{ +	u8 __iomem *addr; + +	addr = ioremap_nocache(pci_resource_start(pcidev, 2), +			       pci_resource_len(pcidev, 2)); +	if (addr == NULL) +		return -ENOMEM; +	phba->ctrl.csr = addr; +	phba->csr_va = addr; +	phba->csr_pa.u.a64.address = pci_resource_start(pcidev, 2); + +	addr = ioremap_nocache(pci_resource_start(pcidev, 4), 128 * 1024); +	if (addr == NULL) +		goto pci_map_err; +	phba->ctrl.db = addr; +	phba->db_va = addr; +	phba->db_pa.u.a64.address =  pci_resource_start(pcidev, 4); + +	addr = ioremap_nocache(pci_resource_start(pcidev, 1), +			       pci_resource_len(pcidev, 1)); +	if (addr == NULL) +		goto pci_map_err; +	phba->ctrl.pcicfg = addr; +	phba->pci_va = addr; +	phba->pci_pa.u.a64.address = pci_resource_start(pcidev, 1); +	return 0; + +pci_map_err: +	beiscsi_unmap_pci_function(phba); +	return -ENOMEM; +} + +static int beiscsi_enable_pci(struct pci_dev *pcidev) +{ +	int ret; + +	ret = pci_enable_device(pcidev); +	if (ret) { +		dev_err(&pcidev->dev, "beiscsi_enable_pci - enable device " +			"failed. Returning -ENODEV\n"); +		return ret; +	} + +	if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) { +		ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)); +		if (ret) { +			dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n"); +			pci_disable_device(pcidev); +			return ret; +		} +	} +	return 0; +} + +static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; +	struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; +	int status = 0; + +	ctrl->pdev = pdev; +	status = beiscsi_map_pci_bars(phba, pdev); +	if (status) +		return status; + +	mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; +	mbox_mem_alloc->va = pci_alloc_consistent(pdev, +						  mbox_mem_alloc->size, +						  &mbox_mem_alloc->dma); +	if (!mbox_mem_alloc->va) { +		beiscsi_unmap_pci_function(phba); +		status = -ENOMEM; +		return status; +	} + +	mbox_mem_align->size = sizeof(struct be_mcc_mailbox); +	mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); +	mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); +	memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); +	spin_lock_init(&ctrl->mbox_lock); +	return status; +} + +static void beiscsi_get_params(struct beiscsi_hba *phba) +{ +	phba->params.ios_per_ctrl = BE2_IO_DEPTH; +	phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS; +	phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS; +	phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2; +	phba->params.num_sge_per_io = BE2_SGE; +	phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; +	phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; +	phba->params.eq_timer = 64; +	phba->params.num_eq_entries = +	    (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / +								512) + 1) * 512; +	phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) +				? 1024 : phba->params.num_eq_entries; +	SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n", +		 phba->params.num_eq_entries); +	phba->params.num_cq_entries = +	    (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) / +								512) + 1) * 512; +	SE_DEBUG(DBG_LVL_8, +		"phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d" +		"BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n", +		phba->params.num_cq_entries, BE2_CMDS_PER_CXN, +		BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS); +	phba->params.wrbs_per_cxn = 256; +} + +static void hwi_ring_eq_db(struct beiscsi_hba *phba, +			   unsigned int id, unsigned int clr_interrupt, +			   unsigned int num_processed, +			   unsigned char rearm, unsigned char event) +{ +	u32 val = 0; +	val |= id & DB_EQ_RING_ID_MASK; +	if (rearm) +		val |= 1 << DB_EQ_REARM_SHIFT; +	if (clr_interrupt) +		val |= 1 << DB_EQ_CLR_SHIFT; +	if (event) +		val |= 1 << DB_EQ_EVNT_SHIFT; +	val |= num_processed << DB_EQ_NUM_POPPED_SHIFT; +	iowrite32(val, phba->db_va + DB_EQ_OFFSET); +} + +/** + * be_isr - The isr routine of the driver. + * @irq: Not used + * @dev_id: Pointer to host adapter structure + */ +static irqreturn_t be_isr(int irq, void *dev_id) +{ +	struct beiscsi_hba *phba; +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	struct be_eq_entry *eqe = NULL; +	struct be_queue_info *eq; +	struct be_queue_info *cq; +	unsigned long flags, index; +	unsigned int num_eq_processed; +	struct be_ctrl_info *ctrl; +	int isr; + +	phba = dev_id; +	if (!enable_msix) { +		ctrl = &phba->ctrl;; +		isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + +			       (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE)); +		if (!isr) +			return IRQ_NONE; +	} + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; +	eq = &phwi_context->be_eq.q; +	cq = &phwi_context->be_cq; +	index = 0; +	eqe = queue_tail_node(eq); +	if (!eqe) +		SE_DEBUG(DBG_LVL_1, "eqe is NULL\n"); + +	num_eq_processed = 0; +	if (blk_iopoll_enabled) { +		while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] +					& EQE_VALID_MASK) { +			if (!blk_iopoll_sched_prep(&phba->iopoll)) +				blk_iopoll_sched(&phba->iopoll); + +			AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); +			queue_tail_inc(eq); +			eqe = queue_tail_node(eq); +			num_eq_processed++; +			SE_DEBUG(DBG_LVL_8, "Valid EQE\n"); +		} +		if (num_eq_processed) { +			hwi_ring_eq_db(phba, eq->id, 0,	num_eq_processed, 0, 1); +			return IRQ_HANDLED; +		} else +			return IRQ_NONE; +	} else { +		while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] +						& EQE_VALID_MASK) { + +			if (((eqe->dw[offsetof(struct amap_eq_entry, +			     resource_id) / 32] & +			     EQE_RESID_MASK) >> 16) != cq->id) { +				spin_lock_irqsave(&phba->isr_lock, flags); +				phba->todo_mcc_cq = 1; +				spin_unlock_irqrestore(&phba->isr_lock, flags); +			} else { +				spin_lock_irqsave(&phba->isr_lock, flags); +				phba->todo_cq = 1; +				spin_unlock_irqrestore(&phba->isr_lock, flags); +			} +			AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); +			queue_tail_inc(eq); +			eqe = queue_tail_node(eq); +			num_eq_processed++; +		} +		if (phba->todo_cq || phba->todo_mcc_cq) +			queue_work(phba->wq, &phba->work_cqs); + +		if (num_eq_processed) { +			hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 1, 1); +			return IRQ_HANDLED; +		} else +			return IRQ_NONE; +	} +} + +static int beiscsi_init_irqs(struct beiscsi_hba *phba) +{ +	struct pci_dev *pcidev = phba->pcidev; +	int ret; + +	ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, "beiscsi", phba); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-" +			     "Failed to register irq\\n"); +		return ret; +	} +	return 0; +} + +static void hwi_ring_cq_db(struct beiscsi_hba *phba, +			   unsigned int id, unsigned int num_processed, +			   unsigned char rearm, unsigned char event) +{ +	u32 val = 0; +	val |= id & DB_CQ_RING_ID_MASK; +	if (rearm) +		val |= 1 << DB_CQ_REARM_SHIFT; +	val |= num_processed << DB_CQ_NUM_POPPED_SHIFT; +	iowrite32(val, phba->db_va + DB_CQ_OFFSET); +} + +/* + * async pdus include + * a. unsolicited NOP-In (target initiated NOP-In) + * b. Async Messages + * c. Reject PDU + * d. Login response + * These headers arrive unprocessed by the EP firmware and iSCSI layer + * process them + */ +static unsigned int +beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, +			  struct beiscsi_hba *phba, +			  unsigned short cid, +			  struct pdu_base *ppdu, +			  unsigned long pdu_len, +			  void *pbuffer, unsigned long buf_len) +{ +	struct iscsi_conn *conn = beiscsi_conn->conn; +	struct iscsi_session *session = conn->session; + +	switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] & +						PDUBASE_OPCODE_MASK) { +	case ISCSI_OP_NOOP_IN: +		pbuffer = NULL; +		buf_len = 0; +		break; +	case ISCSI_OP_ASYNC_EVENT: +		break; +	case ISCSI_OP_REJECT: +		WARN_ON(!pbuffer); +		WARN_ON(!(buf_len == 48)); +		SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n"); +		break; +	case ISCSI_OP_LOGIN_RSP: +		break; +	default: +		shost_printk(KERN_WARNING, phba->shost, +			     "Unrecognized opcode 0x%x in async msg \n", +			     (ppdu-> +			     dw[offsetof(struct amap_pdu_base, opcode) / 32] +						& PDUBASE_OPCODE_MASK)); +		return 1; +	} + +	spin_lock_bh(&session->lock); +	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len); +	spin_unlock_bh(&session->lock); +	return 0; +} + +static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) +{ +	struct sgl_handle *psgl_handle; + +	if (phba->io_sgl_hndl_avbl) { +		SE_DEBUG(DBG_LVL_8, +			 "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n", +			 phba->io_sgl_alloc_index); +		psgl_handle = phba->io_sgl_hndl_base[phba-> +						io_sgl_alloc_index]; +		phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL; +		phba->io_sgl_hndl_avbl--; +		if (phba->io_sgl_alloc_index == (phba->params.ios_per_ctrl - 1)) +			phba->io_sgl_alloc_index = 0; +		else +			phba->io_sgl_alloc_index++; +	} else +		psgl_handle = NULL; +	return psgl_handle; +} + +static void +free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) +{ +	SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n", +		 phba->io_sgl_free_index); +	if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) { +		/* +		 * this can happen if clean_task is called on a task that +		 * failed in xmit_task or alloc_pdu. +		 */ +		 SE_DEBUG(DBG_LVL_8, +			 "Double Free in IO SGL io_sgl_free_index=%d," +			 "value there=%p \n", phba->io_sgl_free_index, +			 phba->io_sgl_hndl_base[phba->io_sgl_free_index]); +		return; +	} +	phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle; +	phba->io_sgl_hndl_avbl++; +	if (phba->io_sgl_free_index == (phba->params.ios_per_ctrl - 1)) +		phba->io_sgl_free_index = 0; +	else +		phba->io_sgl_free_index++; +} + +/** + * alloc_wrb_handle - To allocate a wrb handle + * @phba: The hba pointer + * @cid: The cid to use for allocation + * @index: index allocation and wrb index + * + * This happens under session_lock until submission to chip + */ +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, +				    int index) +{ +	struct hwi_wrb_context *pwrb_context; +	struct hwi_controller *phwi_ctrlr; +	struct wrb_handle *pwrb_handle; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pwrb_context = &phwi_ctrlr->wrb_context[cid]; +	pwrb_handle = pwrb_context->pwrb_handle_base[index]; +	pwrb_handle->wrb_index = index; +	pwrb_handle->nxt_wrb_index = index; +	return pwrb_handle; +} + +/** + * free_wrb_handle - To free the wrb handle back to pool + * @phba: The hba pointer + * @pwrb_context: The context to free from + * @pwrb_handle: The wrb_handle to free + * + * This happens under session_lock until submission to chip + */ +static void +free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, +		struct wrb_handle *pwrb_handle) +{ +	SE_DEBUG(DBG_LVL_8, +		 "FREE WRB: pwrb_handle=%p free_index=%d=0x%x" +		 "wrb_handles_available=%d \n", +		 pwrb_handle, pwrb_context->free_index, +		 pwrb_context->free_index, pwrb_context->wrb_handles_available); +} + +static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) +{ +	struct sgl_handle *psgl_handle; + +	if (phba->eh_sgl_hndl_avbl) { +		psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index]; +		phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL; +		SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n", +			 phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index); +		phba->eh_sgl_hndl_avbl--; +		if (phba->eh_sgl_alloc_index == +		    (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - +		     1)) +			phba->eh_sgl_alloc_index = 0; +		else +			phba->eh_sgl_alloc_index++; +	} else +		psgl_handle = NULL; +	return psgl_handle; +} + +void +free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) +{ + +	if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) { +		/* +		 * this can happen if clean_task is called on a task that +		 * failed in xmit_task or alloc_pdu. +		 */ +		SE_DEBUG(DBG_LVL_8, +			 "Double Free in eh SGL ,eh_sgl_free_index=%d \n", +			 phba->eh_sgl_free_index); +		return; +	} +	phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle; +	phba->eh_sgl_hndl_avbl++; +	if (phba->eh_sgl_free_index == +	    (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 1)) +		phba->eh_sgl_free_index = 0; +	else +		phba->eh_sgl_free_index++; +} + +static void +be_complete_io(struct beiscsi_conn *beiscsi_conn, +	       struct iscsi_task *task, struct sol_cqe *psol) +{ +	struct beiscsi_io_task *io_task = task->dd_data; +	struct be_status_bhs *sts_bhs = +				(struct be_status_bhs *)io_task->cmd_bhs; +	struct iscsi_conn *conn = beiscsi_conn->conn; +	unsigned int sense_len; +	unsigned char *sense; +	u32 resid = 0, exp_cmdsn, max_cmdsn; +	u8 rsp, status, flags; + +	exp_cmdsn = be32_to_cpu(psol-> +			dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] +			& SOL_EXP_CMD_SN_MASK); +	max_cmdsn = be32_to_cpu((psol-> +			dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] +			& SOL_EXP_CMD_SN_MASK) + +			((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) +				/ 32] & SOL_CMD_WND_MASK) >> 24) - 1); +	rsp = ((psol->dw[offsetof(struct amap_sol_cqe, i_resp) / 32] +						& SOL_RESP_MASK) >> 16); +	status = ((psol->dw[offsetof(struct amap_sol_cqe, i_sts) / 32] +						& SOL_STS_MASK) >> 8); +	flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] +					& SOL_FLAGS_MASK) >> 24) | 0x80; + +	task->sc->result = (DID_OK << 16) | status; +	if (rsp != ISCSI_STATUS_CMD_COMPLETED) { +		task->sc->result = DID_ERROR << 16; +		goto unmap; +	} + +	/* bidi not initially supported */ +	if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) { +		resid = (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / +				32] & SOL_RES_CNT_MASK); + +		if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW)) +			task->sc->result = DID_ERROR << 16; + +		if (flags & ISCSI_FLAG_CMD_UNDERFLOW) { +			scsi_set_resid(task->sc, resid); +			if (!status && (scsi_bufflen(task->sc) - resid < +			    task->sc->underflow)) +				task->sc->result = DID_ERROR << 16; +		} +	} + +	if (status == SAM_STAT_CHECK_CONDITION) { +		sense = sts_bhs->sense_info + sizeof(unsigned short); +		sense_len = +		    cpu_to_be16((unsigned short)(sts_bhs->sense_info[0])); +		memcpy(task->sc->sense_buffer, sense, +		       min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); +	} +	if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) { +		if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] +							& SOL_RES_CNT_MASK) +			 conn->rxdata_octets += (psol-> +			      dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] +							& SOL_RES_CNT_MASK); +	} +unmap: +	scsi_dma_unmap(io_task->scsi_cmnd); +	iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn); +} + +static void +be_complete_logout(struct beiscsi_conn *beiscsi_conn, +		   struct iscsi_task *task, struct sol_cqe *psol) +{ +	struct iscsi_logout_rsp *hdr; +	struct iscsi_conn *conn = beiscsi_conn->conn; + +	hdr = (struct iscsi_logout_rsp *)task->hdr; +	hdr->t2wait = 5; +	hdr->t2retain = 0; +	hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] +					& SOL_FLAGS_MASK) >> 24) | 0x80; +	hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / +					32] & SOL_RESP_MASK); +	hdr->exp_cmdsn = cpu_to_be32(psol-> +			dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] +					& SOL_EXP_CMD_SN_MASK); +	hdr->max_cmdsn = be32_to_cpu((psol-> +			 dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] +					& SOL_EXP_CMD_SN_MASK) + +			((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) +					/ 32] & SOL_CMD_WND_MASK) >> 24) - 1); +	hdr->hlength = 0; + +	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); +} + +static void +be_complete_tmf(struct beiscsi_conn *beiscsi_conn, +		struct iscsi_task *task, struct sol_cqe *psol) +{ +	struct iscsi_tm_rsp *hdr; +	struct iscsi_conn *conn = beiscsi_conn->conn; + +	hdr = (struct iscsi_tm_rsp *)task->hdr; +	hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] +					& SOL_FLAGS_MASK) >> 24) | 0x80; +	hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / +					32] & SOL_RESP_MASK); +	hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe, +				     i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK); +	hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe, +			i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) + +			((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) +			/ 32] & SOL_CMD_WND_MASK) >> 24) - 1); +	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); +} + +static void +hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, +		       struct beiscsi_hba *phba, struct sol_cqe *psol) +{ +	struct hwi_wrb_context *pwrb_context; +	struct wrb_handle *pwrb_handle; +	struct hwi_controller *phwi_ctrlr; +	struct iscsi_conn *conn = beiscsi_conn->conn; +	struct iscsi_session *session = conn->session; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pwrb_context = &phwi_ctrlr->wrb_context[((psol-> +				dw[offsetof(struct amap_sol_cqe, cid) / 32] & +				SOL_CID_MASK) >> 6)]; +	pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> +				dw[offsetof(struct amap_sol_cqe, wrb_index) / +				32] & SOL_WRB_INDEX_MASK) >> 16)]; +	spin_lock_bh(&session->lock); +	free_wrb_handle(phba, pwrb_context, pwrb_handle); +	spin_unlock_bh(&session->lock); +} + +static void +be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn, +		       struct iscsi_task *task, struct sol_cqe *psol) +{ +	struct iscsi_nopin *hdr; +	struct iscsi_conn *conn = beiscsi_conn->conn; + +	hdr = (struct iscsi_nopin *)task->hdr; +	hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] +			& SOL_FLAGS_MASK) >> 24) | 0x80; +	hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe, +				     i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK); +	hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe, +			i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) + +			((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) +			/ 32] & SOL_CMD_WND_MASK) >> 24) - 1); +	hdr->opcode = ISCSI_OP_NOOP_IN; +	__iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); +} + +static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, +			     struct beiscsi_hba *phba, struct sol_cqe *psol) +{ +	struct hwi_wrb_context *pwrb_context; +	struct wrb_handle *pwrb_handle; +	struct iscsi_wrb *pwrb = NULL; +	struct hwi_controller *phwi_ctrlr; +	struct iscsi_task *task; +	struct beiscsi_io_task *io_task; +	struct iscsi_conn *conn = beiscsi_conn->conn; +	struct iscsi_session *session = conn->session; + +	phwi_ctrlr = phba->phwi_ctrlr; + +	pwrb_context = &phwi_ctrlr-> +		wrb_context[((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32] +		& SOL_CID_MASK) >> 6)]; +	pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> +				dw[offsetof(struct amap_sol_cqe, wrb_index) / +				32] & SOL_WRB_INDEX_MASK) >> 16)]; + +	task = pwrb_handle->pio_handle; +	io_task = task->dd_data; +	spin_lock_bh(&session->lock); +	pwrb = pwrb_handle->pwrb; +	switch ((pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & +		 WRB_TYPE_MASK) >> 28) { +	case HWH_TYPE_IO: +	case HWH_TYPE_IO_RD: +		if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == +		    ISCSI_OP_NOOP_OUT) { +			be_complete_nopin_resp(beiscsi_conn, task, psol); +		} else +			be_complete_io(beiscsi_conn, task, psol); +		break; + +	case HWH_TYPE_LOGOUT: +		be_complete_logout(beiscsi_conn, task, psol); +		break; + +	case HWH_TYPE_LOGIN: +		SE_DEBUG(DBG_LVL_1, +			 "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd" +			 "- Solicited path \n"); +		break; + +	case HWH_TYPE_TMF: +		be_complete_tmf(beiscsi_conn, task, psol); +		break; + +	case HWH_TYPE_NOP: +		be_complete_nopin_resp(beiscsi_conn, task, psol); +		break; + +	default: +		shost_printk(KERN_WARNING, phba->shost, +			    "wrb_index 0x%x CID 0x%x\n", +			    ((psol->dw[offsetof(struct amap_iscsi_wrb, type) / +					32] & SOL_WRB_INDEX_MASK) >> 16), +			    ((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32] +					& SOL_CID_MASK) >> 6)); +		break; +	} + +	spin_unlock_bh(&session->lock); +} + +static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context +					  *pasync_ctx, unsigned int is_header, +					  unsigned int host_write_ptr) +{ +	if (is_header) +		return &pasync_ctx->async_entry[host_write_ptr]. +		    header_busy_list; +	else +		return &pasync_ctx->async_entry[host_write_ptr].data_busy_list; +} + +static struct async_pdu_handle * +hwi_get_async_handle(struct beiscsi_hba *phba, +		     struct beiscsi_conn *beiscsi_conn, +		     struct hwi_async_pdu_context *pasync_ctx, +		     struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index) +{ +	struct be_bus_address phys_addr; +	struct list_head *pbusy_list; +	struct async_pdu_handle *pasync_handle = NULL; +	int buffer_len = 0; +	unsigned char buffer_index = -1; +	unsigned char is_header = 0; + +	phys_addr.u.a32.address_lo = +	    pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_lo) / 32] - +	    ((pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] +						& PDUCQE_DPL_MASK) >> 16); +	phys_addr.u.a32.address_hi = +	    pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_hi) / 32]; + +	phys_addr.u.a64.address = +			*((unsigned long long *)(&phys_addr.u.a64.address)); + +	switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32] +			& PDUCQE_CODE_MASK) { +	case UNSOL_HDR_NOTIFY: +		is_header = 1; + +		pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1, +			(pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, +			index) / 32] & PDUCQE_INDEX_MASK)); + +		buffer_len = (unsigned int)(phys_addr.u.a64.address - +				pasync_ctx->async_header.pa_base.u.a64.address); + +		buffer_index = buffer_len / +				pasync_ctx->async_header.buffer_size; + +		break; +	case UNSOL_DATA_NOTIFY: +		pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe-> +					dw[offsetof(struct amap_i_t_dpdu_cqe, +					index) / 32] & PDUCQE_INDEX_MASK)); +		buffer_len = (unsigned long)(phys_addr.u.a64.address - +					pasync_ctx->async_data.pa_base.u. +					a64.address); +		buffer_index = buffer_len / pasync_ctx->async_data.buffer_size; +		break; +	default: +		pbusy_list = NULL; +		shost_printk(KERN_WARNING, phba->shost, +			"Unexpected code=%d \n", +			 pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, +					code) / 32] & PDUCQE_CODE_MASK); +		return NULL; +	} + +	WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries)); +	WARN_ON(list_empty(pbusy_list)); +	list_for_each_entry(pasync_handle, pbusy_list, link) { +		WARN_ON(pasync_handle->consumed); +		if (pasync_handle->index == buffer_index) +			break; +	} + +	WARN_ON(!pasync_handle); + +	pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid; +	pasync_handle->is_header = is_header; +	pasync_handle->buffer_len = ((pdpdu_cqe-> +			dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] +			& PDUCQE_DPL_MASK) >> 16); + +	*pcq_index = (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, +			index) / 32] & PDUCQE_INDEX_MASK); +	return pasync_handle; +} + +static unsigned int +hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx, +			   unsigned int is_header, unsigned int cq_index) +{ +	struct list_head *pbusy_list; +	struct async_pdu_handle *pasync_handle; +	unsigned int num_entries, writables = 0; +	unsigned int *pep_read_ptr, *pwritables; + + +	if (is_header) { +		pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr; +		pwritables = &pasync_ctx->async_header.writables; +		num_entries = pasync_ctx->async_header.num_entries; +	} else { +		pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr; +		pwritables = &pasync_ctx->async_data.writables; +		num_entries = pasync_ctx->async_data.num_entries; +	} + +	while ((*pep_read_ptr) != cq_index) { +		(*pep_read_ptr)++; +		*pep_read_ptr = (*pep_read_ptr) % num_entries; + +		pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header, +						     *pep_read_ptr); +		if (writables == 0) +			WARN_ON(list_empty(pbusy_list)); + +		if (!list_empty(pbusy_list)) { +			pasync_handle = list_entry(pbusy_list->next, +						   struct async_pdu_handle, +						   link); +			WARN_ON(!pasync_handle); +			pasync_handle->consumed = 1; +		} + +		writables++; +	} + +	if (!writables) { +		SE_DEBUG(DBG_LVL_1, +			 "Duplicate notification received - index 0x%x!!\n", +			 cq_index); +		WARN_ON(1); +	} + +	*pwritables = *pwritables + writables; +	return 0; +} + +static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba, +				       unsigned int cri) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_async_pdu_context *pasync_ctx; +	struct async_pdu_handle *pasync_handle, *tmp_handle; +	struct list_head *plist; +	unsigned int i = 0; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); + +	plist  = &pasync_ctx->async_entry[cri].wait_queue.list; + +	list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { +		list_del(&pasync_handle->link); + +		if (i == 0) { +			list_add_tail(&pasync_handle->link, +				      &pasync_ctx->async_header.free_list); +			pasync_ctx->async_header.free_entries++; +			i++; +		} else { +			list_add_tail(&pasync_handle->link, +				      &pasync_ctx->async_data.free_list); +			pasync_ctx->async_data.free_entries++; +			i++; +		} +	} + +	INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list); +	pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0; +	pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; +	return 0; +} + +static struct phys_addr * +hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx, +		     unsigned int is_header, unsigned int host_write_ptr) +{ +	struct phys_addr *pasync_sge = NULL; + +	if (is_header) +		pasync_sge = pasync_ctx->async_header.ring_base; +	else +		pasync_sge = pasync_ctx->async_data.ring_base; + +	return pasync_sge + host_write_ptr; +} + +static void hwi_post_async_buffers(struct beiscsi_hba *phba, +				   unsigned int is_header) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_async_pdu_context *pasync_ctx; +	struct async_pdu_handle *pasync_handle; +	struct list_head *pfree_link, *pbusy_list; +	struct phys_addr *pasync_sge; +	unsigned int ring_id, num_entries; +	unsigned int host_write_num; +	unsigned int writables; +	unsigned int i = 0; +	u32 doorbell = 0; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); + +	if (is_header) { +		num_entries = pasync_ctx->async_header.num_entries; +		writables = min(pasync_ctx->async_header.writables, +				pasync_ctx->async_header.free_entries); +		pfree_link = pasync_ctx->async_header.free_list.next; +		host_write_num = pasync_ctx->async_header.host_write_ptr; +		ring_id = phwi_ctrlr->default_pdu_hdr.id; +	} else { +		num_entries = pasync_ctx->async_data.num_entries; +		writables = min(pasync_ctx->async_data.writables, +				pasync_ctx->async_data.free_entries); +		pfree_link = pasync_ctx->async_data.free_list.next; +		host_write_num = pasync_ctx->async_data.host_write_ptr; +		ring_id = phwi_ctrlr->default_pdu_data.id; +	} + +	writables = (writables / 8) * 8; +	if (writables) { +		for (i = 0; i < writables; i++) { +			pbusy_list = +			    hwi_get_async_busy_list(pasync_ctx, is_header, +						    host_write_num); +			pasync_handle = +			    list_entry(pfree_link, struct async_pdu_handle, +								link); +			WARN_ON(!pasync_handle); +			pasync_handle->consumed = 0; + +			pfree_link = pfree_link->next; + +			pasync_sge = hwi_get_ring_address(pasync_ctx, +						is_header, host_write_num); + +			pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; +			pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; + +			list_move(&pasync_handle->link, pbusy_list); + +			host_write_num++; +			host_write_num = host_write_num % num_entries; +		} + +		if (is_header) { +			pasync_ctx->async_header.host_write_ptr = +							host_write_num; +			pasync_ctx->async_header.free_entries -= writables; +			pasync_ctx->async_header.writables -= writables; +			pasync_ctx->async_header.busy_entries += writables; +		} else { +			pasync_ctx->async_data.host_write_ptr = host_write_num; +			pasync_ctx->async_data.free_entries -= writables; +			pasync_ctx->async_data.writables -= writables; +			pasync_ctx->async_data.busy_entries += writables; +		} + +		doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; +		doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; +		doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT; +		doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK) +					<< DB_DEF_PDU_CQPROC_SHIFT; + +		iowrite32(doorbell, phba->db_va + DB_RXULP0_OFFSET); +	} +} + +static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba, +					 struct beiscsi_conn *beiscsi_conn, +					 struct i_t_dpdu_cqe *pdpdu_cqe) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_async_pdu_context *pasync_ctx; +	struct async_pdu_handle *pasync_handle = NULL; +	unsigned int cq_index = -1; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); + +	pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, +					     pdpdu_cqe, &cq_index); +	BUG_ON(pasync_handle->is_header != 0); +	if (pasync_handle->consumed == 0) +		hwi_update_async_writables(pasync_ctx, pasync_handle->is_header, +					   cq_index); + +	hwi_free_async_msg(phba, pasync_handle->cri); +	hwi_post_async_buffers(phba, pasync_handle->is_header); +} + +static unsigned int +hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, +		  struct beiscsi_hba *phba, +		  struct hwi_async_pdu_context *pasync_ctx, unsigned short cri) +{ +	struct list_head *plist; +	struct async_pdu_handle *pasync_handle; +	void *phdr = NULL; +	unsigned int hdr_len = 0, buf_len = 0; +	unsigned int status, index = 0, offset = 0; +	void *pfirst_buffer = NULL; +	unsigned int num_buf = 0; + +	plist = &pasync_ctx->async_entry[cri].wait_queue.list; + +	list_for_each_entry(pasync_handle, plist, link) { +		if (index == 0) { +			phdr = pasync_handle->pbuffer; +			hdr_len = pasync_handle->buffer_len; +		} else { +			buf_len = pasync_handle->buffer_len; +			if (!num_buf) { +				pfirst_buffer = pasync_handle->pbuffer; +				num_buf++; +			} +			memcpy(pfirst_buffer + offset, +			       pasync_handle->pbuffer, buf_len); +			offset = buf_len; +		} +		index++; +	} + +	status = beiscsi_process_async_pdu(beiscsi_conn, phba, +					   beiscsi_conn->beiscsi_conn_cid, +					   phdr, hdr_len, pfirst_buffer, +					   buf_len); + +	if (status == 0) +		hwi_free_async_msg(phba, cri); +	return 0; +} + +static unsigned int +hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn, +		     struct beiscsi_hba *phba, +		     struct async_pdu_handle *pasync_handle) +{ +	struct hwi_async_pdu_context *pasync_ctx; +	struct hwi_controller *phwi_ctrlr; +	unsigned int bytes_needed = 0, status = 0; +	unsigned short cri = pasync_handle->cri; +	struct pdu_base *ppdu; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); + +	list_del(&pasync_handle->link); +	if (pasync_handle->is_header) { +		pasync_ctx->async_header.busy_entries--; +		if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { +			hwi_free_async_msg(phba, cri); +			BUG(); +		} + +		pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; +		pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1; +		pasync_ctx->async_entry[cri].wait_queue.hdr_len = +				(unsigned short)pasync_handle->buffer_len; +		list_add_tail(&pasync_handle->link, +			      &pasync_ctx->async_entry[cri].wait_queue.list); + +		ppdu = pasync_handle->pbuffer; +		bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base, +			data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) & +			0xFFFF0000) | ((be16_to_cpu((ppdu-> +			dw[offsetof(struct amap_pdu_base, data_len_lo) / 32] +			& PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF)); + +		if (status == 0) { +			pasync_ctx->async_entry[cri].wait_queue.bytes_needed = +			    bytes_needed; + +			if (bytes_needed == 0) +				status = hwi_fwd_async_msg(beiscsi_conn, phba, +							   pasync_ctx, cri); +		} +	} else { +		pasync_ctx->async_data.busy_entries--; +		if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { +			list_add_tail(&pasync_handle->link, +				      &pasync_ctx->async_entry[cri].wait_queue. +				      list); +			pasync_ctx->async_entry[cri].wait_queue. +				bytes_received += +				(unsigned short)pasync_handle->buffer_len; + +			if (pasync_ctx->async_entry[cri].wait_queue. +			    bytes_received >= +			    pasync_ctx->async_entry[cri].wait_queue. +			    bytes_needed) +				status = hwi_fwd_async_msg(beiscsi_conn, phba, +							   pasync_ctx, cri); +		} +	} +	return status; +} + +static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, +					 struct beiscsi_hba *phba, +					 struct i_t_dpdu_cqe *pdpdu_cqe) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_async_pdu_context *pasync_ctx; +	struct async_pdu_handle *pasync_handle = NULL; +	unsigned int cq_index = -1; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); +	pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, +					     pdpdu_cqe, &cq_index); + +	if (pasync_handle->consumed == 0) +		hwi_update_async_writables(pasync_ctx, pasync_handle->is_header, +					   cq_index); +	hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle); +	hwi_post_async_buffers(phba, pasync_handle->is_header); +} + +static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	struct be_queue_info *cq; +	struct sol_cqe *sol; +	struct dmsg_cqe *dmsg; +	unsigned int num_processed = 0; +	unsigned int tot_nump = 0; +	struct beiscsi_conn *beiscsi_conn; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; +	cq = &phwi_context->be_cq; +	sol = queue_tail_node(cq); + +	while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] & +	       CQE_VALID_MASK) { +		be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); + +		beiscsi_conn = phba->conn_table[(u32) (sol-> +				 dw[offsetof(struct amap_sol_cqe, cid) / 32] & +				 SOL_CID_MASK) >> 6]; + +		if (!beiscsi_conn || !beiscsi_conn->ep) { +			shost_printk(KERN_WARNING, phba->shost, +				     "Connection table empty for cid = %d\n", +				     (u32)(sol->dw[offsetof(struct amap_sol_cqe, +				     cid) / 32] & SOL_CID_MASK) >> 6); +			return 0; +		} + +		if (num_processed >= 32) { +			hwi_ring_cq_db(phba, phwi_context->be_cq.id, +					num_processed, 0, 0); +			tot_nump += num_processed; +			num_processed = 0; +		} + +		switch ((u32) sol->dw[offsetof(struct amap_sol_cqe, code) / +			32] & CQE_CODE_MASK) { +		case SOL_CMD_COMPLETE: +			hwi_complete_cmd(beiscsi_conn, phba, sol); +			break; +		case DRIVERMSG_NOTIFY: +			SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n"); +			dmsg = (struct dmsg_cqe *)sol; +			hwi_complete_drvr_msgs(beiscsi_conn, phba, sol); +			break; +		case UNSOL_HDR_NOTIFY: +		case UNSOL_DATA_NOTIFY: +			SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR/DATA_NOTIFY\n"); +			hwi_process_default_pdu_ring(beiscsi_conn, phba, +					     (struct i_t_dpdu_cqe *)sol); +			break; +		case CXN_INVALIDATE_INDEX_NOTIFY: +		case CMD_INVALIDATED_NOTIFY: +		case CXN_INVALIDATE_NOTIFY: +			SE_DEBUG(DBG_LVL_1, +				 "Ignoring CQ Error notification for cmd/cxn" +				 "invalidate\n"); +			break; +		case SOL_CMD_KILLED_DATA_DIGEST_ERR: +		case CMD_KILLED_INVALID_STATSN_RCVD: +		case CMD_KILLED_INVALID_R2T_RCVD: +		case CMD_CXN_KILLED_LUN_INVALID: +		case CMD_CXN_KILLED_ICD_INVALID: +		case CMD_CXN_KILLED_ITT_INVALID: +		case CMD_CXN_KILLED_SEQ_OUTOFORDER: +		case CMD_CXN_KILLED_INVALID_DATASN_RCVD: +			SE_DEBUG(DBG_LVL_1, +				 "CQ Error notification for cmd.. " +				 "code %d cid 0x%x\n", +				 sol->dw[offsetof(struct amap_sol_cqe, code) / +				 32] & CQE_CODE_MASK, +				 (sol->dw[offsetof(struct amap_sol_cqe, cid) / +				 32] & SOL_CID_MASK)); +			break; +		case UNSOL_DATA_DIGEST_ERROR_NOTIFY: +			SE_DEBUG(DBG_LVL_1, +				 "Digest error on def pdu ring, dropping..\n"); +			hwi_flush_default_pdu_buffer(phba, beiscsi_conn, +					     (struct i_t_dpdu_cqe *) sol); +			break; +		case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL: +		case CXN_KILLED_BURST_LEN_MISMATCH: +		case CXN_KILLED_AHS_RCVD: +		case CXN_KILLED_HDR_DIGEST_ERR: +		case CXN_KILLED_UNKNOWN_HDR: +		case CXN_KILLED_STALE_ITT_TTT_RCVD: +		case CXN_KILLED_INVALID_ITT_TTT_RCVD: +		case CXN_KILLED_TIMED_OUT: +		case CXN_KILLED_FIN_RCVD: +		case CXN_KILLED_BAD_UNSOL_PDU_RCVD: +		case CXN_KILLED_BAD_WRB_INDEX_ERROR: +		case CXN_KILLED_OVER_RUN_RESIDUAL: +		case CXN_KILLED_UNDER_RUN_RESIDUAL: +		case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: +			SE_DEBUG(DBG_LVL_1, "CQ Error %d, resetting CID " +				 "0x%x...\n", +				 sol->dw[offsetof(struct amap_sol_cqe, code) / +				 32] & CQE_CODE_MASK, +				 sol->dw[offsetof(struct amap_sol_cqe, cid) / +				 32] & CQE_CID_MASK); +			iscsi_conn_failure(beiscsi_conn->conn, +					   ISCSI_ERR_CONN_FAILED); +			break; +		case CXN_KILLED_RST_SENT: +		case CXN_KILLED_RST_RCVD: +			SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset received/sent " +				 "on CID 0x%x...\n", +				 sol->dw[offsetof(struct amap_sol_cqe, code) / +				 32] & CQE_CODE_MASK, +				 sol->dw[offsetof(struct amap_sol_cqe, cid) / +				 32] & CQE_CID_MASK); +			iscsi_conn_failure(beiscsi_conn->conn, +					   ISCSI_ERR_CONN_FAILED); +			break; +		default: +			SE_DEBUG(DBG_LVL_1, "CQ Error Invalid code= %d " +				 "received on CID 0x%x...\n", +				 sol->dw[offsetof(struct amap_sol_cqe, code) / +				 32] & CQE_CODE_MASK, +				 sol->dw[offsetof(struct amap_sol_cqe, cid) / +				 32] & CQE_CID_MASK); +			break; +		} + +		AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0); +		queue_tail_inc(cq); +		sol = queue_tail_node(cq); +		num_processed++; +	} + +	if (num_processed > 0) { +		tot_nump += num_processed; +		hwi_ring_cq_db(phba, phwi_context->be_cq.id, num_processed, +			       1, 0); +	} +	return tot_nump; +} + +static void beiscsi_process_all_cqs(struct work_struct *work) +{ +	unsigned long flags; +	struct beiscsi_hba *phba = +	    container_of(work, struct beiscsi_hba, work_cqs); + +	if (phba->todo_mcc_cq) { +		spin_lock_irqsave(&phba->isr_lock, flags); +		phba->todo_mcc_cq = 0; +		spin_unlock_irqrestore(&phba->isr_lock, flags); +		SE_DEBUG(DBG_LVL_1, "MCC Interrupt Not expected \n"); +	} + +	if (phba->todo_cq) { +		spin_lock_irqsave(&phba->isr_lock, flags); +		phba->todo_cq = 0; +		spin_unlock_irqrestore(&phba->isr_lock, flags); +		beiscsi_process_cq(phba); +	} +} + +static int be_iopoll(struct blk_iopoll *iop, int budget) +{ +	static unsigned int ret; +	struct beiscsi_hba *phba; + +	phba = container_of(iop, struct beiscsi_hba, iopoll); + +	ret = beiscsi_process_cq(phba); +	if (ret < budget) { +		struct hwi_controller *phwi_ctrlr; +		struct hwi_context_memory *phwi_context; + +		phwi_ctrlr = phba->phwi_ctrlr; +		phwi_context = phwi_ctrlr->phwi_ctxt; +		blk_iopoll_complete(iop); +		hwi_ring_eq_db(phba, phwi_context->be_eq.q.id, 0, +							0, 1, 1); +	} +	return ret; +} + +static void +hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, +	      unsigned int num_sg, struct beiscsi_io_task *io_task) +{ +	struct iscsi_sge *psgl; +	unsigned short sg_len, index; +	unsigned int sge_len = 0; +	unsigned long long addr; +	struct scatterlist *l_sg; +	unsigned int offset; + +	AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, +				      io_task->bhs_pa.u.a32.address_lo); +	AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, +				      io_task->bhs_pa.u.a32.address_hi); + +	l_sg = sg; +	for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) { +		if (index == 0) { +			sg_len = sg_dma_len(sg); +			addr = (u64) sg_dma_address(sg); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, +							(addr & 0xFFFFFFFF)); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, +							(addr >> 32)); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, +							sg_len); +			sge_len = sg_len; +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, +							1); +		} else { +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, +							0); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, +							pwrb, sge_len); +			sg_len = sg_dma_len(sg); +			addr = (u64) sg_dma_address(sg); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb, +							(addr & 0xFFFFFFFF)); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb, +							(addr >> 32)); +			AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb, +							sg_len); +		} +	} +	psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; +	memset(psgl, 0, sizeof(*psgl) * BE2_SGE); + +	AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2); + +	AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, +			io_task->bhs_pa.u.a32.address_hi); +	AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, +			io_task->bhs_pa.u.a32.address_lo); + +	if (num_sg == 2) +		AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1); +	sg = l_sg; +	psgl++; +	psgl++; +	offset = 0; +	for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) { +		sg_len = sg_dma_len(sg); +		addr = (u64) sg_dma_address(sg); +		AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, +						(addr & 0xFFFFFFFF)); +		AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, +						(addr >> 32)); +		AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len); +		AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset); +		AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); +		offset += sg_len; +	} +	psgl--; +	AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); +} + +static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) +{ +	struct iscsi_sge *psgl; +	unsigned long long addr; +	struct beiscsi_io_task *io_task = task->dd_data; +	struct beiscsi_conn *beiscsi_conn = io_task->conn; +	struct beiscsi_hba *phba = beiscsi_conn->phba; + +	io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2; +	AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, +				io_task->bhs_pa.u.a32.address_lo); +	AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, +				io_task->bhs_pa.u.a32.address_hi); + +	if (task->data) { +		if (task->data_count) { +			AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); +			addr = (u64) pci_map_single(phba->pcidev, +						    task->data, +						    task->data_count, 1); +		} else { +			AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); +			addr = 0; +		} +		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, +						(addr & 0xFFFFFFFF)); +		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, +						(addr >> 32)); +		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, +						task->data_count); + +		AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1); +	} else { +		AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); +		addr = 0; +	} + +	psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; + +	AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len); + +	AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, +		      io_task->bhs_pa.u.a32.address_hi); +	AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, +		      io_task->bhs_pa.u.a32.address_lo); +	if (task->data) { +		psgl++; +		AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 0); +		AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 0); +		AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0); +		AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, 0); +		AMAP_SET_BITS(struct amap_iscsi_sge, rsvd0, psgl, 0); +		AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); + +		psgl++; +		if (task->data) { +			AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, +						(addr & 0xFFFFFFFF)); +			AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, +						(addr >> 32)); +		} +		AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106); +	} +	AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); +} + +static void beiscsi_find_mem_req(struct beiscsi_hba *phba) +{ +	unsigned int num_cq_pages, num_eq_pages, num_async_pdu_buf_pages; +	unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn; +	unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages; + +	num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ +				      sizeof(struct sol_cqe)); +	num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \ +				      sizeof(struct be_eq_entry)); +	num_async_pdu_buf_pages = +			PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ +				       phba->params.defpdu_hdr_sz); +	num_async_pdu_buf_sgl_pages = +			PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ +				       sizeof(struct phys_addr)); +	num_async_pdu_data_pages = +			PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ +				       phba->params.defpdu_data_sz); +	num_async_pdu_data_sgl_pages = +			PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ +				       sizeof(struct phys_addr)); + +	phba->params.hwi_ws_sz = sizeof(struct hwi_controller); + +	phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 * +						 BE_ISCSI_PDU_HEADER_SIZE; +	phba->mem_req[HWI_MEM_ADDN_CONTEXT] = +					    sizeof(struct hwi_context_memory); + +	phba->mem_req[HWI_MEM_CQ] = num_cq_pages * PAGE_SIZE; +	phba->mem_req[HWI_MEM_EQ] = num_eq_pages * PAGE_SIZE; + +	phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb) +	    * (phba->params.wrbs_per_cxn) +	    * phba->params.cxns_per_ctrl; +	wrb_sz_per_cxn =  sizeof(struct wrb_handle) * +				 (phba->params.wrbs_per_cxn); +	phba->mem_req[HWI_MEM_WRBH] = roundup_pow_of_two((wrb_sz_per_cxn) * +				phba->params.cxns_per_ctrl); + +	phba->mem_req[HWI_MEM_SGLH] = sizeof(struct sgl_handle) * +		phba->params.icds_per_ctrl; +	phba->mem_req[HWI_MEM_SGE] = sizeof(struct iscsi_sge) * +		phba->params.num_sge_per_io * phba->params.icds_per_ctrl; + +	phba->mem_req[HWI_MEM_ASYNC_HEADER_BUF] = +		num_async_pdu_buf_pages * PAGE_SIZE; +	phba->mem_req[HWI_MEM_ASYNC_DATA_BUF] = +		num_async_pdu_data_pages * PAGE_SIZE; +	phba->mem_req[HWI_MEM_ASYNC_HEADER_RING] = +		num_async_pdu_buf_sgl_pages * PAGE_SIZE; +	phba->mem_req[HWI_MEM_ASYNC_DATA_RING] = +		num_async_pdu_data_sgl_pages * PAGE_SIZE; +	phba->mem_req[HWI_MEM_ASYNC_HEADER_HANDLE] = +		phba->params.asyncpdus_per_ctrl * +		sizeof(struct async_pdu_handle); +	phba->mem_req[HWI_MEM_ASYNC_DATA_HANDLE] = +		phba->params.asyncpdus_per_ctrl * +		sizeof(struct async_pdu_handle); +	phba->mem_req[HWI_MEM_ASYNC_PDU_CONTEXT] = +		sizeof(struct hwi_async_pdu_context) + +		(phba->params.cxns_per_ctrl * sizeof(struct hwi_async_entry)); +} + +static int beiscsi_alloc_mem(struct beiscsi_hba *phba) +{ +	struct be_mem_descriptor *mem_descr; +	dma_addr_t bus_add; +	struct mem_array *mem_arr, *mem_arr_orig; +	unsigned int i, j, alloc_size, curr_alloc_size; + +	phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL); +	if (!phba->phwi_ctrlr) +		return -ENOMEM; + +	phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr), +				 GFP_KERNEL); +	if (!phba->init_mem) { +		kfree(phba->phwi_ctrlr); +		return -ENOMEM; +	} + +	mem_arr_orig = kmalloc(sizeof(*mem_arr_orig) * BEISCSI_MAX_FRAGS_INIT, +			       GFP_KERNEL); +	if (!mem_arr_orig) { +		kfree(phba->init_mem); +		kfree(phba->phwi_ctrlr); +		return -ENOMEM; +	} + +	mem_descr = phba->init_mem; +	for (i = 0; i < SE_MEM_MAX; i++) { +		j = 0; +		mem_arr = mem_arr_orig; +		alloc_size = phba->mem_req[i]; +		memset(mem_arr, 0, sizeof(struct mem_array) * +		       BEISCSI_MAX_FRAGS_INIT); +		curr_alloc_size = min(be_max_phys_size * 1024, alloc_size); +		do { +			mem_arr->virtual_address = pci_alloc_consistent( +							phba->pcidev, +							curr_alloc_size, +							&bus_add); +			if (!mem_arr->virtual_address) { +				if (curr_alloc_size <= BE_MIN_MEM_SIZE) +					goto free_mem; +				if (curr_alloc_size - +					rounddown_pow_of_two(curr_alloc_size)) +					curr_alloc_size = rounddown_pow_of_two +							     (curr_alloc_size); +				else +					curr_alloc_size = curr_alloc_size / 2; +			} else { +				mem_arr->bus_address.u. +				    a64.address = (__u64) bus_add; +				mem_arr->size = curr_alloc_size; +				alloc_size -= curr_alloc_size; +				curr_alloc_size = min(be_max_phys_size * +						      1024, alloc_size); +				j++; +				mem_arr++; +			} +		} while (alloc_size); +		mem_descr->num_elements = j; +		mem_descr->size_in_bytes = phba->mem_req[i]; +		mem_descr->mem_array = kmalloc(sizeof(*mem_arr) * j, +					       GFP_KERNEL); +		if (!mem_descr->mem_array) +			goto free_mem; + +		memcpy(mem_descr->mem_array, mem_arr_orig, +		       sizeof(struct mem_array) * j); +		mem_descr++; +	} +	kfree(mem_arr_orig); +	return 0; +free_mem: +	mem_descr->num_elements = j; +	while ((i) || (j)) { +		for (j = mem_descr->num_elements; j > 0; j--) { +			pci_free_consistent(phba->pcidev, +					    mem_descr->mem_array[j - 1].size, +					    mem_descr->mem_array[j - 1]. +					    virtual_address, +					    mem_descr->mem_array[j - 1]. +					    bus_address.u.a64.address); +		} +		if (i) { +			i--; +			kfree(mem_descr->mem_array); +			mem_descr--; +		} +	} +	kfree(mem_arr_orig); +	kfree(phba->init_mem); +	kfree(phba->phwi_ctrlr); +	return -ENOMEM; +} + +static int beiscsi_get_memory(struct beiscsi_hba *phba) +{ +	beiscsi_find_mem_req(phba); +	return beiscsi_alloc_mem(phba); +} + +static void iscsi_init_global_templates(struct beiscsi_hba *phba) +{ +	struct pdu_data_out *pdata_out; +	struct pdu_nop_out *pnop_out; +	struct be_mem_descriptor *mem_descr; + +	mem_descr = phba->init_mem; +	mem_descr += ISCSI_MEM_GLOBAL_HEADER; +	pdata_out = +	    (struct pdu_data_out *)mem_descr->mem_array[0].virtual_address; +	memset(pdata_out, 0, BE_ISCSI_PDU_HEADER_SIZE); + +	AMAP_SET_BITS(struct amap_pdu_data_out, opcode, pdata_out, +		      IIOC_SCSI_DATA); + +	pnop_out = +	    (struct pdu_nop_out *)((unsigned char *)mem_descr->mem_array[0]. +				   virtual_address + BE_ISCSI_PDU_HEADER_SIZE); + +	memset(pnop_out, 0, BE_ISCSI_PDU_HEADER_SIZE); +	AMAP_SET_BITS(struct amap_pdu_nop_out, ttt, pnop_out, 0xFFFFFFFF); +	AMAP_SET_BITS(struct amap_pdu_nop_out, f_bit, pnop_out, 1); +	AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0); +} + +static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) +{ +	struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb; +	struct wrb_handle *pwrb_handle; +	struct hwi_controller *phwi_ctrlr; +	struct hwi_wrb_context *pwrb_context; +	struct iscsi_wrb *pwrb; +	unsigned int num_cxn_wrbh; +	unsigned int num_cxn_wrb, j, idx, index; + +	mem_descr_wrbh = phba->init_mem; +	mem_descr_wrbh += HWI_MEM_WRBH; + +	mem_descr_wrb = phba->init_mem; +	mem_descr_wrb += HWI_MEM_WRB; + +	idx = 0; +	pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address; +	num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) / +			((sizeof(struct wrb_handle)) * +			 phba->params.wrbs_per_cxn)); +	phwi_ctrlr = phba->phwi_ctrlr; + +	for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { +		pwrb_context = &phwi_ctrlr->wrb_context[index]; +		SE_DEBUG(DBG_LVL_8, "cid=%d pwrb_context=%p \n", index, +						pwrb_context); +		pwrb_context->pwrb_handle_base = +				kzalloc(sizeof(struct wrb_handle *) * +					phba->params.wrbs_per_cxn, GFP_KERNEL); +		pwrb_context->pwrb_handle_basestd = +				kzalloc(sizeof(struct wrb_handle *) * +					phba->params.wrbs_per_cxn, GFP_KERNEL); +		if (num_cxn_wrbh) { +			pwrb_context->alloc_index = 0; +			pwrb_context->wrb_handles_available = 0; +			for (j = 0; j < phba->params.wrbs_per_cxn; j++) { +				pwrb_context->pwrb_handle_base[j] = pwrb_handle; +				pwrb_context->pwrb_handle_basestd[j] = +								pwrb_handle; +				pwrb_context->wrb_handles_available++; +				pwrb_handle++; +			} +			pwrb_context->free_index = 0; +			num_cxn_wrbh--; +		} else { +			idx++; +			pwrb_handle = +			    mem_descr_wrbh->mem_array[idx].virtual_address; +			num_cxn_wrbh = +			    ((mem_descr_wrbh->mem_array[idx].size) / +			     ((sizeof(struct wrb_handle)) * +			      phba->params.wrbs_per_cxn)); +			pwrb_context->alloc_index = 0; +			for (j = 0; j < phba->params.wrbs_per_cxn; j++) { +				pwrb_context->pwrb_handle_base[j] = pwrb_handle; +				pwrb_context->pwrb_handle_basestd[j] = +				    pwrb_handle; +				pwrb_context->wrb_handles_available++; +				pwrb_handle++; +			} +			pwrb_context->free_index = 0; +			num_cxn_wrbh--; +		} +	} +	idx = 0; +	pwrb = mem_descr_wrb->mem_array[idx].virtual_address; +	num_cxn_wrb = +	    ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) * +	     phba->params.wrbs_per_cxn); + +	for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) { +		pwrb_context = &phwi_ctrlr->wrb_context[index]; +		if (num_cxn_wrb) { +			for (j = 0; j < phba->params.wrbs_per_cxn; j++) { +				pwrb_handle = pwrb_context->pwrb_handle_base[j]; +				pwrb_handle->pwrb = pwrb; +				pwrb++; +			} +			num_cxn_wrb--; +		} else { +			idx++; +			pwrb = mem_descr_wrb->mem_array[idx].virtual_address; +			num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) / +					(sizeof(struct iscsi_wrb)) * +					phba->params.wrbs_per_cxn); +			for (j = 0; j < phba->params.wrbs_per_cxn; j++) { +				pwrb_handle = pwrb_context->pwrb_handle_base[j]; +				pwrb_handle->pwrb = pwrb; +				pwrb++; +			} +			num_cxn_wrb--; +		} +	} +} + +static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hba_parameters *p = &phba->params; +	struct hwi_async_pdu_context *pasync_ctx; +	struct async_pdu_handle *pasync_header_h, *pasync_data_h; +	unsigned int index; +	struct be_mem_descriptor *mem_descr; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_PDU_CONTEXT; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_ctrlr->phwi_ctxt->pasync_ctx = (struct hwi_async_pdu_context *) +				mem_descr->mem_array[0].virtual_address; +	pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx; +	memset(pasync_ctx, 0, sizeof(*pasync_ctx)); + +	pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl; +	pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; +	pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; +	pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_HEADER_BUF; +	if (mem_descr->mem_array[0].virtual_address) { +		SE_DEBUG(DBG_LVL_8, +			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF" +			 "va=%p \n", mem_descr->mem_array[0].virtual_address); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			     "No Virtual address \n"); + +	pasync_ctx->async_header.va_base = +			mem_descr->mem_array[0].virtual_address; + +	pasync_ctx->async_header.pa_base.u.a64.address = +			mem_descr->mem_array[0].bus_address.u.a64.address; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_HEADER_RING; +	if (mem_descr->mem_array[0].virtual_address) { +		SE_DEBUG(DBG_LVL_8, +			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING" +			 "va=%p \n", mem_descr->mem_array[0].virtual_address); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			    "No Virtual address \n"); +	pasync_ctx->async_header.ring_base = +			mem_descr->mem_array[0].virtual_address; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE; +	if (mem_descr->mem_array[0].virtual_address) { +		SE_DEBUG(DBG_LVL_8, +			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE" +			 "va=%p \n", mem_descr->mem_array[0].virtual_address); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			    "No Virtual address \n"); + +	pasync_ctx->async_header.handle_base = +			mem_descr->mem_array[0].virtual_address; +	pasync_ctx->async_header.writables = 0; +	INIT_LIST_HEAD(&pasync_ctx->async_header.free_list); + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_DATA_BUF; +	if (mem_descr->mem_array[0].virtual_address) { +		SE_DEBUG(DBG_LVL_8, +			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF" +			 "va=%p \n", mem_descr->mem_array[0].virtual_address); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			    "No Virtual address \n"); +	pasync_ctx->async_data.va_base = +			mem_descr->mem_array[0].virtual_address; +	pasync_ctx->async_data.pa_base.u.a64.address = +			mem_descr->mem_array[0].bus_address.u.a64.address; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_DATA_RING; +	if (mem_descr->mem_array[0].virtual_address) { +		SE_DEBUG(DBG_LVL_8, +			 "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING" +			 "va=%p \n", mem_descr->mem_array[0].virtual_address); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			     "No Virtual address \n"); + +	pasync_ctx->async_data.ring_base = +			mem_descr->mem_array[0].virtual_address; + +	mem_descr = (struct be_mem_descriptor *)phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_DATA_HANDLE; +	if (!mem_descr->mem_array[0].virtual_address) +		shost_printk(KERN_WARNING, phba->shost, +			    "No Virtual address \n"); + +	pasync_ctx->async_data.handle_base = +			mem_descr->mem_array[0].virtual_address; +	pasync_ctx->async_data.writables = 0; +	INIT_LIST_HEAD(&pasync_ctx->async_data.free_list); + +	pasync_header_h = +		(struct async_pdu_handle *)pasync_ctx->async_header.handle_base; +	pasync_data_h = +		(struct async_pdu_handle *)pasync_ctx->async_data.handle_base; + +	for (index = 0; index < p->asyncpdus_per_ctrl; index++) { +		pasync_header_h->cri = -1; +		pasync_header_h->index = (char)index; +		INIT_LIST_HEAD(&pasync_header_h->link); +		pasync_header_h->pbuffer = +			(void *)((unsigned long) +			(pasync_ctx->async_header.va_base) + +			(p->defpdu_hdr_sz * index)); + +		pasync_header_h->pa.u.a64.address = +			pasync_ctx->async_header.pa_base.u.a64.address + +			(p->defpdu_hdr_sz * index); + +		list_add_tail(&pasync_header_h->link, +				&pasync_ctx->async_header.free_list); +		pasync_header_h++; +		pasync_ctx->async_header.free_entries++; +		pasync_ctx->async_header.writables++; + +		INIT_LIST_HEAD(&pasync_ctx->async_entry[index].wait_queue.list); +		INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. +			       header_busy_list); +		pasync_data_h->cri = -1; +		pasync_data_h->index = (char)index; +		INIT_LIST_HEAD(&pasync_data_h->link); +		pasync_data_h->pbuffer = +			(void *)((unsigned long) +			(pasync_ctx->async_data.va_base) + +			(p->defpdu_data_sz * index)); + +		pasync_data_h->pa.u.a64.address = +		    pasync_ctx->async_data.pa_base.u.a64.address + +		    (p->defpdu_data_sz * index); + +		list_add_tail(&pasync_data_h->link, +			      &pasync_ctx->async_data.free_list); +		pasync_data_h++; +		pasync_ctx->async_data.free_entries++; +		pasync_ctx->async_data.writables++; + +		INIT_LIST_HEAD(&pasync_ctx->async_entry[index].data_busy_list); +	} + +	pasync_ctx->async_header.host_write_ptr = 0; +	pasync_ctx->async_header.ep_read_ptr = -1; +	pasync_ctx->async_data.host_write_ptr = 0; +	pasync_ctx->async_data.ep_read_ptr = -1; +} + +static int +be_sgl_create_contiguous(void *virtual_address, +			 u64 physical_address, u32 length, +			 struct be_dma_mem *sgl) +{ +	WARN_ON(!virtual_address); +	WARN_ON(!physical_address); +	WARN_ON(!length > 0); +	WARN_ON(!sgl); + +	sgl->va = virtual_address; +	sgl->dma = physical_address; +	sgl->size = length; + +	return 0; +} + +static void be_sgl_destroy_contiguous(struct be_dma_mem *sgl) +{ +	memset(sgl, 0, sizeof(*sgl)); +} + +static void +hwi_build_be_sgl_arr(struct beiscsi_hba *phba, +		     struct mem_array *pmem, struct be_dma_mem *sgl) +{ +	if (sgl->va) +		be_sgl_destroy_contiguous(sgl); + +	be_sgl_create_contiguous(pmem->virtual_address, +				 pmem->bus_address.u.a64.address, +				 pmem->size, sgl); +} + +static void +hwi_build_be_sgl_by_offset(struct beiscsi_hba *phba, +			   struct mem_array *pmem, struct be_dma_mem *sgl) +{ +	if (sgl->va) +		be_sgl_destroy_contiguous(sgl); + +	be_sgl_create_contiguous((unsigned char *)pmem->virtual_address, +				 pmem->bus_address.u.a64.address, +				 pmem->size, sgl); +} + +static int be_fill_queue(struct be_queue_info *q, +		u16 len, u16 entry_size, void *vaddress) +{ +	struct be_dma_mem *mem = &q->dma_mem; + +	memset(q, 0, sizeof(*q)); +	q->len = len; +	q->entry_size = entry_size; +	mem->size = len * entry_size; +	mem->va = vaddress; +	if (!mem->va) +		return -ENOMEM; +	memset(mem->va, 0, mem->size); +	return 0; +} + +static int beiscsi_create_eq(struct beiscsi_hba *phba, +			     struct hwi_context_memory *phwi_context) +{ +	unsigned int idx; +	int ret; +	struct be_queue_info *eq; +	struct be_dma_mem *mem; +	struct be_mem_descriptor *mem_descr; +	void *eq_vaddress; + +	idx = 0; +	eq = &phwi_context->be_eq.q; +	mem = &eq->dma_mem; +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_EQ; +	eq_vaddress = mem_descr->mem_array[idx].virtual_address; + +	ret = be_fill_queue(eq, phba->params.num_eq_entries, +			    sizeof(struct be_eq_entry), eq_vaddress); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_fill_queue Failed for EQ \n"); +		return ret; +	} + +	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; + +	ret = beiscsi_cmd_eq_create(&phba->ctrl, eq, +				    phwi_context->be_eq.cur_eqd); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create" +			     "Failedfor EQ \n"); +		return ret; +	} +	SE_DEBUG(DBG_LVL_8, "eq id is %d\n", phwi_context->be_eq.q.id); +	return 0; +} + +static int beiscsi_create_cq(struct beiscsi_hba *phba, +			     struct hwi_context_memory *phwi_context) +{ +	unsigned int idx; +	int ret; +	struct be_queue_info *cq, *eq; +	struct be_dma_mem *mem; +	struct be_mem_descriptor *mem_descr; +	void *cq_vaddress; + +	idx = 0; +	cq = &phwi_context->be_cq; +	eq = &phwi_context->be_eq.q; +	mem = &cq->dma_mem; +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_CQ; +	cq_vaddress = mem_descr->mem_array[idx].virtual_address; +	ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2, +			    sizeof(struct sol_cqe), cq_vaddress); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_fill_queue Failed for ISCSI CQ \n"); +		return ret; +	} + +	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; +	ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, false, 0); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "beiscsi_cmd_eq_create Failed for ISCSI CQ \n"); +		return ret; +	} +	SE_DEBUG(DBG_LVL_8, "iscsi cq id is %d\n", phwi_context->be_cq.id); +	SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n"); +	return 0; +} + +static int +beiscsi_create_def_hdr(struct beiscsi_hba *phba, +		       struct hwi_context_memory *phwi_context, +		       struct hwi_controller *phwi_ctrlr, +		       unsigned int def_pdu_ring_sz) +{ +	unsigned int idx; +	int ret; +	struct be_queue_info *dq, *cq; +	struct be_dma_mem *mem; +	struct be_mem_descriptor *mem_descr; +	void *dq_vaddress; + +	idx = 0; +	dq = &phwi_context->be_def_hdrq; +	cq = &phwi_context->be_cq; +	mem = &dq->dma_mem; +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_HEADER_RING; +	dq_vaddress = mem_descr->mem_array[idx].virtual_address; +	ret = be_fill_queue(dq, mem_descr->mem_array[0].size / +			    sizeof(struct phys_addr), +			    sizeof(struct phys_addr), dq_vaddress); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_fill_queue Failed for DEF PDU HDR\n"); +		return ret; +	} +	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; +	ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq, +					      def_pdu_ring_sz, +					      phba->params.defpdu_hdr_sz); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_cmd_create_default_pdu_queue Failed DEFHDR\n"); +		return ret; +	} +	phwi_ctrlr->default_pdu_hdr.id = phwi_context->be_def_hdrq.id; +	SE_DEBUG(DBG_LVL_8, "iscsi def pdu id is %d\n", +		 phwi_context->be_def_hdrq.id); +	hwi_post_async_buffers(phba, 1); +	return 0; +} + +static int +beiscsi_create_def_data(struct beiscsi_hba *phba, +			struct hwi_context_memory *phwi_context, +			struct hwi_controller *phwi_ctrlr, +			unsigned int def_pdu_ring_sz) +{ +	unsigned int idx; +	int ret; +	struct be_queue_info *dataq, *cq; +	struct be_dma_mem *mem; +	struct be_mem_descriptor *mem_descr; +	void *dq_vaddress; + +	idx = 0; +	dataq = &phwi_context->be_def_dataq; +	cq = &phwi_context->be_cq; +	mem = &dataq->dma_mem; +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_ASYNC_DATA_RING; +	dq_vaddress = mem_descr->mem_array[idx].virtual_address; +	ret = be_fill_queue(dataq, mem_descr->mem_array[0].size / +			    sizeof(struct phys_addr), +			    sizeof(struct phys_addr), dq_vaddress); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_fill_queue Failed for DEF PDU DATA\n"); +		return ret; +	} +	mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; +	ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq, +					      def_pdu_ring_sz, +					      phba->params.defpdu_data_sz); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, +			     "be_cmd_create_default_pdu_queue Failed" +			     " for DEF PDU DATA\n"); +		return ret; +	} +	phwi_ctrlr->default_pdu_data.id = phwi_context->be_def_dataq.id; +	SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n", +		 phwi_context->be_def_dataq.id); +	hwi_post_async_buffers(phba, 0); +	SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n"); +	return 0; +} + +static int +beiscsi_post_pages(struct beiscsi_hba *phba) +{ +	struct be_mem_descriptor *mem_descr; +	struct mem_array *pm_arr; +	unsigned int page_offset, i; +	struct be_dma_mem sgl; +	int status; + +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_SGE; +	pm_arr = mem_descr->mem_array; + +	page_offset = (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io * +			phba->fw_config.iscsi_icd_start) / PAGE_SIZE; +	for (i = 0; i < mem_descr->num_elements; i++) { +		hwi_build_be_sgl_arr(phba, pm_arr, &sgl); +		status = be_cmd_iscsi_post_sgl_pages(&phba->ctrl, &sgl, +						page_offset, +						(pm_arr->size / PAGE_SIZE)); +		page_offset += pm_arr->size / PAGE_SIZE; +		if (status != 0) { +			shost_printk(KERN_ERR, phba->shost, +				     "post sgl failed.\n"); +			return status; +		} +		pm_arr++; +	} +	SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n"); +	return 0; +} + +static int +beiscsi_create_wrb_rings(struct beiscsi_hba *phba, +			 struct hwi_context_memory *phwi_context, +			 struct hwi_controller *phwi_ctrlr) +{ +	unsigned int wrb_mem_index, offset, size, num_wrb_rings; +	u64 pa_addr_lo; +	unsigned int idx, num, i; +	struct mem_array *pwrb_arr; +	void *wrb_vaddr; +	struct be_dma_mem sgl; +	struct be_mem_descriptor *mem_descr; +	int status; + +	idx = 0; +	mem_descr = phba->init_mem; +	mem_descr += HWI_MEM_WRB; +	pwrb_arr = kmalloc(sizeof(*pwrb_arr) * phba->params.cxns_per_ctrl, +			   GFP_KERNEL); +	if (!pwrb_arr) { +		shost_printk(KERN_ERR, phba->shost, +			     "Memory alloc failed in create wrb ring.\n"); +		return -ENOMEM; +	} +	wrb_vaddr = mem_descr->mem_array[idx].virtual_address; +	pa_addr_lo = mem_descr->mem_array[idx].bus_address.u.a64.address; +	num_wrb_rings = mem_descr->mem_array[idx].size / +		(phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb)); + +	for (num = 0; num < phba->params.cxns_per_ctrl; num++) { +		if (num_wrb_rings) { +			pwrb_arr[num].virtual_address = wrb_vaddr; +			pwrb_arr[num].bus_address.u.a64.address	= pa_addr_lo; +			pwrb_arr[num].size = phba->params.wrbs_per_cxn * +					    sizeof(struct iscsi_wrb); +			wrb_vaddr += pwrb_arr[num].size; +			pa_addr_lo += pwrb_arr[num].size; +			num_wrb_rings--; +		} else { +			idx++; +			wrb_vaddr = mem_descr->mem_array[idx].virtual_address; +			pa_addr_lo = mem_descr->mem_array[idx].\ +					bus_address.u.a64.address; +			num_wrb_rings = mem_descr->mem_array[idx].size / +					(phba->params.wrbs_per_cxn * +					sizeof(struct iscsi_wrb)); +			pwrb_arr[num].virtual_address = wrb_vaddr; +			pwrb_arr[num].bus_address.u.a64.address\ +						= pa_addr_lo; +			pwrb_arr[num].size = phba->params.wrbs_per_cxn * +						 sizeof(struct iscsi_wrb); +			wrb_vaddr += pwrb_arr[num].size; +			pa_addr_lo   += pwrb_arr[num].size; +			num_wrb_rings--; +		} +	} +	for (i = 0; i < phba->params.cxns_per_ctrl; i++) { +		wrb_mem_index = 0; +		offset = 0; +		size = 0; + +		hwi_build_be_sgl_by_offset(phba, &pwrb_arr[i], &sgl); +		status = be_cmd_wrbq_create(&phba->ctrl, &sgl, +					    &phwi_context->be_wrbq[i]); +		if (status != 0) { +			shost_printk(KERN_ERR, phba->shost, +				     "wrbq create failed."); +			return status; +		} +		phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id; +	} +	kfree(pwrb_arr); +	return 0; +} + +static void free_wrb_handles(struct beiscsi_hba *phba) +{ +	unsigned int index; +	struct hwi_controller *phwi_ctrlr; +	struct hwi_wrb_context *pwrb_context; + +	phwi_ctrlr = phba->phwi_ctrlr; +	for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { +		pwrb_context = &phwi_ctrlr->wrb_context[index]; +		kfree(pwrb_context->pwrb_handle_base); +		kfree(pwrb_context->pwrb_handle_basestd); +	} +} + +static void hwi_cleanup(struct beiscsi_hba *phba) +{ +	struct be_queue_info *q; +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	int i; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; +	for (i = 0; i < phba->params.cxns_per_ctrl; i++) { +		q = &phwi_context->be_wrbq[i]; +		if (q->created) +			beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ); +	} + +	free_wrb_handles(phba); + +	q = &phwi_context->be_def_hdrq; +	if (q->created) +		beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); + +	q = &phwi_context->be_def_dataq; +	if (q->created) +		beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); + +	beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); + +	q = &phwi_context->be_cq; +	if (q->created) +		beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); + +	q = &phwi_context->be_eq.q; +	if (q->created) +		beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ); +} + +static int hwi_init_port(struct beiscsi_hba *phba) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	unsigned int def_pdu_ring_sz; +	struct be_ctrl_info *ctrl = &phba->ctrl; +	int status; + +	def_pdu_ring_sz = +		phba->params.asyncpdus_per_ctrl * sizeof(struct phys_addr); +	phwi_ctrlr = phba->phwi_ctrlr; + +	phwi_context = phwi_ctrlr->phwi_ctxt; +	phwi_context->be_eq.max_eqd = 0; +	phwi_context->be_eq.min_eqd = 0; +	phwi_context->be_eq.cur_eqd = 64; +	phwi_context->be_eq.enable_aic = false; +	be_cmd_fw_initialize(&phba->ctrl); +	status = beiscsi_create_eq(phba, phwi_context); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, "EQ not created \n"); +		goto error; +	} + +	status = mgmt_check_supported_fw(ctrl); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "Unsupported fw version \n"); +		goto error; +	} + +	status = mgmt_get_fw_config(ctrl, phba); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "Error getting fw config\n"); +		goto error; +	} + +	status = beiscsi_create_cq(phba, phwi_context); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, "CQ not created\n"); +		goto error; +	} + +	status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr, +					def_pdu_ring_sz); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "Default Header not created\n"); +		goto error; +	} + +	status = beiscsi_create_def_data(phba, phwi_context, +					 phwi_ctrlr, def_pdu_ring_sz); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "Default Data not created\n"); +		goto error; +	} + +	status = beiscsi_post_pages(phba); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, "Post SGL Pages Failed\n"); +		goto error; +	} + +	status = beiscsi_create_wrb_rings(phba,	phwi_context, phwi_ctrlr); +	if (status != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "WRB Rings not created\n"); +		goto error; +	} + +	SE_DEBUG(DBG_LVL_8, "hwi_init_port success\n"); +	return 0; + +error: +	shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed"); +	hwi_cleanup(phba); +	return -ENOMEM; +} + + +static int hwi_init_controller(struct beiscsi_hba *phba) +{ +	struct hwi_controller *phwi_ctrlr; + +	phwi_ctrlr = phba->phwi_ctrlr; +	if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) { +		phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba-> +		    init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address; +		SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n", +			 phwi_ctrlr->phwi_ctxt); +	} else { +		shost_printk(KERN_ERR, phba->shost, +			     "HWI_MEM_ADDN_CONTEXT is more than one element." +			     "Failing to load\n"); +		return -ENOMEM; +	} + +	iscsi_init_global_templates(phba); +	beiscsi_init_wrb_handle(phba); +	hwi_init_async_pdu_ctx(phba); +	if (hwi_init_port(phba) != 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "hwi_init_controller failed\n"); +		return -ENOMEM; +	} +	return 0; +} + +static void beiscsi_free_mem(struct beiscsi_hba *phba) +{ +	struct be_mem_descriptor *mem_descr; +	int i, j; + +	mem_descr = phba->init_mem; +	i = 0; +	j = 0; +	for (i = 0; i < SE_MEM_MAX; i++) { +		for (j = mem_descr->num_elements; j > 0; j--) { +			pci_free_consistent(phba->pcidev, +			  mem_descr->mem_array[j - 1].size, +			  mem_descr->mem_array[j - 1].virtual_address, +			  mem_descr->mem_array[j - 1].bus_address. +				u.a64.address); +		} +		kfree(mem_descr->mem_array); +		mem_descr++; +	} +	kfree(phba->init_mem); +	kfree(phba->phwi_ctrlr); +} + +static int beiscsi_init_controller(struct beiscsi_hba *phba) +{ +	int ret = -ENOMEM; + +	ret = beiscsi_get_memory(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -" +			     "Failed in beiscsi_alloc_memory \n"); +		return ret; +	} + +	ret = hwi_init_controller(phba); +	if (ret) +		goto free_init; +	SE_DEBUG(DBG_LVL_8, "Return success from beiscsi_init_controller"); +	return 0; + +free_init: +	beiscsi_free_mem(phba); +	return -ENOMEM; +} + +static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) +{ +	struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg; +	struct sgl_handle *psgl_handle; +	struct iscsi_sge *pfrag; +	unsigned int arr_index, i, idx; + +	phba->io_sgl_hndl_avbl = 0; +	phba->eh_sgl_hndl_avbl = 0; +	mem_descr_sglh = phba->init_mem; +	mem_descr_sglh += HWI_MEM_SGLH; +	if (1 == mem_descr_sglh->num_elements) { +		phba->io_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * +						 phba->params.ios_per_ctrl, +						 GFP_KERNEL); +		if (!phba->io_sgl_hndl_base) { +			shost_printk(KERN_ERR, phba->shost, +				     "Mem Alloc Failed. Failing to load\n"); +			return -ENOMEM; +		} +		phba->eh_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * +						 (phba->params.icds_per_ctrl - +						 phba->params.ios_per_ctrl), +						 GFP_KERNEL); +		if (!phba->eh_sgl_hndl_base) { +			kfree(phba->io_sgl_hndl_base); +			shost_printk(KERN_ERR, phba->shost, +				     "Mem Alloc Failed. Failing to load\n"); +			return -ENOMEM; +		} +	} else { +		shost_printk(KERN_ERR, phba->shost, +			     "HWI_MEM_SGLH is more than one element." +			     "Failing to load\n"); +		return -ENOMEM; +	} + +	arr_index = 0; +	idx = 0; +	while (idx < mem_descr_sglh->num_elements) { +		psgl_handle = mem_descr_sglh->mem_array[idx].virtual_address; + +		for (i = 0; i < (mem_descr_sglh->mem_array[idx].size / +		      sizeof(struct sgl_handle)); i++) { +			if (arr_index < phba->params.ios_per_ctrl) { +				phba->io_sgl_hndl_base[arr_index] = psgl_handle; +				phba->io_sgl_hndl_avbl++; +				arr_index++; +			} else { +				phba->eh_sgl_hndl_base[arr_index - +					phba->params.ios_per_ctrl] = +								psgl_handle; +				arr_index++; +				phba->eh_sgl_hndl_avbl++; +			} +			psgl_handle++; +		} +		idx++; +	} +	SE_DEBUG(DBG_LVL_8, +		 "phba->io_sgl_hndl_avbl=%d" +		 "phba->eh_sgl_hndl_avbl=%d \n", +		 phba->io_sgl_hndl_avbl, +		 phba->eh_sgl_hndl_avbl); +	mem_descr_sg = phba->init_mem; +	mem_descr_sg += HWI_MEM_SGE; +	SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n", +		 mem_descr_sg->num_elements); +	arr_index = 0; +	idx = 0; +	while (idx < mem_descr_sg->num_elements) { +		pfrag = mem_descr_sg->mem_array[idx].virtual_address; + +		for (i = 0; +		     i < (mem_descr_sg->mem_array[idx].size) / +		     (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io); +		     i++) { +			if (arr_index < phba->params.ios_per_ctrl) +				psgl_handle = phba->io_sgl_hndl_base[arr_index]; +			else +				psgl_handle = phba->eh_sgl_hndl_base[arr_index - +						phba->params.ios_per_ctrl]; +			psgl_handle->pfrag = pfrag; +			AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, pfrag, 0); +			AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); +			pfrag += phba->params.num_sge_per_io; +			psgl_handle->sgl_index = +				phba->fw_config.iscsi_cid_start + arr_index++; +		} +		idx++; +	} +	phba->io_sgl_free_index = 0; +	phba->io_sgl_alloc_index = 0; +	phba->eh_sgl_free_index = 0; +	phba->eh_sgl_alloc_index = 0; +	return 0; +} + +static int hba_setup_cid_tbls(struct beiscsi_hba *phba) +{ +	int i, new_cid; + +	phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl, +				  GFP_KERNEL); +	if (!phba->cid_array) { +		shost_printk(KERN_ERR, phba->shost, +			     "Failed to allocate memory in " +			     "hba_setup_cid_tbls\n"); +		return -ENOMEM; +	} +	phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) * +				 phba->params.cxns_per_ctrl * 2, GFP_KERNEL); +	if (!phba->ep_array) { +		shost_printk(KERN_ERR, phba->shost, +			     "Failed to allocate memory in " +			     "hba_setup_cid_tbls \n"); +		kfree(phba->cid_array); +		return -ENOMEM; +	} +	new_cid = phba->fw_config.iscsi_icd_start; +	for (i = 0; i < phba->params.cxns_per_ctrl; i++) { +		phba->cid_array[i] = new_cid; +		new_cid += 2; +	} +	phba->avlbl_cids = phba->params.cxns_per_ctrl; +	return 0; +} + +static unsigned char hwi_enable_intr(struct beiscsi_hba *phba) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	struct be_queue_info *eq; +	u8 __iomem *addr; +	u32 reg; +	u32 enabled; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; + +	eq = &phwi_context->be_eq.q; +	addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + +			PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); +	reg = ioread32(addr); +	SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg); + +	enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; +	if (!enabled) { +		reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; +		SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr); +		iowrite32(reg, addr); +		SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id); + +		hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			     "In hwi_enable_intr, Not Enabled \n"); +	return true; +} + +static void hwi_disable_intr(struct beiscsi_hba *phba) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; + +	u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; +	u32 reg = ioread32(addr); + +	u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; +	if (enabled) { +		reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; +		iowrite32(reg, addr); +	} else +		shost_printk(KERN_WARNING, phba->shost, +			     "In hwi_disable_intr, Already Disabled \n"); +} + +static int beiscsi_init_port(struct beiscsi_hba *phba) +{ +	int ret; + +	ret = beiscsi_init_controller(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "beiscsi_dev_probe - Failed in" +			     "beiscsi_init_controller \n"); +		return ret; +	} +	ret = beiscsi_init_sgl_handle(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, +			     "beiscsi_dev_probe - Failed in" +			     "beiscsi_init_sgl_handle \n"); +		goto do_cleanup_ctrlr; +	} + +	if (hba_setup_cid_tbls(phba)) { +		shost_printk(KERN_ERR, phba->shost, +			     "Failed in hba_setup_cid_tbls\n"); +		kfree(phba->io_sgl_hndl_base); +		kfree(phba->eh_sgl_hndl_base); +		goto do_cleanup_ctrlr; +	} + +	return ret; + +do_cleanup_ctrlr: +	hwi_cleanup(phba); +	return ret; +} + +static void hwi_purge_eq(struct beiscsi_hba *phba) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	struct be_queue_info *eq; +	struct be_eq_entry *eqe = NULL; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; +	eq = &phwi_context->be_eq.q; +	eqe = queue_tail_node(eq); + +	while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] +						& EQE_VALID_MASK) { +		AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); +		queue_tail_inc(eq); +		eqe = queue_tail_node(eq); +	} +} + +static void beiscsi_clean_port(struct beiscsi_hba *phba) +{ +	unsigned char mgmt_status; + +	mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0); +	if (mgmt_status) +		shost_printk(KERN_WARNING, phba->shost, +			     "mgmt_epfw_cleanup FAILED \n"); +	hwi_cleanup(phba); +	hwi_purge_eq(phba); +	kfree(phba->io_sgl_hndl_base); +	kfree(phba->eh_sgl_hndl_base); +	kfree(phba->cid_array); +	kfree(phba->ep_array); +} + +void +beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, +			   struct beiscsi_offload_params *params) +{ +	struct wrb_handle *pwrb_handle; +	struct iscsi_target_context_update_wrb *pwrb = NULL; +	struct be_mem_descriptor *mem_descr; +	struct beiscsi_hba *phba = beiscsi_conn->phba; +	u32 doorbell = 0; + +	/* +	 * We can always use 0 here because it is reserved by libiscsi for +	 * login/startup related tasks. +	 */ +	pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0); +	pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; +	memset(pwrb, 0, sizeof(*pwrb)); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +		      max_burst_length, pwrb, params->dw[offsetof +		      (struct amap_beiscsi_offload_params, +		      max_burst_length) / 32]); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +		      max_send_data_segment_length, pwrb, +		      params->dw[offsetof(struct amap_beiscsi_offload_params, +		      max_send_data_segment_length) / 32]); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +		      first_burst_length, +		      pwrb, +		      params->dw[offsetof(struct amap_beiscsi_offload_params, +		      first_burst_length) / 32]); + +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		      erl) / 32] & OFFLD_PARAMS_ERL)); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		      dde) / 32] & OFFLD_PARAMS_DDE) >> 2); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		      hde) / 32] & OFFLD_PARAMS_HDE) >> 3); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		      ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		       imd) / 32] & OFFLD_PARAMS_IMD) >> 5); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn, +		      pwrb, +		      (params->dw[offsetof(struct amap_beiscsi_offload_params, +		      exp_statsn) / 32] + 1)); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb, +		      0x7); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx, +		      pwrb, pwrb_handle->wrb_index); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, +		      pwrb, pwrb_handle->nxt_wrb_index); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +			session_state, pwrb, 0); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, +		      pwrb, 1); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq, +		      pwrb, 0); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb, +		      0); + +	mem_descr = phba->init_mem; +	mem_descr += ISCSI_MEM_GLOBAL_HEADER; + +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +			pad_buffer_addr_hi, pwrb, +		      mem_descr->mem_array[0].bus_address.u.a32.address_hi); +	AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, +			pad_buffer_addr_lo, pwrb, +		      mem_descr->mem_array[0].bus_address.u.a32.address_lo); + +	be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb)); + +	doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; +	doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) << +					DB_DEF_PDU_WRB_INDEX_SHIFT; +	doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; + +	iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); +} + +static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt, +			      int *index, int *age) +{ +	*index = be32_to_cpu(itt) >> 16; +	if (age) +		*age = conn->session->age; +} + +/** + * beiscsi_alloc_pdu - allocates pdu and related resources + * @task: libiscsi task + * @opcode: opcode of pdu for task + * + * This is called with the session lock held. It will allocate + * the wrb and sgl if needed for the command. And it will prep + * the pdu's itt. beiscsi_parse_pdu will later translate + * the pdu itt to the libiscsi task itt. + */ +static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) +{ +	struct beiscsi_io_task *io_task = task->dd_data; +	struct iscsi_conn *conn = task->conn; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_hba *phba = beiscsi_conn->phba; +	struct hwi_wrb_context *pwrb_context; +	struct hwi_controller *phwi_ctrlr; +	itt_t itt; +	struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; +	dma_addr_t paddr; + +	io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool, +					  GFP_KERNEL, &paddr); + +	if (!io_task->cmd_bhs) +		return -ENOMEM; + +	io_task->bhs_pa.u.a64.address = paddr; +	io_task->pwrb_handle = alloc_wrb_handle(phba, +						beiscsi_conn->beiscsi_conn_cid, +						task->itt); +	io_task->pwrb_handle->pio_handle = task; +	io_task->conn = beiscsi_conn; + +	task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; +	task->hdr_max = sizeof(struct be_cmd_bhs); + +	if (task->sc) { +		spin_lock(&phba->io_sgl_lock); +		io_task->psgl_handle = alloc_io_sgl_handle(phba); +		spin_unlock(&phba->io_sgl_lock); +		if (!io_task->psgl_handle) +			goto free_hndls; + +	} else { +		io_task->scsi_cmnd = NULL; +		if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { +			if (!beiscsi_conn->login_in_progress) { +				spin_lock(&phba->mgmt_sgl_lock); +				io_task->psgl_handle = (struct sgl_handle *) +						alloc_mgmt_sgl_handle(phba); +				spin_unlock(&phba->mgmt_sgl_lock); +				if (!io_task->psgl_handle) +					goto free_hndls; + +				beiscsi_conn->login_in_progress = 1; +				beiscsi_conn->plogin_sgl_handle = +							io_task->psgl_handle; +			} else { +				io_task->psgl_handle = +						beiscsi_conn->plogin_sgl_handle; +			} +		} else { +			spin_lock(&phba->mgmt_sgl_lock); +			io_task->psgl_handle = alloc_mgmt_sgl_handle(phba); +			spin_unlock(&phba->mgmt_sgl_lock); +			if (!io_task->psgl_handle) +				goto free_hndls; +		} +	} +	itt = (itt_t) cpu_to_be32(((unsigned int)task->itt << 16) | +			(unsigned int)(io_task->psgl_handle->sgl_index)); +	io_task->cmd_bhs->iscsi_hdr.itt = itt; +	return 0; + +free_hndls: +	phwi_ctrlr = phba->phwi_ctrlr; +	pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; +	free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); +	io_task->pwrb_handle = NULL; +	pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, +		      io_task->bhs_pa.u.a64.address); +	SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n"); +	return -ENOMEM; +} + +static void beiscsi_cleanup_task(struct iscsi_task *task) +{ +	struct beiscsi_io_task *io_task = task->dd_data; +	struct iscsi_conn *conn = task->conn; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_hba *phba = beiscsi_conn->phba; +	struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; +	struct hwi_wrb_context *pwrb_context; +	struct hwi_controller *phwi_ctrlr; + +	phwi_ctrlr = phba->phwi_ctrlr; +	pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid]; +	if (io_task->pwrb_handle) { +		free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); +		io_task->pwrb_handle = NULL; +	} + +	if (io_task->cmd_bhs) { +		pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, +			      io_task->bhs_pa.u.a64.address); +	} + +	if (task->sc) { +		if (io_task->psgl_handle) { +			spin_lock(&phba->io_sgl_lock); +			free_io_sgl_handle(phba, io_task->psgl_handle); +			spin_unlock(&phba->io_sgl_lock); +			io_task->psgl_handle = NULL; +		} +	} else { +		if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) +			return; +		if (io_task->psgl_handle) { +			spin_lock(&phba->mgmt_sgl_lock); +			free_mgmt_sgl_handle(phba, io_task->psgl_handle); +			spin_unlock(&phba->mgmt_sgl_lock); +			io_task->psgl_handle = NULL; +		} +	} +} + +static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, +			  unsigned int num_sg, unsigned int xferlen, +			  unsigned int writedir) +{ + +	struct beiscsi_io_task *io_task = task->dd_data; +	struct iscsi_conn *conn = task->conn; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_hba *phba = beiscsi_conn->phba; +	struct iscsi_wrb *pwrb = NULL; +	unsigned int doorbell = 0; + +	pwrb = io_task->pwrb_handle->pwrb; +	io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0; +	io_task->bhs_len = sizeof(struct be_cmd_bhs); + +	if (writedir) { +		SE_DEBUG(DBG_LVL_4, " WRITE Command \t"); +		memset(&io_task->cmd_bhs->iscsi_data_pdu, 0, 48); +		AMAP_SET_BITS(struct amap_pdu_data_out, itt, +			      &io_task->cmd_bhs->iscsi_data_pdu, +			      (unsigned int)io_task->cmd_bhs->iscsi_hdr.itt); +		AMAP_SET_BITS(struct amap_pdu_data_out, opcode, +			      &io_task->cmd_bhs->iscsi_data_pdu, +			      ISCSI_OPCODE_SCSI_DATA_OUT); +		AMAP_SET_BITS(struct amap_pdu_data_out, final_bit, +			      &io_task->cmd_bhs->iscsi_data_pdu, 1); +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD); +		AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); +	} else { +		SE_DEBUG(DBG_LVL_4, "READ Command \t"); +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD); +		AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); +	} +	memcpy(&io_task->cmd_bhs->iscsi_data_pdu. +	       dw[offsetof(struct amap_pdu_data_out, lun) / 32], +	       io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); + +	AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, +		      cpu_to_be16((unsigned short)io_task->cmd_bhs->iscsi_hdr. +				  lun[0])); +	AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); +	AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, +		      io_task->pwrb_handle->wrb_index); +	AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, +		      be32_to_cpu(task->cmdsn)); +	AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, +		      io_task->psgl_handle->sgl_index); + +	hwi_write_sgl(pwrb, sg, num_sg, io_task); + +	AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, +		      io_task->pwrb_handle->nxt_wrb_index); +	be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); + +	doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; +	doorbell |= (io_task->pwrb_handle->wrb_index & +		     DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; +	doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; + +	iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); +	return 0; +} + +static int beiscsi_mtask(struct iscsi_task *task) +{ +	struct beiscsi_io_task *aborted_io_task, *io_task = task->dd_data; +	struct iscsi_conn *conn = task->conn; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct beiscsi_hba *phba = beiscsi_conn->phba; +	struct iscsi_wrb *pwrb = NULL; +	unsigned int doorbell = 0; +	struct iscsi_task *aborted_task; + +	pwrb = io_task->pwrb_handle->pwrb; +	AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, +		      be32_to_cpu(task->cmdsn)); +	AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, +		      io_task->pwrb_handle->wrb_index); +	AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, +		      io_task->psgl_handle->sgl_index); + +	switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { +	case ISCSI_OP_LOGIN: +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, TGT_DM_CMD); +		AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); +		AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); +		hwi_write_buffer(pwrb, task); +		break; +	case ISCSI_OP_NOOP_OUT: +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD); +		hwi_write_buffer(pwrb, task); +		break; +	case ISCSI_OP_TEXT: +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD); +		AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); +		hwi_write_buffer(pwrb, task); +		break; +	case ISCSI_OP_SCSI_TMFUNC: +		aborted_task = iscsi_itt_to_task(conn, +					((struct iscsi_tm *)task->hdr)->rtt); +		 if (!aborted_task) +			return 0; +		aborted_io_task = aborted_task->dd_data; +		if (!aborted_io_task->scsi_cmnd) +			return 0; + +		mgmt_invalidate_icds(phba, +				     aborted_io_task->psgl_handle->sgl_index, +				     beiscsi_conn->beiscsi_conn_cid); +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_TMF_CMD); +		AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); +		hwi_write_buffer(pwrb, task); +		break; +	case ISCSI_OP_LOGOUT: +		AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); +		AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, +				HWH_TYPE_LOGOUT); +		hwi_write_buffer(pwrb, task); +		break; + +	default: +		SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n", +			 task->hdr->opcode & ISCSI_OPCODE_MASK); +		return -EINVAL; +	} + +	AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, +		      be32_to_cpu(task->data_count)); +	AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, +		      io_task->pwrb_handle->nxt_wrb_index); +	be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); + +	doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; +	doorbell |= (io_task->pwrb_handle->wrb_index & +		     DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; +	doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; +	iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); +	return 0; +} + +static int beiscsi_task_xmit(struct iscsi_task *task) +{ +	struct iscsi_conn *conn = task->conn; +	struct beiscsi_io_task *io_task = task->dd_data; +	struct scsi_cmnd *sc = task->sc; +	struct beiscsi_conn *beiscsi_conn = conn->dd_data; +	struct scatterlist *sg; +	int num_sg; +	unsigned int  writedir = 0, xferlen = 0; + +	SE_DEBUG(DBG_LVL_4, "\n cid=%d In beiscsi_task_xmit task=%p conn=%p \t" +		 "beiscsi_conn=%p \n", beiscsi_conn->beiscsi_conn_cid, +		 task, conn, beiscsi_conn); +	if (!sc) +		return beiscsi_mtask(task); + +	io_task->scsi_cmnd = sc; +	num_sg = scsi_dma_map(sc); +	if (num_sg < 0) { +		SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n") +		return num_sg; +	} +	SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n", +		  (scsi_bufflen(sc)), sc, num_sg, sc->serial_number); +	xferlen = scsi_bufflen(sc); +	sg = scsi_sglist(sc); +	if (sc->sc_data_direction == DMA_TO_DEVICE) { +		writedir = 1; +		SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n", +			 task->imm_count); +	} else +		writedir = 0; +	return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); +} + +static void beiscsi_remove(struct pci_dev *pcidev) +{ +	struct beiscsi_hba *phba = NULL; + +	phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev); +	if (!phba) { +		dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n"); +		return; +	} + +	hwi_disable_intr(phba); +	if (phba->pcidev->irq) +		free_irq(phba->pcidev->irq, phba); +	destroy_workqueue(phba->wq); +	if (blk_iopoll_enabled) +		blk_iopoll_disable(&phba->iopoll); + +	beiscsi_clean_port(phba); +	beiscsi_free_mem(phba); +	beiscsi_unmap_pci_function(phba); +	pci_free_consistent(phba->pcidev, +			    phba->ctrl.mbox_mem_alloced.size, +			    phba->ctrl.mbox_mem_alloced.va, +			    phba->ctrl.mbox_mem_alloced.dma); +	iscsi_host_remove(phba->shost); +	pci_dev_put(phba->pcidev); +	iscsi_host_free(phba->shost); +} + +static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, +				const struct pci_device_id *id) +{ +	struct beiscsi_hba *phba = NULL; +	int ret; + +	ret = beiscsi_enable_pci(pcidev); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +			     "Failed to enable pci device \n"); +		return ret; +	} + +	phba = beiscsi_hba_alloc(pcidev); +	if (!phba) { +		dev_err(&pcidev->dev, "beiscsi_dev_probe-" +			" Failed in beiscsi_hba_alloc \n"); +		goto disable_pci; +	} + +	pci_set_drvdata(pcidev, phba); +	ret = be_ctrl_init(phba, pcidev); +	if (ret) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +				"Failed in be_ctrl_init\n"); +		goto hba_free; +	} + +	spin_lock_init(&phba->io_sgl_lock); +	spin_lock_init(&phba->mgmt_sgl_lock); +	spin_lock_init(&phba->isr_lock); +	beiscsi_get_params(phba); +	ret = beiscsi_init_port(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +			     "Failed in beiscsi_init_port\n"); +		goto free_port; +	} + +	snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u", +		 phba->shost->host_no); +	phba->wq = create_singlethread_workqueue(phba->wq_name); +	if (!phba->wq) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +				"Failed to allocate work queue\n"); +		goto free_twq; +	} + +	INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs); + +	if (blk_iopoll_enabled) { +		blk_iopoll_init(&phba->iopoll, be_iopoll_budget, be_iopoll); +		blk_iopoll_enable(&phba->iopoll); +	} + +	ret = beiscsi_init_irqs(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +			     "Failed to beiscsi_init_irqs\n"); +		goto free_blkenbld; +	} +	ret = hwi_enable_intr(phba); +	if (ret < 0) { +		shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" +			     "Failed to hwi_enable_intr\n"); +		goto free_ctrlr; +	} + +	SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n"); +	return 0; + +free_ctrlr: +	if (phba->pcidev->irq) +		free_irq(phba->pcidev->irq, phba); +free_blkenbld: +	destroy_workqueue(phba->wq); +	if (blk_iopoll_enabled) +		blk_iopoll_disable(&phba->iopoll); +free_twq: +	beiscsi_clean_port(phba); +	beiscsi_free_mem(phba); +free_port: +	pci_free_consistent(phba->pcidev, +			    phba->ctrl.mbox_mem_alloced.size, +			    phba->ctrl.mbox_mem_alloced.va, +			   phba->ctrl.mbox_mem_alloced.dma); +	beiscsi_unmap_pci_function(phba); +hba_free: +	iscsi_host_remove(phba->shost); +	pci_dev_put(phba->pcidev); +	iscsi_host_free(phba->shost); +disable_pci: +	pci_disable_device(pcidev); +	return ret; +} + +struct iscsi_transport beiscsi_iscsi_transport = { +	.owner = THIS_MODULE, +	.name = DRV_NAME, +	.caps = CAP_RECOVERY_L0 | CAP_HDRDGST | +		CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, +	.param_mask = ISCSI_MAX_RECV_DLENGTH | +		ISCSI_MAX_XMIT_DLENGTH | +		ISCSI_HDRDGST_EN | +		ISCSI_DATADGST_EN | +		ISCSI_INITIAL_R2T_EN | +		ISCSI_MAX_R2T | +		ISCSI_IMM_DATA_EN | +		ISCSI_FIRST_BURST | +		ISCSI_MAX_BURST | +		ISCSI_PDU_INORDER_EN | +		ISCSI_DATASEQ_INORDER_EN | +		ISCSI_ERL | +		ISCSI_CONN_PORT | +		ISCSI_CONN_ADDRESS | +		ISCSI_EXP_STATSN | +		ISCSI_PERSISTENT_PORT | +		ISCSI_PERSISTENT_ADDRESS | +		ISCSI_TARGET_NAME | ISCSI_TPGT | +		ISCSI_USERNAME | ISCSI_PASSWORD | +		ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | +		ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | +		ISCSI_LU_RESET_TMO | +		ISCSI_PING_TMO | ISCSI_RECV_TMO | +		ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, +	.host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | +				ISCSI_HOST_INITIATOR_NAME, +	.create_session = beiscsi_session_create, +	.destroy_session = beiscsi_session_destroy, +	.create_conn = beiscsi_conn_create, +	.bind_conn = beiscsi_conn_bind, +	.destroy_conn = iscsi_conn_teardown, +	.set_param = beiscsi_set_param, +	.get_conn_param = beiscsi_conn_get_param, +	.get_session_param = iscsi_session_get_param, +	.get_host_param = beiscsi_get_host_param, +	.start_conn = beiscsi_conn_start, +	.stop_conn = beiscsi_conn_stop, +	.send_pdu = iscsi_conn_send_pdu, +	.xmit_task = beiscsi_task_xmit, +	.cleanup_task = beiscsi_cleanup_task, +	.alloc_pdu = beiscsi_alloc_pdu, +	.parse_pdu_itt = beiscsi_parse_pdu, +	.get_stats = beiscsi_conn_get_stats, +	.ep_connect = beiscsi_ep_connect, +	.ep_poll = beiscsi_ep_poll, +	.ep_disconnect = beiscsi_ep_disconnect, +	.session_recovery_timedout = iscsi_session_recovery_timedout, +}; + +static struct pci_driver beiscsi_pci_driver = { +	.name = DRV_NAME, +	.probe = beiscsi_dev_probe, +	.remove = beiscsi_remove, +	.id_table = beiscsi_pci_id_table +}; + +static int __init beiscsi_module_init(void) +{ +	int ret; + +	beiscsi_scsi_transport = +			iscsi_register_transport(&beiscsi_iscsi_transport); +	if (!beiscsi_scsi_transport) { +		SE_DEBUG(DBG_LVL_1, +			 "beiscsi_module_init - Unable to  register beiscsi" +			 "transport.\n"); +		ret = -ENOMEM; +	} +	SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n", +		 &beiscsi_iscsi_transport); + +	ret = pci_register_driver(&beiscsi_pci_driver); +	if (ret) { +		SE_DEBUG(DBG_LVL_1, +			 "beiscsi_module_init - Unable to  register" +			 "beiscsi pci driver.\n"); +		goto unregister_iscsi_transport; +	} +	return 0; + +unregister_iscsi_transport: +	iscsi_unregister_transport(&beiscsi_iscsi_transport); +	return ret; +} + +static void __exit beiscsi_module_exit(void) +{ +	pci_unregister_driver(&beiscsi_pci_driver); +	iscsi_unregister_transport(&beiscsi_iscsi_transport); +} + +module_init(beiscsi_module_init); +module_exit(beiscsi_module_exit); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h new file mode 100644 index 00000000000..53c9b70ac7a --- /dev/null +++ b/drivers/scsi/be2iscsi/be_main.h @@ -0,0 +1,837 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#ifndef _BEISCSI_MAIN_ +#define _BEISCSI_MAIN_ + + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/in.h> +#include <linux/blk-iopoll.h> +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/iscsi_proto.h> +#include <scsi/libiscsi.h> +#include <scsi/scsi_transport_iscsi.h> + +#include "be.h" + + + +#define DRV_NAME		"be2iscsi" +#define BUILD_STR		"2.0.527.0" + +#define BE_NAME			"ServerEngines BladeEngine2" \ +				"Linux iSCSI Driver version" BUILD_STR +#define DRV_DESC		BE_NAME " " "Driver" + +#define BE_VENDOR_ID 		0x19A2 +#define BE_DEVICE_ID1		0x212 +#define OC_DEVICE_ID1		0x702 +#define OC_DEVICE_ID2		0x703 + +#define BE2_MAX_SESSIONS	64 +#define BE2_CMDS_PER_CXN	128 +#define BE2_LOGOUTS		BE2_MAX_SESSIONS +#define BE2_TMFS		16 +#define BE2_NOPOUT_REQ		16 +#define BE2_ASYNCPDUS		BE2_MAX_SESSIONS +#define BE2_MAX_ICDS		2048 +#define BE2_SGE			32 +#define BE2_DEFPDU_HDR_SZ	64 +#define BE2_DEFPDU_DATA_SZ	8192 +#define BE2_IO_DEPTH \ +	(BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ)) + +#define BEISCSI_SGLIST_ELEMENTS	BE2_SGE + +#define BEISCSI_MAX_CMNDS	1024	/* Max IO's per Ctrlr sht->can_queue */ +#define BEISCSI_CMD_PER_LUN	128	/* scsi_host->cmd_per_lun */ +#define BEISCSI_MAX_SECTORS	2048	/* scsi_host->max_sectors */ + +#define BEISCSI_MAX_CMD_LEN	16	/* scsi_host->max_cmd_len */ +#define BEISCSI_NUM_MAX_LUN	256	/* scsi_host->max_lun */ +#define BEISCSI_NUM_DEVICES_SUPPORTED	0x01 +#define BEISCSI_MAX_FRAGS_INIT	192 +#define BE_NUM_MSIX_ENTRIES 	1 +#define MPU_EP_SEMAPHORE 	0xac + +#define BE_SENSE_INFO_SIZE		258 +#define BE_ISCSI_PDU_HEADER_SIZE	64 +#define BE_MIN_MEM_SIZE			16384 + +#define IIOC_SCSI_DATA                  0x05	/* Write Operation */ + +#define DBG_LVL				0x00000001 +#define DBG_LVL_1			0x00000001 +#define DBG_LVL_2			0x00000002 +#define DBG_LVL_3			0x00000004 +#define DBG_LVL_4			0x00000008 +#define DBG_LVL_5			0x00000010 +#define DBG_LVL_6			0x00000020 +#define DBG_LVL_7			0x00000040 +#define DBG_LVL_8			0x00000080 + +#define SE_DEBUG(debug_mask, fmt, args...)		\ +do {							\ +	if (debug_mask & DBG_LVL) {			\ +		printk(KERN_ERR "(%s():%d):", __func__, __LINE__);\ +		printk(fmt, ##args);			\ +	}						\ +} while (0); + +/** + * hardware needs the async PDU buffers to be posted in multiples of 8 + * So have atleast 8 of them by default + */ + +#define HWI_GET_ASYNC_PDU_CTX(phwi)	(phwi->phwi_ctxt->pasync_ctx) + +/********* Memory BAR register ************/ +#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 	0xfc +/** + * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt + * Disable" may still globally block interrupts in addition to individual + * interrupt masks; a mechanism for the device driver to block all interrupts + * atomically without having to arbitrate for the PCI Interrupt Disable bit + * with the OS. + */ +#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK	(1 << 29)	/* bit 29 */ + +/********* ISR0 Register offset **********/ +#define CEV_ISR0_OFFSET 			0xC18 +#define CEV_ISR_SIZE				4 + +/** + * Macros for reading/writing a protection domain or CSR registers + * in BladeEngine. + */ + +#define DB_TXULP0_OFFSET 0x40 +#define DB_RXULP0_OFFSET 0xA0 +/********* Event Q door bell *************/ +#define DB_EQ_OFFSET			DB_CQ_OFFSET +#define DB_EQ_RING_ID_MASK		0x1FF	/* bits 0 - 8 */ +/* Clear the interrupt for this eq */ +#define DB_EQ_CLR_SHIFT			(9)	/* bit 9 */ +/* Must be 1 */ +#define DB_EQ_EVNT_SHIFT		(10)	/* bit 10 */ +/* Number of event entries processed */ +#define DB_EQ_NUM_POPPED_SHIFT		(16)	/* bits 16 - 28 */ +/* Rearm bit */ +#define DB_EQ_REARM_SHIFT		(29)	/* bit 29 */ + +/********* Compl Q door bell *************/ +#define DB_CQ_OFFSET 			0x120 +#define DB_CQ_RING_ID_MASK		0x3FF	/* bits 0 - 9 */ +/* Number of event entries processed */ +#define DB_CQ_NUM_POPPED_SHIFT		(16) 	/* bits 16 - 28 */ +/* Rearm bit */ +#define DB_CQ_REARM_SHIFT		(29) 	/* bit 29 */ + +#define GET_HWI_CONTROLLER_WS(pc)	(pc->phwi_ctrlr) +#define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\ +		(GET_HWI_CONTROLLER_WS(pc)))->default_pdu_data.id) +#define HWI_GET_DEF_HDRQ_ID(pc) (((struct hwi_controller *)\ +		(GET_HWI_CONTROLLER_WS(pc)))->default_pdu_hdr.id) + +#define PAGES_REQUIRED(x) \ +	((x < PAGE_SIZE) ? 1 :  ((x + PAGE_SIZE - 1) / PAGE_SIZE)) + +enum be_mem_enum { +	HWI_MEM_ADDN_CONTEXT, +	HWI_MEM_CQ, +	HWI_MEM_EQ, +	HWI_MEM_WRB, +	HWI_MEM_WRBH, +	HWI_MEM_SGLH,	/* 5 */ +	HWI_MEM_SGE, +	HWI_MEM_ASYNC_HEADER_BUF, +	HWI_MEM_ASYNC_DATA_BUF, +	HWI_MEM_ASYNC_HEADER_RING, +	HWI_MEM_ASYNC_DATA_RING,	/* 10 */ +	HWI_MEM_ASYNC_HEADER_HANDLE, +	HWI_MEM_ASYNC_DATA_HANDLE, +	HWI_MEM_ASYNC_PDU_CONTEXT, +	ISCSI_MEM_GLOBAL_HEADER, +	SE_MEM_MAX  	/* 15 */ +}; + +struct be_bus_address32 { +	unsigned int address_lo; +	unsigned int address_hi; +}; + +struct be_bus_address64 { +	unsigned long long address; +}; + +struct be_bus_address { +	union { +		struct be_bus_address32 a32; +		struct be_bus_address64 a64; +	} u; +}; + +struct mem_array { +	struct be_bus_address bus_address;	/* Bus address of location */ +	void *virtual_address;		/* virtual address to the location */ +	unsigned int size;		/* Size required by memory block */ +}; + +struct be_mem_descriptor { +	unsigned int index;	/* Index of this memory parameter */ +	unsigned int category;	/* type indicates cached/non-cached */ +	unsigned int num_elements;	/* number of elements in this +					 * descriptor +					 */ +	unsigned int alignment_mask;	/* Alignment mask for this block */ +	unsigned int size_in_bytes;	/* Size required by memory block */ +	struct mem_array *mem_array; +}; + +struct sgl_handle { +	unsigned int sgl_index; +	struct iscsi_sge *pfrag; +}; + +struct hba_parameters { +	unsigned int ios_per_ctrl; +	unsigned int cxns_per_ctrl; +	unsigned int asyncpdus_per_ctrl; +	unsigned int icds_per_ctrl; +	unsigned int num_sge_per_io; +	unsigned int defpdu_hdr_sz; +	unsigned int defpdu_data_sz; +	unsigned int num_cq_entries; +	unsigned int num_eq_entries; +	unsigned int wrbs_per_cxn; +	unsigned int crashmode; +	unsigned int hba_num; + +	unsigned int mgmt_ws_sz; +	unsigned int hwi_ws_sz; + +	unsigned int eto; +	unsigned int ldto; + +	unsigned int dbg_flags; +	unsigned int num_cxn; + +	unsigned int eq_timer; +	/** +	 * These are calculated from other params. They're here +	 * for debug purposes +	 */ +	unsigned int num_mcc_pages; +	unsigned int num_mcc_cq_pages; +	unsigned int num_cq_pages; +	unsigned int num_eq_pages; + +	unsigned int num_async_pdu_buf_pages; +	unsigned int num_async_pdu_buf_sgl_pages; +	unsigned int num_async_pdu_buf_cq_pages; + +	unsigned int num_async_pdu_hdr_pages; +	unsigned int num_async_pdu_hdr_sgl_pages; +	unsigned int num_async_pdu_hdr_cq_pages; + +	unsigned int num_sge; +}; + +struct beiscsi_hba { +	struct hba_parameters params; +	struct hwi_controller *phwi_ctrlr; +	unsigned int mem_req[SE_MEM_MAX]; +	/* PCI BAR mapped addresses */ +	u8 __iomem *csr_va;	/* CSR */ +	u8 __iomem *db_va;	/* Door  Bell  */ +	u8 __iomem *pci_va;	/* PCI Config */ +	struct be_bus_address csr_pa;	/* CSR */ +	struct be_bus_address db_pa;	/* CSR */ +	struct be_bus_address pci_pa;	/* CSR */ +	/* PCI representation of our HBA */ +	struct pci_dev *pcidev; +	unsigned int state; +	unsigned short asic_revision; +	struct blk_iopoll	iopoll; +	struct be_mem_descriptor *init_mem; + +	unsigned short io_sgl_alloc_index; +	unsigned short io_sgl_free_index; +	unsigned short io_sgl_hndl_avbl; +	struct sgl_handle **io_sgl_hndl_base; + +	unsigned short eh_sgl_alloc_index; +	unsigned short eh_sgl_free_index; +	unsigned short eh_sgl_hndl_avbl; +	struct sgl_handle **eh_sgl_hndl_base; +	spinlock_t io_sgl_lock; +	spinlock_t mgmt_sgl_lock; +	spinlock_t isr_lock; +	unsigned int age; +	unsigned short avlbl_cids; +	unsigned short cid_alloc; +	unsigned short cid_free; +	struct beiscsi_conn *conn_table[BE2_MAX_SESSIONS * 2]; +	struct list_head hba_queue; +	unsigned short *cid_array; +	struct iscsi_endpoint **ep_array; +	struct Scsi_Host *shost; +	struct { +		/** +		 * group together since they are used most frequently +		 * for cid to cri conversion +		 */ +		unsigned int iscsi_cid_start; +		unsigned int phys_port; + +		unsigned int isr_offset; +		unsigned int iscsi_icd_start; +		unsigned int iscsi_cid_count; +		unsigned int iscsi_icd_count; +		unsigned int pci_function; + +		unsigned short cid_alloc; +		unsigned short cid_free; +		unsigned short avlbl_cids; +		spinlock_t cid_lock; +	} fw_config; + +	u8 mac_address[ETH_ALEN]; +	unsigned short todo_cq; +	unsigned short todo_mcc_cq; +	char wq_name[20]; +	struct workqueue_struct *wq;	/* The actuak work queue */ +	struct work_struct work_cqs;	/* The work being queued */ +	struct be_ctrl_info ctrl; +}; + +struct beiscsi_session { +	struct pci_pool *bhs_pool; +}; + +/** + * struct beiscsi_conn - iscsi connection structure + */ +struct beiscsi_conn { +	struct iscsi_conn *conn; +	struct beiscsi_hba *phba; +	u32 exp_statsn; +	u32 beiscsi_conn_cid; +	struct beiscsi_endpoint *ep; +	unsigned short login_in_progress; +	struct sgl_handle *plogin_sgl_handle; +	struct beiscsi_session *beiscsi_sess; +}; + +/* This structure is used by the chip */ +struct pdu_data_out { +	u32 dw[12]; +}; +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_pdu_data_out { +	u8 opcode[6];		/* opcode */ +	u8 rsvd0[2];		/* should be 0 */ +	u8 rsvd1[7]; +	u8 final_bit;		/* F bit */ +	u8 rsvd2[16]; +	u8 ahs_length[8];	/* no AHS */ +	u8 data_len_hi[8]; +	u8 data_len_lo[16];	/* DataSegmentLength */ +	u8 lun[64]; +	u8 itt[32];		/* ITT; initiator task tag */ +	u8 ttt[32];		/* TTT; valid for R2T or 0xffffffff */ +	u8 rsvd3[32]; +	u8 exp_stat_sn[32]; +	u8 rsvd4[32]; +	u8 data_sn[32]; +	u8 buffer_offset[32]; +	u8 rsvd5[32]; +}; + +struct be_cmd_bhs { +	struct iscsi_cmd iscsi_hdr; +	unsigned char pad1[16]; +	struct pdu_data_out iscsi_data_pdu; +	unsigned char pad2[BE_SENSE_INFO_SIZE - +			sizeof(struct pdu_data_out)]; +}; + +struct beiscsi_io_task { +	struct wrb_handle *pwrb_handle; +	struct sgl_handle *psgl_handle; +	struct beiscsi_conn *conn; +	struct scsi_cmnd *scsi_cmnd; +	unsigned int cmd_sn; +	unsigned int flags; +	unsigned short cid; +	unsigned short header_len; + +	struct be_cmd_bhs *cmd_bhs; +	struct be_bus_address bhs_pa; +	unsigned short bhs_len; +}; + +struct be_nonio_bhs { +	struct iscsi_hdr iscsi_hdr; +	unsigned char pad1[16]; +	struct pdu_data_out iscsi_data_pdu; +	unsigned char pad2[BE_SENSE_INFO_SIZE - +			sizeof(struct pdu_data_out)]; +}; + +struct be_status_bhs { +	struct iscsi_cmd iscsi_hdr; +	unsigned char pad1[16]; +	/** +	 * The plus 2 below is to hold the sense info length that gets +	 * DMA'ed by RxULP +	 */ +	unsigned char sense_info[BE_SENSE_INFO_SIZE]; +}; + +struct iscsi_sge { +	u32 dw[4]; +}; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_iscsi_sge { +	u8 addr_hi[32]; +	u8 addr_lo[32]; +	u8 sge_offset[22];	/* DWORD 2 */ +	u8 rsvd0[9];		/* DWORD 2 */ +	u8 last_sge;		/* DWORD 2 */ +	u8 len[17];		/* DWORD 3 */ +	u8 rsvd1[15];		/* DWORD 3 */ +}; + +struct beiscsi_offload_params { +	u32 dw[5]; +}; + +#define OFFLD_PARAMS_ERL	0x00000003 +#define OFFLD_PARAMS_DDE	0x00000004 +#define OFFLD_PARAMS_HDE	0x00000008 +#define OFFLD_PARAMS_IR2T	0x00000010 +#define OFFLD_PARAMS_IMD	0x00000020 + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_beiscsi_offload_params { +	u8 max_burst_length[32]; +	u8 max_send_data_segment_length[32]; +	u8 first_burst_length[32]; +	u8 erl[2]; +	u8 dde[1]; +	u8 hde[1]; +	u8 ir2t[1]; +	u8 imd[1]; +	u8 pad[26]; +	u8 exp_statsn[32]; +}; + +/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, +		struct beiscsi_hba *phba, struct sol_cqe *psol);*/ + +struct async_pdu_handle { +	struct list_head link; +	struct be_bus_address pa; +	void *pbuffer; +	unsigned int consumed; +	unsigned char index; +	unsigned char is_header; +	unsigned short cri; +	unsigned long buffer_len; +}; + +struct hwi_async_entry { +	struct { +		unsigned char hdr_received; +		unsigned char hdr_len; +		unsigned short bytes_received; +		unsigned int bytes_needed; +		struct list_head list; +	} wait_queue; + +	struct list_head header_busy_list; +	struct list_head data_busy_list; +}; + +#define BE_MIN_ASYNC_ENTRIES 128 + +struct hwi_async_pdu_context { +	struct { +		struct be_bus_address pa_base; +		void *va_base; +		void *ring_base; +		struct async_pdu_handle *handle_base; + +		unsigned int host_write_ptr; +		unsigned int ep_read_ptr; +		unsigned int writables; + +		unsigned int free_entries; +		unsigned int busy_entries; +		unsigned int buffer_size; +		unsigned int num_entries; + +		struct list_head free_list; +	} async_header; + +	struct { +		struct be_bus_address pa_base; +		void *va_base; +		void *ring_base; +		struct async_pdu_handle *handle_base; + +		unsigned int host_write_ptr; +		unsigned int ep_read_ptr; +		unsigned int writables; + +		unsigned int free_entries; +		unsigned int busy_entries; +		unsigned int buffer_size; +		struct list_head free_list; +		unsigned int num_entries; +	} async_data; + +	/** +	 * This is a varying size list! Do not add anything +	 * after this entry!! +	 */ +	struct hwi_async_entry async_entry[BE_MIN_ASYNC_ENTRIES]; +}; + +#define PDUCQE_CODE_MASK	0x0000003F +#define PDUCQE_DPL_MASK		0xFFFF0000 +#define PDUCQE_INDEX_MASK	0x0000FFFF + +struct i_t_dpdu_cqe { +	u32 dw[4]; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_i_t_dpdu_cqe { +	u8 db_addr_hi[32]; +	u8 db_addr_lo[32]; +	u8 code[6]; +	u8 cid[10]; +	u8 dpl[16]; +	u8 index[16]; +	u8 num_cons[10]; +	u8 rsvd0[4]; +	u8 final; +	u8 valid; +} __packed; + +#define CQE_VALID_MASK	0x80000000 +#define CQE_CODE_MASK	0x0000003F +#define CQE_CID_MASK	0x0000FFC0 + +#define EQE_VALID_MASK		0x00000001 +#define EQE_MAJORCODE_MASK	0x0000000E +#define EQE_RESID_MASK		0xFFFF0000 + +struct be_eq_entry { +	u32 dw[1]; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_eq_entry { +	u8 valid;		/* DWORD 0 */ +	u8 major_code[3];	/* DWORD 0 */ +	u8 minor_code[12];	/* DWORD 0 */ +	u8 resource_id[16];	/* DWORD 0 */ + +} __packed; + +struct cq_db { +	u32 dw[1]; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_cq_db { +	u8 qid[10]; +	u8 event[1]; +	u8 rsvd0[5]; +	u8 num_popped[13]; +	u8 rearm[1]; +	u8 rsvd1[2]; +} __packed; + +void beiscsi_process_eq(struct beiscsi_hba *phba); + + +struct iscsi_wrb { +	u32 dw[16]; +} __packed; + +#define WRB_TYPE_MASK 0xF0000000 + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_iscsi_wrb { +	u8 lun[14];		/* DWORD 0 */ +	u8 lt;			/* DWORD 0 */ +	u8 invld;		/* DWORD 0 */ +	u8 wrb_idx[8];		/* DWORD 0 */ +	u8 dsp;			/* DWORD 0 */ +	u8 dmsg;		/* DWORD 0 */ +	u8 undr_run;		/* DWORD 0 */ +	u8 over_run;		/* DWORD 0 */ +	u8 type[4];		/* DWORD 0 */ +	u8 ptr2nextwrb[8];	/* DWORD 1 */ +	u8 r2t_exp_dtl[24];	/* DWORD 1 */ +	u8 sgl_icd_idx[12];	/* DWORD 2 */ +	u8 rsvd0[20];		/* DWORD 2 */ +	u8 exp_data_sn[32];	/* DWORD 3 */ +	u8 iscsi_bhs_addr_hi[32];	/* DWORD 4 */ +	u8 iscsi_bhs_addr_lo[32];	/* DWORD 5 */ +	u8 cmdsn_itt[32];	/* DWORD 6 */ +	u8 dif_ref_tag[32];	/* DWORD 7 */ +	u8 sge0_addr_hi[32];	/* DWORD 8 */ +	u8 sge0_addr_lo[32];	/* DWORD 9  */ +	u8 sge0_offset[22];	/* DWORD 10 */ +	u8 pbs;			/* DWORD 10 */ +	u8 dif_mode[2];		/* DWORD 10 */ +	u8 rsvd1[6];		/* DWORD 10 */ +	u8 sge0_last;		/* DWORD 10 */ +	u8 sge0_len[17];	/* DWORD 11 */ +	u8 dif_meta_tag[14];	/* DWORD 11 */ +	u8 sge0_in_ddr;		/* DWORD 11 */ +	u8 sge1_addr_hi[32];	/* DWORD 12 */ +	u8 sge1_addr_lo[32];	/* DWORD 13 */ +	u8 sge1_r2t_offset[22];	/* DWORD 14 */ +	u8 rsvd2[9];		/* DWORD 14 */ +	u8 sge1_last;		/* DWORD 14 */ +	u8 sge1_len[17];	/* DWORD 15 */ +	u8 ref_sgl_icd_idx[12];	/* DWORD 15 */ +	u8 rsvd3[2];		/* DWORD 15 */ +	u8 sge1_in_ddr;		/* DWORD 15 */ + +} __packed; + +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, +				    int index); +void +free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); + +struct pdu_nop_out { +	u32 dw[12]; +}; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_pdu_nop_out { +	u8 opcode[6];		/* opcode 0x00 */ +	u8 i_bit;		/* I Bit */ +	u8 x_bit;		/* reserved; should be 0 */ +	u8 fp_bit_filler1[7]; +	u8 f_bit;		/* always 1 */ +	u8 reserved1[16]; +	u8 ahs_length[8];	/* no AHS */ +	u8 data_len_hi[8]; +	u8 data_len_lo[16];	/* DataSegmentLength */ +	u8 lun[64]; +	u8 itt[32];		/* initiator id for ping or 0xffffffff */ +	u8 ttt[32];		/* target id for ping or 0xffffffff */ +	u8 cmd_sn[32]; +	u8 exp_stat_sn[32]; +	u8 reserved5[128]; +}; + +#define PDUBASE_OPCODE_MASK	0x0000003F +#define PDUBASE_DATALENHI_MASK	0x0000FF00 +#define PDUBASE_DATALENLO_MASK	0xFFFF0000 + +struct pdu_base { +	u32 dw[16]; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_pdu_base { +	u8 opcode[6]; +	u8 i_bit;		/* immediate bit */ +	u8 x_bit;		/* reserved, always 0 */ +	u8 reserved1[24];	/* opcode-specific fields */ +	u8 ahs_length[8];	/* length units is 4 byte words */ +	u8 data_len_hi[8]; +	u8 data_len_lo[16];	/* DatasegmentLength */ +	u8 lun[64];		/* lun or opcode-specific fields */ +	u8 itt[32];		/* initiator task tag */ +	u8 reserved4[224]; +}; + +struct iscsi_target_context_update_wrb { +	u32 dw[16]; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_iscsi_target_context_update_wrb { +	u8 lun[14];		/* DWORD 0 */ +	u8 lt;			/* DWORD 0 */ +	u8 invld;		/* DWORD 0 */ +	u8 wrb_idx[8];		/* DWORD 0 */ +	u8 dsp;			/* DWORD 0 */ +	u8 dmsg;		/* DWORD 0 */ +	u8 undr_run;		/* DWORD 0 */ +	u8 over_run;		/* DWORD 0 */ +	u8 type[4];		/* DWORD 0 */ +	u8 ptr2nextwrb[8];	/* DWORD 1 */ +	u8 max_burst_length[19];	/* DWORD 1 */ +	u8 rsvd0[5];		/* DWORD 1 */ +	u8 rsvd1[15];		/* DWORD 2 */ +	u8 max_send_data_segment_length[17];	/* DWORD 2 */ +	u8 first_burst_length[14];	/* DWORD 3 */ +	u8 rsvd2[2];		/* DWORD 3 */ +	u8 tx_wrbindex_drv_msg[8];	/* DWORD 3 */ +	u8 rsvd3[5];		/* DWORD 3 */ +	u8 session_state[3];	/* DWORD 3 */ +	u8 rsvd4[16];		/* DWORD 4 */ +	u8 tx_jumbo;		/* DWORD 4 */ +	u8 hde;			/* DWORD 4 */ +	u8 dde;			/* DWORD 4 */ +	u8 erl[2];		/* DWORD 4 */ +	u8 domain_id[5];		/* DWORD 4 */ +	u8 mode;		/* DWORD 4 */ +	u8 imd;			/* DWORD 4 */ +	u8 ir2t;		/* DWORD 4 */ +	u8 notpredblq[2];	/* DWORD 4 */ +	u8 compltonack;		/* DWORD 4 */ +	u8 stat_sn[32];		/* DWORD 5 */ +	u8 pad_buffer_addr_hi[32];	/* DWORD 6 */ +	u8 pad_buffer_addr_lo[32];	/* DWORD 7 */ +	u8 pad_addr_hi[32];	/* DWORD 8 */ +	u8 pad_addr_lo[32];	/* DWORD 9 */ +	u8 rsvd5[32];		/* DWORD 10 */ +	u8 rsvd6[32];		/* DWORD 11 */ +	u8 rsvd7[32];		/* DWORD 12 */ +	u8 rsvd8[32];		/* DWORD 13 */ +	u8 rsvd9[32];		/* DWORD 14 */ +	u8 rsvd10[32];		/* DWORD 15 */ + +} __packed; + +struct be_ring { +	u32 pages;		/* queue size in pages */ +	u32 id;			/* queue id assigned by beklib */ +	u32 num;		/* number of elements in queue */ +	u32 cidx;		/* consumer index */ +	u32 pidx;		/* producer index -- not used by most rings */ +	u32 item_size;		/* size in bytes of one object */ + +	void *va;		/* The virtual address of the ring.  This +				 * should be last to allow 32 & 64 bit debugger +				 * extensions to work. +				 */ +}; + +struct hwi_wrb_context { +	struct list_head wrb_handle_list; +	struct list_head wrb_handle_drvr_list; +	struct wrb_handle **pwrb_handle_base; +	struct wrb_handle **pwrb_handle_basestd; +	struct iscsi_wrb *plast_wrb; +	unsigned short alloc_index; +	unsigned short free_index; +	unsigned short wrb_handles_available; +	unsigned short cid; +}; + +struct hwi_controller { +	struct list_head io_sgl_list; +	struct list_head eh_sgl_list; +	struct sgl_handle *psgl_handle_base; +	unsigned int wrb_mem_index; + +	struct hwi_wrb_context wrb_context[BE2_MAX_SESSIONS * 2]; +	struct mcc_wrb *pmcc_wrb_base; +	struct be_ring default_pdu_hdr; +	struct be_ring default_pdu_data; +	struct hwi_context_memory *phwi_ctxt; +	unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN]; +}; + +enum hwh_type_enum { +	HWH_TYPE_IO = 1, +	HWH_TYPE_LOGOUT = 2, +	HWH_TYPE_TMF = 3, +	HWH_TYPE_NOP = 4, +	HWH_TYPE_IO_RD = 5, +	HWH_TYPE_LOGIN = 11, +	HWH_TYPE_INVALID = 0xFFFFFFFF +}; + +struct wrb_handle { +	enum hwh_type_enum type; +	unsigned short wrb_index; +	unsigned short nxt_wrb_index; + +	struct iscsi_task *pio_handle; +	struct iscsi_wrb *pwrb; +}; + +struct hwi_context_memory { +	struct be_eq_obj be_eq; +	struct be_queue_info be_cq; +	struct be_queue_info be_mcc_cq; +	struct be_queue_info be_mcc; + +	struct be_queue_info be_def_hdrq; +	struct be_queue_info be_def_dataq; + +	struct be_queue_info be_wrbq[BE2_MAX_SESSIONS]; +	struct be_mcc_wrb_context *pbe_mcc_context; + +	struct hwi_async_pdu_context *pasync_ctx; +}; + +#endif diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c new file mode 100644 index 00000000000..12e644fc746 --- /dev/null +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -0,0 +1,321 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#include "be_mgmt.h" +#include "be_iscsi.h" + +unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, +				struct beiscsi_hba *phba) +{ +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_fw_cfg *req = embedded_payload(wrb); +	int status = 0; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +			   OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		struct be_fw_cfg *pfw_cfg; +		pfw_cfg = req; +		phba->fw_config.phys_port = pfw_cfg->phys_port; +		phba->fw_config.iscsi_icd_start = +					pfw_cfg->ulp[0].icd_base; +		phba->fw_config.iscsi_icd_count = +					pfw_cfg->ulp[0].icd_count; +		phba->fw_config.iscsi_cid_start = +					pfw_cfg->ulp[0].sq_base; +		phba->fw_config.iscsi_cid_count = +					pfw_cfg->ulp[0].sq_count; +	} else { +		shost_printk(KERN_WARNING, phba->shost, +			     "Failed in mgmt_get_fw_config \n"); +	} + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl) +{ +	struct be_dma_mem nonemb_cmd; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_mgmt_controller_attributes *req; +	struct be_sge *sge = nonembedded_sgl(wrb); +	int status = 0; + +	nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, +				sizeof(struct be_mgmt_controller_attributes), +				&nonemb_cmd.dma); +	if (nonemb_cmd.va == NULL) { +		SE_DEBUG(DBG_LVL_1, +			 "Failed to allocate memory for mgmt_check_supported_fw" +			 "\n"); +		return -1; +	} +	nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); +	req = nonemb_cmd.va; +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); +	be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, +			   OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req)); +	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); +	sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); +	sge->len = cpu_to_le32(nonemb_cmd.size); + +	status = be_mbox_notify(ctrl); +	if (!status) { +		struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va; +		SE_DEBUG(DBG_LVL_8, "Firmware version of CMD: %s\n", +			resp->params.hba_attribs.flashrom_version_string); +		SE_DEBUG(DBG_LVL_8, "Firmware version is : %s\n", +			resp->params.hba_attribs.firmware_version_string); +		SE_DEBUG(DBG_LVL_8, +			"Developer Build, not performing version check...\n"); + +	} else +		SE_DEBUG(DBG_LVL_1, " Failed in mgmt_check_supported_fw\n"); +	if (nonemb_cmd.va) +		pci_free_consistent(ctrl->pdev, nonemb_cmd.size, +				    nonemb_cmd.va, nonemb_cmd.dma); + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct iscsi_cleanup_req *req = embedded_payload(wrb); +	int status = 0; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +			   OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); + +	req->chute = chute; +	req->hdr_ring_id = 0; +	req->data_ring_id = 0; + +	status = be_mbox_notify(ctrl); +	if (status) +		shost_printk(KERN_WARNING, phba->shost, +			     " mgmt_epfw_cleanup , FAILED\n"); +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, +				   unsigned int icd, unsigned int cid) +{ +	struct be_dma_mem nonemb_cmd; +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct be_sge *sge = nonembedded_sgl(wrb); +	struct invalidate_commands_params_in *req; +	int status = 0; + +	nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, +				sizeof(struct invalidate_commands_params_in), +				&nonemb_cmd.dma); +	if (nonemb_cmd.va == NULL) { +		SE_DEBUG(DBG_LVL_1, +			 "Failed to allocate memory for" +			 "mgmt_invalidate_icds \n"); +		return -1; +	} +	nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); +	req = nonemb_cmd.va; +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +			OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, +			sizeof(*req)); +	req->ref_handle = 0; +	req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; +	req->icd_count = 0; +	req->table[req->icd_count].icd = icd; +	req->table[req->icd_count].cid = cid; +	sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); +	sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); +	sge->len = cpu_to_le32(nonemb_cmd.size); + +	status = be_mbox_notify(ctrl); +	if (status) +		SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n"); +	spin_unlock(&ctrl->mbox_lock); +	if (nonemb_cmd.va) +		pci_free_consistent(ctrl->pdev, nonemb_cmd.size, +				    nonemb_cmd.va, nonemb_cmd.dma); +	return status; +} + +unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, +					 struct beiscsi_endpoint *beiscsi_ep, +					 unsigned short cid, +					 unsigned short issue_reset, +					 unsigned short savecfg_flag) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct iscsi_invalidate_connection_params_in *req = +						embedded_payload(wrb); +	int status = 0; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, +			   OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, +			   sizeof(*req)); +	req->session_handle = beiscsi_ep->fw_handle; +	req->cid = cid; +	if (issue_reset) +		req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST; +	else +		req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; +	req->save_cfg = savecfg_flag; +	status = be_mbox_notify(ctrl); +	if (status) +		SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n"); + +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, +				unsigned short cid, unsigned int upload_flag) +{ +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct tcp_upload_params_in *req = embedded_payload(wrb); +	int status = 0; + +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +	be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, +			   OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); +	req->id = (unsigned short)cid; +	req->upload_type = (unsigned char)upload_flag; +	status = be_mbox_notify(ctrl); +	if (status) +		SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n"); +	spin_unlock(&ctrl->mbox_lock); +	return status; +} + +int mgmt_open_connection(struct beiscsi_hba *phba, +			 struct sockaddr *dst_addr, +			 struct beiscsi_endpoint *beiscsi_ep) +{ +	struct hwi_controller *phwi_ctrlr; +	struct hwi_context_memory *phwi_context; +	struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; +	struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; +	struct be_ctrl_info *ctrl = &phba->ctrl; +	struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); +	struct tcp_connect_and_offload_in *req = embedded_payload(wrb); +	unsigned short def_hdr_id; +	unsigned short def_data_id; +	struct phys_addr template_address = { 0, 0 }; +	struct phys_addr *ptemplate_address; +	int status = 0; +	unsigned short cid = beiscsi_ep->ep_cid; + +	phwi_ctrlr = phba->phwi_ctrlr; +	phwi_context = phwi_ctrlr->phwi_ctxt; +	def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba); +	def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba); + +	ptemplate_address = &template_address; +	ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); +	spin_lock(&ctrl->mbox_lock); +	memset(wrb, 0, sizeof(*wrb)); + +	be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); +	be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, +			   OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, +			   sizeof(*req)); +	if (dst_addr->sa_family == PF_INET) { +		__be32 s_addr = daddr_in->sin_addr.s_addr; +		req->ip_address.ip_type = BE2_IPV4; +		req->ip_address.ip_address[0] = s_addr & 0x000000ff; +		req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8; +		req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16; +		req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24; +		req->tcp_port = ntohs(daddr_in->sin_port); +		beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; +		beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); +		beiscsi_ep->ip_type = BE2_IPV4; +	} else if (dst_addr->sa_family == PF_INET6) { +		req->ip_address.ip_type = BE2_IPV6; +		memcpy(&req->ip_address.ip_address, +		       &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); +		req->tcp_port = ntohs(daddr_in6->sin6_port); +		beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); +		memcpy(&beiscsi_ep->dst6_addr, +		       &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); +		beiscsi_ep->ip_type = BE2_IPV6; +	} else{ +		shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n", +			     dst_addr->sa_family); +		spin_unlock(&ctrl->mbox_lock); +		return -EINVAL; + +	} +	req->cid = cid; +	req->cq_id = phwi_context->be_cq.id; +	req->defq_id = def_hdr_id; +	req->hdr_ring_id = def_hdr_id; +	req->data_ring_id = def_data_id; +	req->do_offload = 1; +	req->dataout_template_pa.lo = ptemplate_address->lo; +	req->dataout_template_pa.hi = ptemplate_address->hi; +	status = be_mbox_notify(ctrl); +	if (!status) { +		struct iscsi_endpoint *ep; +		struct tcp_connect_and_offload_out *ptcpcnct_out = +							embedded_payload(wrb); + +		ep = phba->ep_array[ptcpcnct_out->cid]; +		beiscsi_ep = ep->dd_data; +		beiscsi_ep->fw_handle = 0; +		beiscsi_ep->cid_vld = 1; +		SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); +	} else +		SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n"); +	spin_unlock(&ctrl->mbox_lock); +	return status; +} diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h new file mode 100644 index 00000000000..00e816ee807 --- /dev/null +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -0,0 +1,249 @@ +/** + * Copyright (C) 2005 - 2009 ServerEngines + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation.  The full GNU General + * Public License is included in this distribution in the file called COPYING. + * + * Written by: Jayamohan Kallickal (jayamohank@serverengines.com) + * + * Contact Information: + * linux-drivers@serverengines.com + * + * ServerEngines + * 209 N. Fair Oaks Ave + * Sunnyvale, CA 94085 + * + */ + +#ifndef _BEISCSI_MGMT_ +#define _BEISCSI_MGMT_ + +#include <linux/types.h> +#include <linux/list.h> +#include "be_iscsi.h" +#include "be_main.h" + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_mcc_sge { +	u8 pa_lo[32];		/* dword 0 */ +	u8 pa_hi[32];		/* dword 1 */ +	u8 length[32];		/* DWORD 2 */ +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_mcc_wrb_payload { +	union { +		struct amap_mcc_sge sgl[19]; +		u8 embedded[59 * 32];	/* DWORDS 57 to 115 */ +	} u; +} __packed; + +/** + * Pseudo amap definition in which each bit of the actual structure is defined + * as a byte: used to calculate offset/shift/mask of each field + */ +struct amap_mcc_wrb { +	u8 embedded;		/* DWORD 0 */ +	u8 rsvd0[2];		/* DWORD 0 */ +	u8 sge_count[5];	/* DWORD 0 */ +	u8 rsvd1[16];		/* DWORD 0 */ +	u8 special[8];		/* DWORD 0 */ +	u8 payload_length[32]; +	u8 tag[64];		/* DWORD 2 */ +	u8 rsvd2[32];		/* DWORD 4 */ +	struct amap_mcc_wrb_payload payload; +}; + +struct mcc_sge { +	u32 pa_lo;		/* dword 0 */ +	u32 pa_hi;		/* dword 1 */ +	u32 length;		/* DWORD 2 */ +} __packed; + +struct mcc_wrb_payload { +	union { +		struct mcc_sge sgl[19]; +		u32 embedded[59];	/* DWORDS 57 to 115 */ +	} u; +} __packed; + +#define MCC_WRB_EMBEDDED_MASK                0x00000001 + +struct mcc_wrb { +	u32 dw[0];		/* DWORD 0 */ +	u32 payload_length; +	u32 tag[2];		/* DWORD 2 */ +	u32 rsvd2[1];		/* DWORD 4 */ +	struct mcc_wrb_payload payload; +}; + +unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); +int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, +			 struct beiscsi_endpoint *beiscsi_ep); + +unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, +				     unsigned short cid, +				     unsigned int upload_flag); +unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, +				   unsigned int icd, unsigned int cid); + +struct iscsi_invalidate_connection_params_in { +	struct be_cmd_req_hdr hdr; +	unsigned int session_handle; +	unsigned short cid; +	unsigned short unused; +	unsigned short cleanup_type; +	unsigned short save_cfg; +} __packed; + +struct iscsi_invalidate_connection_params_out { +	unsigned int session_handle; +	unsigned short cid; +	unsigned short unused; +} __packed; + +union iscsi_invalidate_connection_params { +	struct iscsi_invalidate_connection_params_in request; +	struct iscsi_invalidate_connection_params_out response; +} __packed; + +struct invalidate_command_table { +	unsigned short icd; +	unsigned short cid; +} __packed; + +struct invalidate_commands_params_in { +	struct be_cmd_req_hdr hdr; +	unsigned int ref_handle; +	unsigned int icd_count; +	struct invalidate_command_table table[128]; +	unsigned short cleanup_type; +	unsigned short unused; +} __packed; + +struct invalidate_commands_params_out { +	unsigned int ref_handle; +	unsigned int icd_count; +	unsigned int icd_status[128]; +} __packed; + +union invalidate_commands_params { +	struct invalidate_commands_params_in request; +	struct invalidate_commands_params_out response; +} __packed; + +struct mgmt_hba_attributes { +	u8 flashrom_version_string[32]; +	u8 manufacturer_name[32]; +	u32 supported_modes; +	u8 seeprom_version_lo; +	u8 seeprom_version_hi; +	u8 rsvd0[2]; +	u32 fw_cmd_data_struct_version; +	u32 ep_fw_data_struct_version; +	u32 future_reserved[12]; +	u32 default_extended_timeout; +	u8 controller_model_number[32]; +	u8 controller_description[64]; +	u8 controller_serial_number[32]; +	u8 ip_version_string[32]; +	u8 firmware_version_string[32]; +	u8 bios_version_string[32]; +	u8 redboot_version_string[32]; +	u8 driver_version_string[32]; +	u8 fw_on_flash_version_string[32]; +	u32 functionalities_supported; +	u16 max_cdblength; +	u8 asic_revision; +	u8 generational_guid[16]; +	u8 hba_port_count; +	u16 default_link_down_timeout; +	u8 iscsi_ver_min_max; +	u8 multifunction_device; +	u8 cache_valid; +	u8 hba_status; +	u8 max_domains_supported; +	u8 phy_port; +	u32 firmware_post_status; +	u32 hba_mtu[8]; +	u32 future_u32[4]; +} __packed; + +struct mgmt_controller_attributes { +	struct mgmt_hba_attributes hba_attribs; +	u16 pci_vendor_id; +	u16 pci_device_id; +	u16 pci_sub_vendor_id; +	u16 pci_sub_system_id; +	u8 pci_bus_number; +	u8 pci_device_number; +	u8 pci_function_number; +	u8 interface_type; +	u64 unique_identifier; +	u8 netfilters; +	u8 rsvd0[3]; +	u8 future_u32[4]; +} __packed; + +struct be_mgmt_controller_attributes { +	struct be_cmd_req_hdr hdr; +	struct mgmt_controller_attributes params; +} __packed; + +struct be_mgmt_controller_attributes_resp { +	struct be_cmd_resp_hdr hdr; +	struct mgmt_controller_attributes params; +} __packed; + +/* configuration management */ + +#define GET_MGMT_CONTROLLER_WS(phba)    (phba->pmgmt_ws) + +/* MGMT CMD flags */ + +#define MGMT_CMDH_FREE                (1<<0) + +/*  --- MGMT_ERROR_CODES --- */ +/*  Error Codes returned in the status field of the CMD response header */ +#define MGMT_STATUS_SUCCESS 0	/* The CMD completed without errors */ +#define MGMT_STATUS_FAILED 1	/* Error status in the Status field of */ +				/* the CMD_RESPONSE_HEADER  */ + +#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\ +    pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ +					bus_address.u.a32.address_lo;  \ +    pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ +					bus_address.u.a32.address_hi;  \ +} + +struct beiscsi_endpoint { +	struct beiscsi_hba *phba; +	struct beiscsi_sess *sess; +	struct beiscsi_conn *conn; +	unsigned short ip_type; +	char dst6_addr[ISCSI_ADDRESS_BUF_LEN]; +	unsigned long dst_addr; +	unsigned short ep_cid; +	unsigned int fw_handle; +	u16 dst_tcpport; +	u16 cid_vld; +}; + +unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, +				 struct beiscsi_hba *phba); + +unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, +					 struct beiscsi_endpoint *beiscsi_ep, +					 unsigned short cid, +					 unsigned short issue_reset, +					 unsigned short savecfg_flag); +#endif diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile new file mode 100644 index 00000000000..1d6009490d1 --- /dev/null +++ b/drivers/scsi/bfa/Makefile @@ -0,0 +1,15 @@ +obj-$(CONFIG_SCSI_BFA_FC) := bfa.o + +bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o + +bfa-y += bfa_core.o bfa_ioc.o bfa_iocfc.o bfa_fcxp.o bfa_lps.o +bfa-y += bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o  +bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o +bfa-y += bfa_itnim.o bfa_fcpim.o bfa_tskim.o bfa_log.o bfa_log_module.o +bfa-y += bfa_csdebug.o bfa_sm.o plog.o + +bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o  +bfa-y += bfa_fcs_uf.o bfa_fcs_lport.o fab.o fdmi.o ms.o ns.o scn.o loop.o +bfa-y += lport_api.o n2n.o rport.o rport_api.o rport_ftrs.o vport.o + +ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna diff --git a/drivers/scsi/bfa/bfa_callback_priv.h b/drivers/scsi/bfa/bfa_callback_priv.h new file mode 100644 index 00000000000..1e3265c9f7d --- /dev/null +++ b/drivers/scsi/bfa/bfa_callback_priv.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_CALLBACK_PRIV_H__ +#define __BFA_CALLBACK_PRIV_H__ + +#include <cs/bfa_q.h> + +typedef void    (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); + +/** + * Generic BFA callback element. + */ +struct bfa_cb_qe_s { +	struct list_head         qe; +	bfa_cb_cbfn_t  cbfn; +	bfa_boolean_t   once; +	u32		rsvd; +	void           *cbarg; +}; + +#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do {		\ +	(__hcb_qe)->cbfn  = (__cbfn);      \ +	(__hcb_qe)->cbarg = (__cbarg);      \ +	list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q);      \ +} while (0) + +#define bfa_cb_dequeue(__hcb_qe)	list_del(&(__hcb_qe)->qe) + +#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do {	\ +	(__hcb_qe)->cbfn  = (__cbfn);      \ +	(__hcb_qe)->cbarg = (__cbarg);      \ +	if (!(__hcb_qe)->once) {      \ +		list_add_tail((__hcb_qe), &(__bfa)->comp_q);      \ +		(__hcb_qe)->once = BFA_TRUE;				\ +	}								\ +} while (0) + +#define bfa_cb_queue_done(__hcb_qe) do {				\ +	(__hcb_qe)->once = BFA_FALSE;					\ +} while (0) + +#endif /* __BFA_CALLBACK_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h new file mode 100644 index 00000000000..0050c838c35 --- /dev/null +++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_cb_ioim_macros.h BFA IOIM driver interface macros. + */ + +#ifndef __BFA_HCB_IOIM_MACROS_H__ +#define __BFA_HCB_IOIM_MACROS_H__ + +#include <bfa_os_inc.h> +/* + * #include <linux/dma-mapping.h> + * + * #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include + * <scsi/scsi_device.h> #include <scsi/scsi_host.h> + */ +#include "bfad_im_compat.h" + +/* + * task attribute values in FCP-2 FCP_CMND IU + */ +#define SIMPLE_Q    0 +#define HEAD_OF_Q   1 +#define ORDERED_Q   2 +#define ACA_Q       4 +#define UNTAGGED    5 + +static inline lun_t +bfad_int_to_lun(u32 luno) +{ +	union { +		u16        scsi_lun[4]; +		lun_t           bfa_lun; +	} lun; + +	lun.bfa_lun     = 0; +	lun.scsi_lun[0] = bfa_os_htons(luno); + +	return (lun.bfa_lun); +} + +/** + * Get LUN for the I/O request + */ +#define bfa_cb_ioim_get_lun(__dio)	\ +	bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun) + +/** + * Get CDB for the I/O request + */ +static inline u8 * +bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; + +	return ((u8 *) cmnd->cmnd); +} + +/** + * Get I/O direction (read/write) for the I/O request + */ +static inline enum fcp_iodir +bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	enum dma_data_direction dmadir; + +	dmadir = cmnd->sc_data_direction; +	if (dmadir == DMA_TO_DEVICE) +		return FCP_IODIR_WRITE; +	else if (dmadir == DMA_FROM_DEVICE) +		return FCP_IODIR_READ; +	else +		return FCP_IODIR_NONE; +} + +/** + * Get IO size in bytes for the I/O request + */ +static inline u32 +bfa_cb_ioim_get_size(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; + +	return (scsi_bufflen(cmnd)); +} + +/** + * Get timeout for the I/O request + */ +static inline u8 +bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	/* +	 * TBD: need a timeout for scsi passthru +	 */ +	if (cmnd->device->host == NULL) +		return 4; + +	return 0; +} + +/** + * Get SG element for the I/O request given the SG element index + */ +static inline union bfi_addr_u +bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	struct scatterlist *sge; +	u64        addr; + +	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid; +	addr = (u64) sg_dma_address(sge); + +	return (*(union bfi_addr_u *) &addr); +} + +static inline u32 +bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	struct scatterlist *sge; +	u32        len; + +	sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid; +	len = sg_dma_len(sge); + +	return len; +} + +/** + * Get Command Reference Number for the I/O request. 0 if none. + */ +static inline u8 +bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio) +{ +	return 0; +} + +/** + * Get SAM-3 priority for the I/O request. 0 is default. + */ +static inline u8 +bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio) +{ +	return 0; +} + +/** + * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0). + */ +static inline u8 +bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	u8         task_attr = UNTAGGED; + +	if (cmnd->device->tagged_supported) { +		switch (cmnd->tag) { +		case HEAD_OF_QUEUE_TAG: +			task_attr = HEAD_OF_Q; +			break; +		case ORDERED_QUEUE_TAG: +			task_attr = ORDERED_Q; +			break; +		default: +			task_attr = SIMPLE_Q; +			break; +		} +	} + +	return task_attr; +} + +/** + * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16). + */ +static inline u8 +bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; + +	return (cmnd->cmd_len); +} + + + +#endif /* __BFA_HCB_IOIM_MACROS_H__ */ diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c new file mode 100644 index 00000000000..7a959c34e78 --- /dev/null +++ b/drivers/scsi/bfa/bfa_cee.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <defs/bfa_defs_cee.h> +#include <cs/bfa_trc.h> +#include <cs/bfa_log.h> +#include <cs/bfa_debug.h> +#include <cee/bfa_cee.h> +#include <bfi/bfi_cee.h> +#include <bfi/bfi.h> +#include <bfa_ioc.h> +#include <cna/bfa_cna_trcmod.h> + +BFA_TRC_FILE(CNA, CEE); + +#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) +#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc) + +static void     bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg); +static void     bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s +					   *dcbcx_stats); +static void     bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s +					  *lldp_stats); +static void     bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats); +static void     bfa_cee_format_cee_cfg(void *buffer); +static void     bfa_cee_format_cee_stats(void *buffer); + +static void +bfa_cee_format_cee_stats(void *buffer) +{ +	struct bfa_cee_stats_s *cee_stats = buffer; +	bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats); +	bfa_cee_format_lldp_stats(&cee_stats->lldp_stats); +	bfa_cee_format_cfg_stats(&cee_stats->cfg_stats); +} + +static void +bfa_cee_format_cee_cfg(void *buffer) +{ +	struct bfa_cee_attr_s *cee_cfg = buffer; +	bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote); +} + +static void +bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s *dcbcx_stats) +{ +	dcbcx_stats->subtlvs_unrecognized = +		bfa_os_ntohl(dcbcx_stats->subtlvs_unrecognized); +	dcbcx_stats->negotiation_failed = +		bfa_os_ntohl(dcbcx_stats->negotiation_failed); +	dcbcx_stats->remote_cfg_changed = +		bfa_os_ntohl(dcbcx_stats->remote_cfg_changed); +	dcbcx_stats->tlvs_received = bfa_os_ntohl(dcbcx_stats->tlvs_received); +	dcbcx_stats->tlvs_invalid = bfa_os_ntohl(dcbcx_stats->tlvs_invalid); +	dcbcx_stats->seqno = bfa_os_ntohl(dcbcx_stats->seqno); +	dcbcx_stats->ackno = bfa_os_ntohl(dcbcx_stats->ackno); +	dcbcx_stats->recvd_seqno = bfa_os_ntohl(dcbcx_stats->recvd_seqno); +	dcbcx_stats->recvd_ackno = bfa_os_ntohl(dcbcx_stats->recvd_ackno); +} + +static void +bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s *lldp_stats) +{ +	lldp_stats->frames_transmitted = +		bfa_os_ntohl(lldp_stats->frames_transmitted); +	lldp_stats->frames_aged_out = bfa_os_ntohl(lldp_stats->frames_aged_out); +	lldp_stats->frames_discarded = +		bfa_os_ntohl(lldp_stats->frames_discarded); +	lldp_stats->frames_in_error = bfa_os_ntohl(lldp_stats->frames_in_error); +	lldp_stats->frames_rcvd = bfa_os_ntohl(lldp_stats->frames_rcvd); +	lldp_stats->tlvs_discarded = bfa_os_ntohl(lldp_stats->tlvs_discarded); +	lldp_stats->tlvs_unrecognized = +		bfa_os_ntohl(lldp_stats->tlvs_unrecognized); +} + +static void +bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats) +{ +	cfg_stats->cee_status_down = bfa_os_ntohl(cfg_stats->cee_status_down); +	cfg_stats->cee_status_up = bfa_os_ntohl(cfg_stats->cee_status_up); +	cfg_stats->cee_hw_cfg_changed = +		bfa_os_ntohl(cfg_stats->cee_hw_cfg_changed); +	cfg_stats->recvd_invalid_cfg = +		bfa_os_ntohl(cfg_stats->recvd_invalid_cfg); +} + +static void +bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg) +{ +	lldp_cfg->time_to_interval = bfa_os_ntohs(lldp_cfg->time_to_interval); +	lldp_cfg->enabled_system_cap = +		bfa_os_ntohs(lldp_cfg->enabled_system_cap); +} + +/** + * bfa_cee_attr_meminfo() + * + * + * @param[in] void + * + * @return Size of DMA region + */ +static          u32 +bfa_cee_attr_meminfo(void) +{ +	return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); +} + +/** + * bfa_cee_stats_meminfo() + * + * + * @param[in] void + * + * @return Size of DMA region + */ +static          u32 +bfa_cee_stats_meminfo(void) +{ +	return BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ); +} + +/** + * bfa_cee_get_attr_isr() + * + * + * @param[in] cee - Pointer to the CEE module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status) +{ +	cee->get_attr_status = status; +	bfa_trc(cee, 0); +	if (status == BFA_STATUS_OK) { +		bfa_trc(cee, 0); +		/* +		 * The requested data has been copied to the DMA area, *process +		 * it. +		 */ +		memcpy(cee->attr, cee->attr_dma.kva, +		       sizeof(struct bfa_cee_attr_s)); +		bfa_cee_format_cee_cfg(cee->attr); +	} +	cee->get_attr_pending = BFA_FALSE; +	if (cee->cbfn.get_attr_cbfn) { +		bfa_trc(cee, 0); +		cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status); +	} +	bfa_trc(cee, 0); +} + +/** + * bfa_cee_get_attr_isr() + * + * + * @param[in] cee - Pointer to the CEE module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) +{ +	cee->get_stats_status = status; +	bfa_trc(cee, 0); +	if (status == BFA_STATUS_OK) { +		bfa_trc(cee, 0); +		/* +		 * The requested data has been copied to the DMA area, process +		 * it. +		 */ +		memcpy(cee->stats, cee->stats_dma.kva, +		       sizeof(struct bfa_cee_stats_s)); +		bfa_cee_format_cee_stats(cee->stats); +	} +	cee->get_stats_pending = BFA_FALSE; +	bfa_trc(cee, 0); +	if (cee->cbfn.get_stats_cbfn) { +		bfa_trc(cee, 0); +		cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status); +	} +	bfa_trc(cee, 0); +} + +/** + * bfa_cee_get_attr_isr() + * + * + * @param[in] cee - Pointer to the CEE module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) +{ +	cee->reset_stats_status = status; +	cee->reset_stats_pending = BFA_FALSE; +	if (cee->cbfn.reset_stats_cbfn) +		cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status); +} + +/** + * bfa_cee_meminfo() + * + * + * @param[in] void + * + * @return Size of DMA region + */ +u32 +bfa_cee_meminfo(void) +{ +	return (bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo()); +} + +/** + * bfa_cee_mem_claim() + * + * + * @param[in] cee CEE module pointer + * 	      dma_kva Kernel Virtual Address of CEE DMA Memory + * 	      dma_pa  Physical Address of CEE DMA Memory + * + * @return void + */ +void +bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa) +{ +	cee->attr_dma.kva = dma_kva; +	cee->attr_dma.pa = dma_pa; +	cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo(); +	cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo(); +	cee->attr = (struct bfa_cee_attr_s *)dma_kva; +	cee->stats = +		(struct bfa_cee_stats_s *)(dma_kva + bfa_cee_attr_meminfo()); +} + +/** + * bfa_cee_get_attr() + * + *   Send the request to the f/w to fetch CEE attributes. + * + * @param[in] Pointer to the CEE module data structure. + * + * @return Status + */ + +bfa_status_t +bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr, +		 bfa_cee_get_attr_cbfn_t cbfn, void *cbarg) +{ +	struct bfi_cee_get_req_s *cmd; + +	bfa_assert((cee != NULL) && (cee->ioc != NULL)); +	bfa_trc(cee, 0); +	if (!bfa_ioc_is_operational(cee->ioc)) { +		bfa_trc(cee, 0); +		return BFA_STATUS_IOC_FAILURE; +	} +	if (cee->get_attr_pending == BFA_TRUE) { +		bfa_trc(cee, 0); +		return BFA_STATUS_DEVBUSY; +	} +	cee->get_attr_pending = BFA_TRUE; +	cmd = (struct bfi_cee_get_req_s *)cee->get_cfg_mb.msg; +	cee->attr = attr; +	cee->cbfn.get_attr_cbfn = cbfn; +	cee->cbfn.get_attr_cbarg = cbarg; +	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, +		    bfa_ioc_portid(cee->ioc)); +	bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa); +	bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb); +	bfa_trc(cee, 0); + +	return BFA_STATUS_OK; +} + +/** + * bfa_cee_get_stats() + * + *   Send the request to the f/w to fetch CEE statistics. + * + * @param[in] Pointer to the CEE module data structure. + * + * @return Status + */ + +bfa_status_t +bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats, +		  bfa_cee_get_stats_cbfn_t cbfn, void *cbarg) +{ +	struct bfi_cee_get_req_s *cmd; + +	bfa_assert((cee != NULL) && (cee->ioc != NULL)); + +	if (!bfa_ioc_is_operational(cee->ioc)) { +		bfa_trc(cee, 0); +		return BFA_STATUS_IOC_FAILURE; +	} +	if (cee->get_stats_pending == BFA_TRUE) { +		bfa_trc(cee, 0); +		return BFA_STATUS_DEVBUSY; +	} +	cee->get_stats_pending = BFA_TRUE; +	cmd = (struct bfi_cee_get_req_s *)cee->get_stats_mb.msg; +	cee->stats = stats; +	cee->cbfn.get_stats_cbfn = cbfn; +	cee->cbfn.get_stats_cbarg = cbarg; +	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, +		    bfa_ioc_portid(cee->ioc)); +	bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa); +	bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb); +	bfa_trc(cee, 0); + +	return BFA_STATUS_OK; +} + +/** + * bfa_cee_reset_stats() + * + * + * @param[in] Pointer to the CEE module data structure. + * + * @return Status + */ + +bfa_status_t +bfa_cee_reset_stats(struct bfa_cee_s *cee, bfa_cee_reset_stats_cbfn_t cbfn, +		    void *cbarg) +{ +	struct bfi_cee_reset_stats_s *cmd; + +	bfa_assert((cee != NULL) && (cee->ioc != NULL)); +	if (!bfa_ioc_is_operational(cee->ioc)) { +		bfa_trc(cee, 0); +		return BFA_STATUS_IOC_FAILURE; +	} +	if (cee->reset_stats_pending == BFA_TRUE) { +		bfa_trc(cee, 0); +		return BFA_STATUS_DEVBUSY; +	} +	cee->reset_stats_pending = BFA_TRUE; +	cmd = (struct bfi_cee_reset_stats_s *)cee->reset_stats_mb.msg; +	cee->cbfn.reset_stats_cbfn = cbfn; +	cee->cbfn.reset_stats_cbarg = cbarg; +	bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, +		    bfa_ioc_portid(cee->ioc)); +	bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb); +	bfa_trc(cee, 0); +	return BFA_STATUS_OK; +} + +/** + * bfa_cee_isrs() + * + * + * @param[in] Pointer to the CEE module data structure. + * + * @return void + */ + +void +bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m) +{ +	union bfi_cee_i2h_msg_u *msg; +	struct bfi_cee_get_rsp_s *get_rsp; +	struct bfa_cee_s *cee = (struct bfa_cee_s *)cbarg; +	msg = (union bfi_cee_i2h_msg_u *)m; +	get_rsp = (struct bfi_cee_get_rsp_s *)m; +	bfa_trc(cee, msg->mh.msg_id); +	switch (msg->mh.msg_id) { +	case BFI_CEE_I2H_GET_CFG_RSP: +		bfa_trc(cee, get_rsp->cmd_status); +		bfa_cee_get_attr_isr(cee, get_rsp->cmd_status); +		break; +	case BFI_CEE_I2H_GET_STATS_RSP: +		bfa_cee_get_stats_isr(cee, get_rsp->cmd_status); +		break; +	case BFI_CEE_I2H_RESET_STATS_RSP: +		bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status); +		break; +	default: +		bfa_assert(0); +	} +} + +/** + * bfa_cee_hbfail() + * + * + * @param[in] Pointer to the CEE module data structure. + * + * @return void + */ + +void +bfa_cee_hbfail(void *arg) +{ +	struct bfa_cee_s *cee; +	cee = (struct bfa_cee_s *)arg; + +	if (cee->get_attr_pending == BFA_TRUE) { +		cee->get_attr_status = BFA_STATUS_FAILED; +		cee->get_attr_pending = BFA_FALSE; +		if (cee->cbfn.get_attr_cbfn) { +			cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, +						BFA_STATUS_FAILED); +		} +	} +	if (cee->get_stats_pending == BFA_TRUE) { +		cee->get_stats_status = BFA_STATUS_FAILED; +		cee->get_stats_pending = BFA_FALSE; +		if (cee->cbfn.get_stats_cbfn) { +			cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, +						 BFA_STATUS_FAILED); +		} +	} +	if (cee->reset_stats_pending == BFA_TRUE) { +		cee->reset_stats_status = BFA_STATUS_FAILED; +		cee->reset_stats_pending = BFA_FALSE; +		if (cee->cbfn.reset_stats_cbfn) { +			cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, +						   BFA_STATUS_FAILED); +		} +	} +} + +/** + * bfa_cee_attach() + * + * + * @param[in] cee - Pointer to the CEE module data structure + *            ioc - Pointer to the ioc module data structure + *            dev - Pointer to the device driver module data structure + *                  The device driver specific mbox ISR functions have + *                  this pointer as one of the parameters. + *            trcmod - + *            logmod - + * + * @return void + */ +void +bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev, +	       struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) +{ +	bfa_assert(cee != NULL); +	cee->dev = dev; +	cee->trcmod = trcmod; +	cee->logmod = logmod; +	cee->ioc = ioc; + +	bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee); +	bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee); +	bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail); +	bfa_trc(cee, 0); +} + +/** + * bfa_cee_detach() + * + * + * @param[in] cee - Pointer to the CEE module data structure + * + * @return void + */ +void +bfa_cee_detach(struct bfa_cee_s *cee) +{ +	/* +	 * For now, just check if there is some ioctl pending and mark that as +	 * failed? +	 */ +	/* bfa_cee_hbfail(cee); */ +} diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c new file mode 100644 index 00000000000..44e2d1155c5 --- /dev/null +++ b/drivers/scsi/bfa/bfa_core.c @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <defs/bfa_defs_pci.h> +#include <cs/bfa_debug.h> +#include <bfa_iocfc.h> + +#define DEF_CFG_NUM_FABRICS         1 +#define DEF_CFG_NUM_LPORTS          256 +#define DEF_CFG_NUM_CQS             4 +#define DEF_CFG_NUM_IOIM_REQS       (BFA_IOIM_MAX) +#define DEF_CFG_NUM_TSKIM_REQS      128 +#define DEF_CFG_NUM_FCXP_REQS       64 +#define DEF_CFG_NUM_UF_BUFS         64 +#define DEF_CFG_NUM_RPORTS          1024 +#define DEF_CFG_NUM_ITNIMS          (DEF_CFG_NUM_RPORTS) +#define DEF_CFG_NUM_TINS            256 + +#define DEF_CFG_NUM_SGPGS           2048 +#define DEF_CFG_NUM_REQQ_ELEMS      256 +#define DEF_CFG_NUM_RSPQ_ELEMS      64 +#define DEF_CFG_NUM_SBOOT_TGTS      16 +#define DEF_CFG_NUM_SBOOT_LUNS      16 + +/** + * Use this function query the memory requirement of the BFA library. + * This function needs to be called before bfa_attach() to get the + * memory required of the BFA layer for a given driver configuration. + * + * This call will fail, if the cap is out of range compared to pre-defined + * values within the BFA library + * + * @param[in] cfg - 	pointer to bfa_ioc_cfg_t. Driver layer should indicate + * 			its configuration in this structure. + *			The default values for struct bfa_iocfc_cfg_s can be + *			fetched using bfa_cfg_get_default() API. + * + * 			If cap's boundary check fails, the library will use + *			the default bfa_cap_t values (and log a warning msg). + * + * @param[out] meminfo - pointer to bfa_meminfo_t. This content + * 			indicates the memory type (see bfa_mem_type_t) and + *			amount of memory required. + * + *			Driver should allocate the memory, populate the + *			starting address for each block and provide the same + *			structure as input parameter to bfa_attach() call. + * + * @return void + * + * Special Considerations: @note + */ +void +bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo) +{ +	int             i; +	u32        km_len = 0, dm_len = 0; + +	bfa_assert((cfg != NULL) && (meminfo != NULL)); + +	bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s)); +	meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type = +		BFA_MEM_TYPE_KVA; +	meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type = +		BFA_MEM_TYPE_DMA; + +	bfa_iocfc_meminfo(cfg, &km_len, &dm_len); + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->meminfo(cfg, &km_len, &dm_len); + + +	meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len; +	meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len; +} + +/** + * Use this function to do attach the driver instance with the BFA + * library. This function will not trigger any HW initialization + * process (which will be done in bfa_init() call) + * + * This call will fail, if the cap is out of range compared to + * pre-defined values within the BFA library + * + * @param[out]	bfa	Pointer to bfa_t. + * @param[in]	bfad 	Opaque handle back to the driver's IOC structure + * @param[in]	cfg	Pointer to bfa_ioc_cfg_t. Should be same structure + * 			that was used in bfa_cfg_get_meminfo(). + * @param[in] 	meminfo Pointer to bfa_meminfo_t. The driver should + * 			use the bfa_cfg_get_meminfo() call to + * 			find the memory blocks required, allocate the + * 			required memory and provide the starting addresses. + * @param[in] 	pcidev	pointer to struct bfa_pcidev_s + * + * @return + * void + * + * Special Considerations: + * + * @note + * + */ +void +bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +	       struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	int             i; +	struct bfa_mem_elem_s *melem; + +	bfa->fcs = BFA_FALSE; + +	bfa_assert((cfg != NULL) && (meminfo != NULL)); + +	/** +	 * initialize all memory pointers for iterative allocation +	 */ +	for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { +		melem = meminfo->meminfo + i; +		melem->kva_curp = melem->kva; +		melem->dma_curp = melem->dma; +	} + +	bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev); + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev); + +} + +/** + * Use this function to delete a BFA IOC. IOC should be stopped (by + * calling bfa_stop()) before this function call. + * + * @param[in] bfa - pointer to bfa_t. + * + * @return + * void + * + * Special Considerations: + * + * @note + */ +void +bfa_detach(struct bfa_s *bfa) +{ +	int	i; + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->detach(bfa); + +	bfa_iocfc_detach(bfa); +} + + +void +bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod) +{ +	bfa->trcmod = trcmod; +} + + +void +bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod) +{ +	bfa->logm = logmod; +} + + +void +bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen) +{ +	bfa->aen = aen; +} + +void +bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog) +{ +	bfa->plog = plog; +} + +/** + * Initialize IOC. + * + * This function will return immediately, when the IOC initialization is + * completed, the bfa_cb_init() will be called. + * + * @param[in]	bfa	instance + * + * @return void + * + * Special Considerations: + * + * @note + * When this function returns, the driver should register the interrupt service + * routine(s) and enable the device interrupts. If this is not done, + * bfa_cb_init() will never get called + */ +void +bfa_init(struct bfa_s *bfa) +{ +	bfa_iocfc_init(bfa); +} + +/** + * Use this function initiate the IOC configuration setup. This function + * will return immediately. + * + * @param[in]	bfa	instance + * + * @return None + */ +void +bfa_start(struct bfa_s *bfa) +{ +	bfa_iocfc_start(bfa); +} + +/** + * Use this function quiese the IOC. This function will return immediately, + * when the IOC is actually stopped, the bfa_cb_stop() will be called. + * + * @param[in] 	bfa - pointer to bfa_t. + * + * @return None + * + * Special Considerations: + * bfa_cb_stop() could be called before or after bfa_stop() returns. + * + * @note + * In case of any failure, we could handle it automatically by doing a + * reset and then succeed the bfa_stop() call. + */ +void +bfa_stop(struct bfa_s *bfa) +{ +	bfa_iocfc_stop(bfa); +} + +void +bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q) +{ +	INIT_LIST_HEAD(comp_q); +	list_splice_tail_init(&bfa->comp_q, comp_q); +} + +void +bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) +{ +	struct list_head        *qe; +	struct list_head        *qen; +	struct bfa_cb_qe_s   *hcb_qe; + +	list_for_each_safe(qe, qen, comp_q) { +		hcb_qe = (struct bfa_cb_qe_s *) qe; +		hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE); +	} +} + +void +bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q) +{ +	struct list_head        *qe; +	struct bfa_cb_qe_s   *hcb_qe; + +	while (!list_empty(comp_q)) { +		bfa_q_deq(comp_q, &qe); +		hcb_qe = (struct bfa_cb_qe_s *) qe; +		hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE); +	} +} + +void +bfa_attach_fcs(struct bfa_s *bfa) +{ +	bfa->fcs = BFA_TRUE; +} + +/** + * Periodic timer heart beat from driver + */ +void +bfa_timer_tick(struct bfa_s *bfa) +{ +	bfa_timer_beat(&bfa->timer_mod); +} + +#ifndef BFA_BIOS_BUILD +/** + * Return the list of PCI vendor/device id lists supported by this + * BFA instance. + */ +void +bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) +{ +	static struct bfa_pciid_s __pciids[] = { +		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P}, +		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P}, +		{BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT}, +	}; + +	*npciids = sizeof(__pciids) / sizeof(__pciids[0]); +	*pciids = __pciids; +} + +/** + * Use this function query the default struct bfa_iocfc_cfg_s value (compiled + * into BFA layer). The OS driver can then turn back and overwrite entries that + * have been configured by the user. + * + * @param[in] cfg - pointer to bfa_ioc_cfg_t + * + * @return + *	void + * + * Special Considerations: + * 	note + */ +void +bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) +{ +	cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS; +	cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS; +	cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS; +	cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS; +	cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS; +	cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS; +	cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS; +	cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS; + +	cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS; +	cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS; +	cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS; +	cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS; +	cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS; +	cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF; +	cfg->drvcfg.ioc_recover = BFA_FALSE; +	cfg->drvcfg.delay_comp = BFA_FALSE; + +} + +void +bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) +{ +	bfa_cfg_get_default(cfg); +	cfg->fwcfg.num_ioim_reqs   = BFA_IOIM_MIN; +	cfg->fwcfg.num_tskim_reqs  = BFA_TSKIM_MIN; +	cfg->fwcfg.num_fcxp_reqs   = BFA_FCXP_MIN; +	cfg->fwcfg.num_uf_bufs     = BFA_UF_MIN; +	cfg->fwcfg.num_rports      = BFA_RPORT_MIN; + +	cfg->drvcfg.num_sgpgs      = BFA_SGPG_MIN; +	cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; +	cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN; +	cfg->drvcfg.min_cfg        = BFA_TRUE; +} + +void +bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr) +{ +	bfa_ioc_get_attr(&bfa->ioc, ioc_attr); +} + +/** + * Retrieve firmware trace information on IOC failure. + */ +bfa_status_t +bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen) +{ +	return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen); +} + +/** + * 		Fetch firmware trace data. + * + * @param[in]		bfa			BFA instance + * @param[out]		trcdata		Firmware trace buffer + * @param[in,out]	trclen		Firmware trace buffer len + * + * @retval BFA_STATUS_OK			Firmware trace is fetched. + * @retval BFA_STATUS_INPROGRESS	Firmware trace fetch is in progress. + */ +bfa_status_t +bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen) +{ +	return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen); +} +#endif diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c new file mode 100644 index 00000000000..1b71d349451 --- /dev/null +++ b/drivers/scsi/bfa/bfa_csdebug.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <cs/bfa_debug.h> +#include <bfa_os_inc.h> +#include <cs/bfa_q.h> +#include <log/bfa_log_hal.h> + +/** + *  cs_debug_api + */ + + +void +bfa_panic(int line, char *file, char *panicstr) +{ +	bfa_log(NULL, BFA_LOG_HAL_ASSERT, file, line, panicstr); +	bfa_os_panic(); +} + +void +bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event) +{ +	bfa_log(logm, BFA_LOG_HAL_SM_ASSERT, file, line, event); +	bfa_os_panic(); +} + +int +bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe) +{ +	struct list_head        *tqe; + +	tqe = bfa_q_next(q); +	while (tqe != q) { +		if (tqe == qe) +			return (1); +		tqe = bfa_q_next(tqe); +		if (tqe == NULL) +			break; +	} +	return (0); +} + + diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c new file mode 100644 index 00000000000..401babe3494 --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <log/bfa_log_hal.h> + +BFA_TRC_FILE(HAL, FCPIM); +BFA_MODULE(fcpim); + +/** + *  hal_fcpim_mod BFA FCP Initiator Mode module + */ + +/** + * 		Compute and return memory needed by FCP(im) module. + */ +static void +bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len) +{ +	bfa_itnim_meminfo(cfg, km_len, dm_len); + +	/** +	 * IO memory +	 */ +	if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) +		cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; +	else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) +		cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; + +	*km_len += cfg->fwcfg.num_ioim_reqs * +	  (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s)); + +	*dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN; + +	/** +	 * task management command memory +	 */ +	if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN) +		cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN; +	*km_len += cfg->fwcfg.num_tskim_reqs * sizeof(struct bfa_tskim_s); +} + + +static void +bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		     struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	bfa_trc(bfa, cfg->drvcfg.path_tov); +	bfa_trc(bfa, cfg->fwcfg.num_rports); +	bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs); +	bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs); + +	fcpim->bfa            = bfa; +	fcpim->num_itnims     = cfg->fwcfg.num_rports; +	fcpim->num_ioim_reqs  = cfg->fwcfg.num_ioim_reqs; +	fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs; +	fcpim->path_tov       = cfg->drvcfg.path_tov; +	fcpim->delay_comp	  = cfg->drvcfg.delay_comp; + +	bfa_itnim_attach(fcpim, meminfo); +	bfa_tskim_attach(fcpim, meminfo); +	bfa_ioim_attach(fcpim, meminfo); +} + +static void +bfa_fcpim_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_fcpim_detach(struct bfa_s *bfa) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	bfa_ioim_detach(fcpim); +	bfa_tskim_detach(fcpim); +} + +static void +bfa_fcpim_start(struct bfa_s *bfa) +{ +} + +static void +bfa_fcpim_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_fcpim_iocdisable(struct bfa_s *bfa) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfa_itnim_s *itnim; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &fcpim->itnim_q) { +		itnim = (struct bfa_itnim_s *) qe; +		bfa_itnim_iocdisable(itnim); +	} +} + +void +bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	fcpim->path_tov = path_tov * 1000; +	if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX) +		fcpim->path_tov = BFA_FCPIM_PATHTOV_MAX; +} + +u16 +bfa_fcpim_path_tov_get(struct bfa_s *bfa) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	return (fcpim->path_tov / 1000); +} + +bfa_status_t +bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_fcpim_stats_s *modstats) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	*modstats = fcpim->stats; + +	return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcpim_clr_modstats(struct bfa_s *bfa) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	memset(&fcpim->stats, 0, sizeof(struct bfa_fcpim_stats_s)); + +	return BFA_STATUS_OK; +} + +void +bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX); + +	fcpim->q_depth = q_depth; +} + +u16 +bfa_fcpim_qdepth_get(struct bfa_s *bfa) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + +	return (fcpim->q_depth); +} + + diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h new file mode 100644 index 00000000000..153206cfb37 --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcpim_priv.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCPIM_PRIV_H__ +#define __BFA_FCPIM_PRIV_H__ + +#include <bfa_fcpim.h> +#include <defs/bfa_defs_fcpim.h> +#include <cs/bfa_wc.h> +#include "bfa_sgpg_priv.h" + +#define BFA_ITNIM_MIN   32 +#define BFA_ITNIM_MAX   1024 + +#define BFA_IOIM_MIN    8 +#define BFA_IOIM_MAX    2000 + +#define BFA_TSKIM_MIN   4 +#define BFA_TSKIM_MAX   512 +#define BFA_FCPIM_PATHTOV_DEF	(30 * 1000)	/* in millisecs */ +#define BFA_FCPIM_PATHTOV_MAX	(90 * 1000)	/* in millisecs */ + +#define bfa_fcpim_stats(__fcpim, __stats)   \ +    (__fcpim)->stats.__stats ++ + +struct bfa_fcpim_mod_s { +	struct bfa_s 	*bfa; +	struct bfa_itnim_s 	*itnim_arr; +	struct bfa_ioim_s 	*ioim_arr; +	struct bfa_ioim_sp_s *ioim_sp_arr; +	struct bfa_tskim_s 	*tskim_arr; +	struct bfa_dma_s	snsbase; +	int			num_itnims; +	int			num_ioim_reqs; +	int			num_tskim_reqs; +	u32		path_tov; +	u16		q_depth; +	u16		rsvd; +	struct list_head 	itnim_q;        /*  queue of active itnim    */ +	struct list_head 	ioim_free_q;    /*  free IO resources        */ +	struct list_head 	ioim_resfree_q; /*  IOs waiting for f/w      */ +	struct list_head 	ioim_comp_q;    /*  IO global comp Q         */ +	struct list_head 	tskim_free_q; +	u32	ios_active;	/*  current active IOs	      */ +	u32	delay_comp; +	struct bfa_fcpim_stats_s stats; +}; + +struct bfa_ioim_s; +struct bfa_tskim_s; + +/** + * BFA IO (initiator mode) + */ +struct bfa_ioim_s { +	struct list_head qe;		/*  queue elememt            */ +	bfa_sm_t		sm; 	/*  BFA ioim state machine   */ +	struct bfa_s 	        *bfa;	/*  BFA module               */ +	struct bfa_fcpim_mod_s	*fcpim;	/*  parent fcpim module      */ +	struct bfa_itnim_s 	*itnim;	/*  i-t-n nexus for this IO  */ +	struct bfad_ioim_s 	*dio;	/*  driver IO handle         */ +	u16	iotag;		/*  FWI IO tag               */ +	u16	abort_tag;	/*  unqiue abort request tag */ +	u16	nsges;		/*  number of SG elements    */ +	u16	nsgpgs;		/*  number of SG pages       */ +	struct bfa_sgpg_s *sgpg;	/*  first SG page            */ +	struct list_head sgpg_q;		/*  allocated SG pages       */ +	struct bfa_cb_qe_s hcb_qe;	/*  bfa callback qelem       */ +	bfa_cb_cbfn_t io_cbfn;		/*  IO completion handler    */ +	struct bfa_ioim_sp_s *iosp;	/*  slow-path IO handling    */ +}; + +struct bfa_ioim_sp_s { +	struct bfi_msg_s 	comp_rspmsg;	/*  IO comp f/w response     */ +	u8			*snsinfo;	/*  sense info for this IO   */ +	struct bfa_sgpg_wqe_s sgpg_wqe;	/*  waitq elem for sgpg      */ +	struct bfa_reqq_wait_s reqq_wait;	/*  to wait for room in reqq */ +	bfa_boolean_t		abort_explicit;	/*  aborted by OS            */ +	struct bfa_tskim_s	*tskim;		/*  Relevant TM cmd          */ +}; + +/** + * BFA Task management command (initiator mode) + */ +struct bfa_tskim_s { +	struct list_head          qe; +	bfa_sm_t		sm; +	struct bfa_s            *bfa;        /*  BFA module  */ +	struct bfa_fcpim_mod_s  *fcpim;      /*  parent fcpim module      */ +	struct bfa_itnim_s      *itnim;      /*  i-t-n nexus for this IO  */ +	struct bfad_tskim_s         *dtsk;   /*  driver task mgmt cmnd    */ +	bfa_boolean_t        notify;         /*  notify itnim on TM comp  */ +	lun_t                lun;            /*  lun if applicable        */ +	enum fcp_tm_cmnd        tm_cmnd;     /*  task management command  */ +	u16             tsk_tag;        /*  FWI IO tag               */ +	u8              tsecs;          /*  timeout in seconds       */ +	struct bfa_reqq_wait_s  reqq_wait;   /*  to wait for room in reqq */ +	struct list_head              io_q;    /*  queue of affected IOs    */ +	struct bfa_wc_s             wc;      /*  waiting counter          */ +	struct bfa_cb_qe_s	hcb_qe;      /*  bfa callback qelem       */ +	enum bfi_tskim_status   tsk_status;  /*  TM status                */ +}; + +/** + * BFA i-t-n (initiator mode) + */ +struct bfa_itnim_s { +	struct list_head    qe;		/*  queue element               */ +	bfa_sm_t	  sm;		/*  i-t-n im BFA state machine  */ +	struct bfa_s      *bfa;		/*  bfa instance                */ +	struct bfa_rport_s *rport;	/*  bfa rport                   */ +	void           *ditn;		/*  driver i-t-n structure      */ +	struct bfi_mhdr_s      mhdr;	/*  pre-built mhdr              */ +	u8         msg_no;		/*  itnim/rport firmware handle */ +	u8         reqq;		/*  CQ for requests             */ +	struct bfa_cb_qe_s    hcb_qe;	/*  bfa callback qelem          */ +	struct list_head pending_q;	/*  queue of pending IO requests*/ +	struct list_head io_q;		/*  queue of active IO requests */ +	struct list_head io_cleanup_q;	/*  IO being cleaned up         */ +	struct list_head tsk_q;		/*  queue of active TM commands */ +	struct list_head  delay_comp_q;/*  queue of failed inflight cmds */ +	bfa_boolean_t   seq_rec;	/*  SQER supported              */ +	bfa_boolean_t   is_online;	/*  itnim is ONLINE for IO      */ +	bfa_boolean_t   iotov_active;	/*  IO TOV timer is active	 */ +	struct bfa_wc_s        wc;	/*  waiting counter             */ +	struct bfa_timer_s timer;	/*  pending IO TOV		 */ +	struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq */ +	struct bfa_fcpim_mod_s *fcpim;	/*  fcpim module                */ +	struct bfa_itnim_hal_stats_s	stats; +}; + +#define bfa_itnim_is_online(_itnim) (_itnim)->is_online +#define BFA_FCPIM_MOD(_hal) (&(_hal)->modules.fcpim_mod) +#define BFA_IOIM_FROM_TAG(_fcpim, _iotag)	\ +	(&fcpim->ioim_arr[_iotag]) +#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag)                  \ +    (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) + +/* + * function prototypes + */ +void            bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, +				    struct bfa_meminfo_s *minfo); +void            bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim); +void            bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void            bfa_ioim_good_comp_isr(struct bfa_s *bfa, +					struct bfi_msg_s *msg); +void            bfa_ioim_cleanup(struct bfa_ioim_s *ioim); +void            bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, +					struct bfa_tskim_s *tskim); +void            bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); +void            bfa_ioim_tov(struct bfa_ioim_s *ioim); + +void            bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, +				     struct bfa_meminfo_s *minfo); +void            bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim); +void            bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void            bfa_tskim_iodone(struct bfa_tskim_s *tskim); +void            bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); +void            bfa_tskim_cleanup(struct bfa_tskim_s *tskim); + +void            bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +				      u32 *dm_len); +void            bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, +				     struct bfa_meminfo_s *minfo); +void            bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim); +void            bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); +void            bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void            bfa_itnim_iodone(struct bfa_itnim_s *itnim); +void            bfa_itnim_tskdone(struct bfa_itnim_s *itnim); +bfa_boolean_t   bfa_itnim_hold_io(struct bfa_itnim_s *itnim); + +#endif /* __BFA_FCPIM_PRIV_H__ */ + diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c new file mode 100644 index 00000000000..992435987de --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -0,0 +1,1671 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include <bfi/bfi_pport.h> +#include <cs/bfa_debug.h> +#include <aen/bfa_aen.h> +#include <cs/bfa_plog.h> +#include <aen/bfa_aen_port.h> + +BFA_TRC_FILE(HAL, PPORT); +BFA_MODULE(pport); + +#define bfa_pport_callback(__pport, __event) do {			\ +	if ((__pport)->bfa->fcs) {      \ +		(__pport)->event_cbfn((__pport)->event_cbarg, (__event));      \ +	} else {							\ +		(__pport)->hcb_event = (__event);      \ +		bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe,	\ +		__bfa_cb_port_event, (__pport));      \ +	}								\ +} while (0) + +/* + * The port is considered disabled if corresponding physical port or IOC are + * disabled explicitly + */ +#define BFA_PORT_IS_DISABLED(bfa) \ +	((bfa_pport_is_disabled(bfa) == BFA_TRUE) || \ +	(bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE)) + +/* + * forward declarations + */ +static bfa_boolean_t bfa_pport_send_enable(struct bfa_pport_s *port); +static bfa_boolean_t bfa_pport_send_disable(struct bfa_pport_s *port); +static void     bfa_pport_update_linkinfo(struct bfa_pport_s *pport); +static void     bfa_pport_reset_linkinfo(struct bfa_pport_s *pport); +static void     bfa_pport_set_wwns(struct bfa_pport_s *port); +static void     __bfa_cb_port_event(void *cbarg, bfa_boolean_t complete); +static void     __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete); +static void     __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete); +static void     bfa_port_stats_timeout(void *cbarg); +static void     bfa_port_stats_clr_timeout(void *cbarg); + +/** + *  bfa_pport_private + */ + +/** + * BFA port state machine events + */ +enum bfa_pport_sm_event { +	BFA_PPORT_SM_START = 1,	/*  start port state machine */ +	BFA_PPORT_SM_STOP = 2,	/*  stop port state machine */ +	BFA_PPORT_SM_ENABLE = 3,	/*  enable port */ +	BFA_PPORT_SM_DISABLE = 4,	/*  disable port state machine */ +	BFA_PPORT_SM_FWRSP = 5,	/*  firmware enable/disable rsp */ +	BFA_PPORT_SM_LINKUP = 6,	/*  firmware linkup event */ +	BFA_PPORT_SM_LINKDOWN = 7,	/*  firmware linkup down */ +	BFA_PPORT_SM_QRESUME = 8,	/*  CQ space available */ +	BFA_PPORT_SM_HWFAIL = 9,	/*  IOC h/w failure */ +}; + +static void     bfa_pport_sm_uninit(struct bfa_pport_s *pport, +				    enum bfa_pport_sm_event event); +static void     bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport, +					    enum bfa_pport_sm_event event); +static void     bfa_pport_sm_enabling(struct bfa_pport_s *pport, +				      enum bfa_pport_sm_event event); +static void     bfa_pport_sm_linkdown(struct bfa_pport_s *pport, +				      enum bfa_pport_sm_event event); +static void     bfa_pport_sm_linkup(struct bfa_pport_s *pport, +				    enum bfa_pport_sm_event event); +static void     bfa_pport_sm_disabling(struct bfa_pport_s *pport, +				       enum bfa_pport_sm_event event); +static void     bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport, +					     enum bfa_pport_sm_event event); +static void     bfa_pport_sm_disabled(struct bfa_pport_s *pport, +				      enum bfa_pport_sm_event event); +static void     bfa_pport_sm_stopped(struct bfa_pport_s *pport, +				     enum bfa_pport_sm_event event); +static void     bfa_pport_sm_iocdown(struct bfa_pport_s *pport, +				     enum bfa_pport_sm_event event); +static void     bfa_pport_sm_iocfail(struct bfa_pport_s *pport, +				     enum bfa_pport_sm_event event); + +static struct bfa_sm_table_s hal_pport_sm_table[] = { +	{BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT}, +	{BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT}, +	{BFA_SM(bfa_pport_sm_enabling), BFA_PPORT_ST_ENABLING}, +	{BFA_SM(bfa_pport_sm_linkdown), BFA_PPORT_ST_LINKDOWN}, +	{BFA_SM(bfa_pport_sm_linkup), BFA_PPORT_ST_LINKUP}, +	{BFA_SM(bfa_pport_sm_disabling_qwait), +	 BFA_PPORT_ST_DISABLING_QWAIT}, +	{BFA_SM(bfa_pport_sm_disabling), BFA_PPORT_ST_DISABLING}, +	{BFA_SM(bfa_pport_sm_disabled), BFA_PPORT_ST_DISABLED}, +	{BFA_SM(bfa_pport_sm_stopped), BFA_PPORT_ST_STOPPED}, +	{BFA_SM(bfa_pport_sm_iocdown), BFA_PPORT_ST_IOCDOWN}, +	{BFA_SM(bfa_pport_sm_iocfail), BFA_PPORT_ST_IOCDOWN}, +}; + +static void +bfa_pport_aen_post(struct bfa_pport_s *pport, enum bfa_port_aen_event event) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = pport->bfa->logm; +	wwn_t           pwwn = pport->pwwn; +	char            pwwn_ptr[BFA_STRING_32]; +	struct bfa_ioc_attr_s ioc_attr; + +	wwn2str(pwwn_ptr, pwwn); +	switch (event) { +	case BFA_PORT_AEN_ONLINE: +		bfa_log(logmod, BFA_AEN_PORT_ONLINE, pwwn_ptr); +		break; +	case BFA_PORT_AEN_OFFLINE: +		bfa_log(logmod, BFA_AEN_PORT_OFFLINE, pwwn_ptr); +		break; +	case BFA_PORT_AEN_ENABLE: +		bfa_log(logmod, BFA_AEN_PORT_ENABLE, pwwn_ptr); +		break; +	case BFA_PORT_AEN_DISABLE: +		bfa_log(logmod, BFA_AEN_PORT_DISABLE, pwwn_ptr); +		break; +	case BFA_PORT_AEN_DISCONNECT: +		bfa_log(logmod, BFA_AEN_PORT_DISCONNECT, pwwn_ptr); +		break; +	case BFA_PORT_AEN_QOS_NEG: +		bfa_log(logmod, BFA_AEN_PORT_QOS_NEG, pwwn_ptr); +		break; +	default: +		break; +	} + +	bfa_ioc_get_attr(&pport->bfa->ioc, &ioc_attr); +	aen_data.port.ioc_type = ioc_attr.ioc_type; +	aen_data.port.pwwn = pwwn; +} + +static void +bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_START: +		/** +		 * Start event after IOC is configured and BFA is started. +		 */ +		if (bfa_pport_send_enable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait); +		break; + +	case BFA_PPORT_SM_ENABLE: +		/** +		 * Port is persistently configured to be in enabled state. Do +		 * not change state. Port enabling is done when START event is +		 * received. +		 */ +		break; + +	case BFA_PPORT_SM_DISABLE: +		/** +		 * If a port is persistently configured to be disabled, the +		 * first event will a port disable request. +		 */ +		bfa_sm_set_state(pport, bfa_pport_sm_disabled); +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport, +			    enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_QRESUME: +		bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		bfa_pport_send_enable(pport); +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_reqq_wcancel(&pport->reqq_wait); +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		break; + +	case BFA_PPORT_SM_ENABLE: +		/** +		 * Already enable is in progress. +		 */ +		break; + +	case BFA_PPORT_SM_DISABLE: +		/** +		 * Just send disable request to firmware when room becomes +		 * available in request queue. +		 */ +		bfa_sm_set_state(pport, bfa_pport_sm_disabled); +		bfa_reqq_wcancel(&pport->reqq_wait); +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE); +		break; + +	case BFA_PPORT_SM_LINKUP: +	case BFA_PPORT_SM_LINKDOWN: +		/** +		 * Possible to get link events when doing back-to-back +		 * enable/disables. +		 */ +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_reqq_wcancel(&pport->reqq_wait); +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_enabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_FWRSP: +	case BFA_PPORT_SM_LINKDOWN: +		bfa_sm_set_state(pport, bfa_pport_sm_linkdown); +		break; + +	case BFA_PPORT_SM_LINKUP: +		bfa_pport_update_linkinfo(pport); +		bfa_sm_set_state(pport, bfa_pport_sm_linkup); + +		bfa_assert(pport->event_cbfn); +		bfa_pport_callback(pport, BFA_PPORT_LINKUP); +		break; + +	case BFA_PPORT_SM_ENABLE: +		/** +		 * Already being enabled. +		 */ +		break; + +	case BFA_PPORT_SM_DISABLE: +		if (bfa_pport_send_disable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_disabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait); + +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE); +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_linkdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_LINKUP: +		bfa_pport_update_linkinfo(pport); +		bfa_sm_set_state(pport, bfa_pport_sm_linkup); +		bfa_assert(pport->event_cbfn); +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup"); +		bfa_pport_callback(pport, BFA_PPORT_LINKUP); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_ONLINE); +		/** +		 * If QoS is enabled and it is not online, +		 * Send a separate event. +		 */ +		if ((pport->cfg.qos_enabled) +		    && (bfa_os_ntohl(pport->qos_attr.state) != BFA_QOS_ONLINE)) +			bfa_pport_aen_post(pport, BFA_PORT_AEN_QOS_NEG); + +		break; + +	case BFA_PPORT_SM_LINKDOWN: +		/** +		 * Possible to get link down event. +		 */ +		break; + +	case BFA_PPORT_SM_ENABLE: +		/** +		 * Already enabled. +		 */ +		break; + +	case BFA_PPORT_SM_DISABLE: +		if (bfa_pport_send_disable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_disabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait); + +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE); +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_ENABLE: +		/** +		 * Already enabled. +		 */ +		break; + +	case BFA_PPORT_SM_DISABLE: +		if (bfa_pport_send_disable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_disabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait); + +		bfa_pport_reset_linkinfo(pport); +		bfa_pport_callback(pport, BFA_PPORT_LINKDOWN); +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE); +		break; + +	case BFA_PPORT_SM_LINKDOWN: +		bfa_sm_set_state(pport, bfa_pport_sm_linkdown); +		bfa_pport_reset_linkinfo(pport); +		bfa_pport_callback(pport, BFA_PPORT_LINKDOWN); +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown"); +		if (BFA_PORT_IS_DISABLED(pport->bfa)) { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE); +		} else { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT); +		} +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		bfa_pport_reset_linkinfo(pport); +		if (BFA_PORT_IS_DISABLED(pport->bfa)) { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE); +		} else { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT); +		} +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		bfa_pport_reset_linkinfo(pport); +		bfa_pport_callback(pport, BFA_PPORT_LINKDOWN); +		if (BFA_PORT_IS_DISABLED(pport->bfa)) { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE); +		} else { +			bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT); +		} +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport, +			     enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_QRESUME: +		bfa_sm_set_state(pport, bfa_pport_sm_disabling); +		bfa_pport_send_disable(pport); +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		bfa_reqq_wcancel(&pport->reqq_wait); +		break; + +	case BFA_PPORT_SM_DISABLE: +		/** +		 * Already being disabled. +		 */ +		break; + +	case BFA_PPORT_SM_LINKUP: +	case BFA_PPORT_SM_LINKDOWN: +		/** +		 * Possible to get link events when doing back-to-back +		 * enable/disables. +		 */ +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocfail); +		bfa_reqq_wcancel(&pport->reqq_wait); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_disabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_FWRSP: +		bfa_sm_set_state(pport, bfa_pport_sm_disabled); +		break; + +	case BFA_PPORT_SM_DISABLE: +		/** +		 * Already being disabled. +		 */ +		break; + +	case BFA_PPORT_SM_ENABLE: +		if (bfa_pport_send_enable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait); + +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE); +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		break; + +	case BFA_PPORT_SM_LINKUP: +	case BFA_PPORT_SM_LINKDOWN: +		/** +		 * Possible to get link events when doing back-to-back +		 * enable/disables. +		 */ +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocfail); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_disabled(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_START: +		/** +		 * Ignore start event for a port that is disabled. +		 */ +		break; + +	case BFA_PPORT_SM_STOP: +		bfa_sm_set_state(pport, bfa_pport_sm_stopped); +		break; + +	case BFA_PPORT_SM_ENABLE: +		if (bfa_pport_send_enable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait); + +		bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL, +			     BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); +		bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE); +		break; + +	case BFA_PPORT_SM_DISABLE: +		/** +		 * Already disabled. +		 */ +		break; + +	case BFA_PPORT_SM_HWFAIL: +		bfa_sm_set_state(pport, bfa_pport_sm_iocfail); +		break; + +	default: +		bfa_sm_fault(pport->bfa, event); +	} +} + +static void +bfa_pport_sm_stopped(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_START: +		if (bfa_pport_send_enable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait); +		break; + +	default: +		/** +		 * Ignore all other events. +		 */ +		; +	} +} + +/** + * Port is enabled. IOC is down/failed. + */ +static void +bfa_pport_sm_iocdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_START: +		if (bfa_pport_send_enable(pport)) +			bfa_sm_set_state(pport, bfa_pport_sm_enabling); +		else +			bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait); +		break; + +	default: +		/** +		 * Ignore all events. +		 */ +		; +	} +} + +/** + * Port is disabled. IOC is down/failed. + */ +static void +bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event) +{ +	bfa_trc(pport->bfa, event); + +	switch (event) { +	case BFA_PPORT_SM_START: +		bfa_sm_set_state(pport, bfa_pport_sm_disabled); +		break; + +	case BFA_PPORT_SM_ENABLE: +		bfa_sm_set_state(pport, bfa_pport_sm_iocdown); +		break; + +	default: +		/** +		 * Ignore all events. +		 */ +		; +	} +} + + + +/** + *  bfa_pport_private + */ + +static void +__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_pport_s *pport = cbarg; + +	if (complete) +		pport->event_cbfn(pport->event_cbarg, pport->hcb_event); +} + +#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), \ +							BFA_CACHELINE_SZ)) + +static void +bfa_pport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, +		  u32 *dm_len) +{ +	*dm_len += PPORT_STATS_DMA_SZ; +} + +static void +bfa_pport_qresume(void *cbarg) +{ +	struct bfa_pport_s *port = cbarg; + +	bfa_sm_send_event(port, BFA_PPORT_SM_QRESUME); +} + +static void +bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo) +{ +	u8        *dm_kva; +	u64        dm_pa; + +	dm_kva = bfa_meminfo_dma_virt(meminfo); +	dm_pa = bfa_meminfo_dma_phys(meminfo); + +	pport->stats_kva = dm_kva; +	pport->stats_pa = dm_pa; +	pport->stats = (union bfa_pport_stats_u *)dm_kva; + +	dm_kva += PPORT_STATS_DMA_SZ; +	dm_pa += PPORT_STATS_DMA_SZ; + +	bfa_meminfo_dma_virt(meminfo) = dm_kva; +	bfa_meminfo_dma_phys(meminfo) = dm_pa; +} + +/** + * Memory initialization. + */ +static void +bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		 struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); +	struct bfa_pport_cfg_s *port_cfg = &pport->cfg; + +	bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s)); +	pport->bfa = bfa; + +	bfa_pport_mem_claim(pport, meminfo); + +	bfa_sm_set_state(pport, bfa_pport_sm_uninit); + +	/** +	 * initialize and set default configuration +	 */ +	port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P; +	port_cfg->speed = BFA_PPORT_SPEED_AUTO; +	port_cfg->trunked = BFA_FALSE; +	port_cfg->maxfrsize = 0; + +	port_cfg->trl_def_speed = BFA_PPORT_SPEED_1GBPS; + +	bfa_reqq_winit(&pport->reqq_wait, bfa_pport_qresume, pport); +} + +static void +bfa_pport_initdone(struct bfa_s *bfa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	/** +	 * Initialize port attributes from IOC hardware data. +	 */ +	bfa_pport_set_wwns(pport); +	if (pport->cfg.maxfrsize == 0) +		pport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc); +	pport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); +	pport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); + +	bfa_assert(pport->cfg.maxfrsize); +	bfa_assert(pport->cfg.rx_bbcredit); +	bfa_assert(pport->speed_sup); +} + +static void +bfa_pport_detach(struct bfa_s *bfa) +{ +} + +/** + * Called when IOC is ready. + */ +static void +bfa_pport_start(struct bfa_s *bfa) +{ +	bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_START); +} + +/** + * Called before IOC is stopped. + */ +static void +bfa_pport_stop(struct bfa_s *bfa) +{ +	bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_STOP); +} + +/** + * Called when IOC failure is detected. + */ +static void +bfa_pport_iocdisable(struct bfa_s *bfa) +{ +	bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_HWFAIL); +} + +static void +bfa_pport_update_linkinfo(struct bfa_pport_s *pport) +{ +	struct bfi_pport_event_s *pevent = pport->event_arg.i2hmsg.event; + +	pport->speed = pevent->link_state.speed; +	pport->topology = pevent->link_state.topology; + +	if (pport->topology == BFA_PPORT_TOPOLOGY_LOOP) +		pport->myalpa = pevent->link_state.tl.loop_info.myalpa; + +	/* +	 * QoS Details +	 */ +	bfa_os_assign(pport->qos_attr, pevent->link_state.qos_attr); +	bfa_os_assign(pport->qos_vc_attr, pevent->link_state.qos_vc_attr); + +	bfa_trc(pport->bfa, pport->speed); +	bfa_trc(pport->bfa, pport->topology); +} + +static void +bfa_pport_reset_linkinfo(struct bfa_pport_s *pport) +{ +	pport->speed = BFA_PPORT_SPEED_UNKNOWN; +	pport->topology = BFA_PPORT_TOPOLOGY_NONE; +} + +/** + * Send port enable message to firmware. + */ +static          bfa_boolean_t +bfa_pport_send_enable(struct bfa_pport_s *port) +{ +	struct bfi_pport_enable_req_s *m; + +	/** +	 * Increment message tag before queue check, so that responses to old +	 * requests are discarded. +	 */ +	port->msgtag++; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); +	if (!m) { +		bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_ENABLE_REQ, +		    bfa_lpuid(port->bfa)); +	m->nwwn = port->nwwn; +	m->pwwn = port->pwwn; +	m->port_cfg = port->cfg; +	m->msgtag = port->msgtag; +	m->port_cfg.maxfrsize = bfa_os_htons(port->cfg.maxfrsize); +	bfa_dma_be_addr_set(m->stats_dma_addr, port->stats_pa); +	bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_lo); +	bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_hi); + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); +	return BFA_TRUE; +} + +/** + * Send port disable message to firmware. + */ +static          bfa_boolean_t +bfa_pport_send_disable(struct bfa_pport_s *port) +{ +	bfi_pport_disable_req_t *m; + +	/** +	 * Increment message tag before queue check, so that responses to old +	 * requests are discarded. +	 */ +	port->msgtag++; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); +	if (!m) { +		bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_DISABLE_REQ, +		    bfa_lpuid(port->bfa)); +	m->msgtag = port->msgtag; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); + +	return BFA_TRUE; +} + +static void +bfa_pport_set_wwns(struct bfa_pport_s *port) +{ +	port->pwwn = bfa_ioc_get_pwwn(&port->bfa->ioc); +	port->nwwn = bfa_ioc_get_nwwn(&port->bfa->ioc); + +	bfa_trc(port->bfa, port->pwwn); +	bfa_trc(port->bfa, port->nwwn); +} + +static void +bfa_port_send_txcredit(void *port_cbarg) +{ + +	struct bfa_pport_s *port = port_cbarg; +	struct bfi_pport_set_svc_params_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); +	if (!m) { +		bfa_trc(port->bfa, port->cfg.tx_bbcredit); +		return; +	} + +	bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_SET_SVC_PARAMS_REQ, +		    bfa_lpuid(port->bfa)); +	m->tx_bbcredit = bfa_os_htons((u16) port->cfg.tx_bbcredit); + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); +} + + + +/** + *  bfa_pport_public + */ + +/** + * Firmware message handler. + */ +void +bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); +	union bfi_pport_i2h_msg_u i2hmsg; + +	i2hmsg.msg = msg; +	pport->event_arg.i2hmsg = i2hmsg; + +	switch (msg->mhdr.msg_id) { +	case BFI_PPORT_I2H_ENABLE_RSP: +		if (pport->msgtag == i2hmsg.enable_rsp->msgtag) +			bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP); +		break; + +	case BFI_PPORT_I2H_DISABLE_RSP: +		if (pport->msgtag == i2hmsg.enable_rsp->msgtag) +			bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP); +		break; + +	case BFI_PPORT_I2H_EVENT: +		switch (i2hmsg.event->link_state.linkstate) { +		case BFA_PPORT_LINKUP: +			bfa_sm_send_event(pport, BFA_PPORT_SM_LINKUP); +			break; +		case BFA_PPORT_LINKDOWN: +			bfa_sm_send_event(pport, BFA_PPORT_SM_LINKDOWN); +			break; +		case BFA_PPORT_TRUNK_LINKDOWN: +			/** todo: event notification */ +			break; +		} +		break; + +	case BFI_PPORT_I2H_GET_STATS_RSP: +	case BFI_PPORT_I2H_GET_QOS_STATS_RSP: +		/* +		 * check for timer pop before processing the rsp +		 */ +		if (pport->stats_busy == BFA_FALSE +		    || pport->stats_status == BFA_STATUS_ETIMER) +			break; + +		bfa_timer_stop(&pport->timer); +		pport->stats_status = i2hmsg.getstats_rsp->status; +		bfa_cb_queue(pport->bfa, &pport->hcb_qe, __bfa_cb_port_stats, +			     pport); +		break; +	case BFI_PPORT_I2H_CLEAR_STATS_RSP: +	case BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP: +		/* +		 * check for timer pop before processing the rsp +		 */ +		if (pport->stats_busy == BFA_FALSE +		    || pport->stats_status == BFA_STATUS_ETIMER) +			break; + +		bfa_timer_stop(&pport->timer); +		pport->stats_status = BFA_STATUS_OK; +		bfa_cb_queue(pport->bfa, &pport->hcb_qe, +			     __bfa_cb_port_stats_clr, pport); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  bfa_pport_api + */ + +/** + * Registered callback for port events. + */ +void +bfa_pport_event_register(struct bfa_s *bfa, +			 void (*cbfn) (void *cbarg, bfa_pport_event_t event), +			 void *cbarg) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	pport->event_cbfn = cbfn; +	pport->event_cbarg = cbarg; +} + +bfa_status_t +bfa_pport_enable(struct bfa_s *bfa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	if (pport->diag_busy) +		return (BFA_STATUS_DIAG_BUSY); +	else if (bfa_sm_cmp_state +		 (BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait)) +		return (BFA_STATUS_DEVBUSY); + +	bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE); +	return BFA_STATUS_OK; +} + +bfa_status_t +bfa_pport_disable(struct bfa_s *bfa) +{ +	bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_DISABLE); +	return BFA_STATUS_OK; +} + +/** + * Configure port speed. + */ +bfa_status_t +bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, speed); + +	if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > pport->speed_sup)) { +		bfa_trc(bfa, pport->speed_sup); +		return BFA_STATUS_UNSUPP_SPEED; +	} + +	pport->cfg.speed = speed; + +	return (BFA_STATUS_OK); +} + +/** + * Get current speed. + */ +enum bfa_pport_speed +bfa_pport_get_speed(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->speed; +} + +/** + * Configure port topology. + */ +bfa_status_t +bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, topology); +	bfa_trc(bfa, pport->cfg.topology); + +	switch (topology) { +	case BFA_PPORT_TOPOLOGY_P2P: +	case BFA_PPORT_TOPOLOGY_LOOP: +	case BFA_PPORT_TOPOLOGY_AUTO: +		break; + +	default: +		return BFA_STATUS_EINVAL; +	} + +	pport->cfg.topology = topology; +	return (BFA_STATUS_OK); +} + +/** + * Get current topology. + */ +enum bfa_pport_topology +bfa_pport_get_topology(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->topology; +} + +bfa_status_t +bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, alpa); +	bfa_trc(bfa, pport->cfg.cfg_hardalpa); +	bfa_trc(bfa, pport->cfg.hardalpa); + +	pport->cfg.cfg_hardalpa = BFA_TRUE; +	pport->cfg.hardalpa = alpa; + +	return (BFA_STATUS_OK); +} + +bfa_status_t +bfa_pport_clr_hardalpa(struct bfa_s *bfa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, pport->cfg.cfg_hardalpa); +	bfa_trc(bfa, pport->cfg.hardalpa); + +	pport->cfg.cfg_hardalpa = BFA_FALSE; +	return (BFA_STATUS_OK); +} + +bfa_boolean_t +bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	*alpa = port->cfg.hardalpa; +	return port->cfg.cfg_hardalpa; +} + +u8 +bfa_pport_get_myalpa(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->myalpa; +} + +bfa_status_t +bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, maxfrsize); +	bfa_trc(bfa, pport->cfg.maxfrsize); + +	/* +	 * with in range +	 */ +	if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ)) +		return (BFA_STATUS_INVLD_DFSZ); + +	/* +	 * power of 2, if not the max frame size of 2112 +	 */ +	if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1))) +		return (BFA_STATUS_INVLD_DFSZ); + +	pport->cfg.maxfrsize = maxfrsize; +	return (BFA_STATUS_OK); +} + +u16 +bfa_pport_get_maxfrsize(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->cfg.maxfrsize; +} + +u32 +bfa_pport_mypid(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->mypid; +} + +u8 +bfa_pport_get_rx_bbcredit(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return port->cfg.rx_bbcredit; +} + +void +bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	port->cfg.tx_bbcredit = (u8) tx_bbcredit; +	bfa_port_send_txcredit(port); +} + +/** + * Get port attributes. + */ + +wwn_t +bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); +	if (node) +		return pport->nwwn; +	else +		return pport->pwwn; +} + +void +bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s)); + +	attr->nwwn = pport->nwwn; +	attr->pwwn = pport->pwwn; + +	bfa_os_memcpy(&attr->pport_cfg, &pport->cfg, +		      sizeof(struct bfa_pport_cfg_s)); +	/* +	 * speed attributes +	 */ +	attr->pport_cfg.speed = pport->cfg.speed; +	attr->speed_supported = pport->speed_sup; +	attr->speed = pport->speed; +	attr->cos_supported = FC_CLASS_3; + +	/* +	 * topology attributes +	 */ +	attr->pport_cfg.topology = pport->cfg.topology; +	attr->topology = pport->topology; + +	/* +	 * beacon attributes +	 */ +	attr->beacon = pport->beacon; +	attr->link_e2e_beacon = pport->link_e2e_beacon; +	attr->plog_enabled = bfa_plog_get_setting(pport->bfa->plog); + +	attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); +	attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); +	attr->port_state = bfa_sm_to_state(hal_pport_sm_table, pport->sm); +	if (bfa_ioc_is_disabled(&pport->bfa->ioc)) +		attr->port_state = BFA_PPORT_ST_IOCDIS; +	else if (bfa_ioc_fw_mismatch(&pport->bfa->ioc)) +		attr->port_state = BFA_PPORT_ST_FWMISMATCH; +} + +static void +bfa_port_stats_query(void *cbarg) +{ +	struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg; +	bfi_pport_get_stats_req_t *msg; + +	msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); + +	if (!msg) { +		port->stats_qfull = BFA_TRUE; +		bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_query, +			       port); +		bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait); +		return; +	} +	port->stats_qfull = BFA_FALSE; + +	bfa_os_memset(msg, 0, sizeof(bfi_pport_get_stats_req_t)); +	bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_GET_STATS_REQ, +		    bfa_lpuid(port->bfa)); +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); + +	return; +} + +static void +bfa_port_stats_clear(void *cbarg) +{ +	struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg; +	bfi_pport_clear_stats_req_t *msg; + +	msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); + +	if (!msg) { +		port->stats_qfull = BFA_TRUE; +		bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_clear, +			       port); +		bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait); +		return; +	} +	port->stats_qfull = BFA_FALSE; + +	bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_stats_req_t)); +	bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_STATS_REQ, +		    bfa_lpuid(port->bfa)); +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); +	return; +} + +static void +bfa_port_qos_stats_clear(void *cbarg) +{ +	struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg; +	bfi_pport_clear_qos_stats_req_t *msg; + +	msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT); + +	if (!msg) { +		port->stats_qfull = BFA_TRUE; +		bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_qos_stats_clear, +			       port); +		bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait); +		return; +	} +	port->stats_qfull = BFA_FALSE; + +	bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_qos_stats_req_t)); +	bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ, +		    bfa_lpuid(port->bfa)); +	bfa_reqq_produce(port->bfa, BFA_REQQ_PORT); +	return; +} + +static void +bfa_pport_stats_swap(union bfa_pport_stats_u *d, union bfa_pport_stats_u *s) +{ +	u32       *dip = (u32 *) d; +	u32       *sip = (u32 *) s; +	int             i; + +	/* +	 * Do 64 bit fields swap first +	 */ +	for (i = 0; +	     i < +	     ((sizeof(union bfa_pport_stats_u) - +	       sizeof(struct bfa_qos_stats_s)) / sizeof(u32)); i = i + 2) { +#ifdef __BIGENDIAN +		dip[i] = bfa_os_ntohl(sip[i]); +		dip[i + 1] = bfa_os_ntohl(sip[i + 1]); +#else +		dip[i] = bfa_os_ntohl(sip[i + 1]); +		dip[i + 1] = bfa_os_ntohl(sip[i]); +#endif +	} + +	/* +	 * Now swap the 32 bit fields +	 */ +	for (; i < (sizeof(union bfa_pport_stats_u) / sizeof(u32)); ++i) +		dip[i] = bfa_os_ntohl(sip[i]); +} + +static void +__bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_pport_s *port = cbarg; + +	if (complete) { +		port->stats_cbfn(port->stats_cbarg, port->stats_status); +	} else { +		port->stats_busy = BFA_FALSE; +		port->stats_status = BFA_STATUS_OK; +	} +} + +static void +bfa_port_stats_clr_timeout(void *cbarg) +{ +	struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg; + +	bfa_trc(port->bfa, port->stats_qfull); + +	if (port->stats_qfull) { +		bfa_reqq_wcancel(&port->stats_reqq_wait); +		port->stats_qfull = BFA_FALSE; +	} + +	port->stats_status = BFA_STATUS_ETIMER; +	bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats_clr, port); +} + +static void +__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_pport_s *port = cbarg; + +	if (complete) { +		if (port->stats_status == BFA_STATUS_OK) +			bfa_pport_stats_swap(port->stats_ret, port->stats); +		port->stats_cbfn(port->stats_cbarg, port->stats_status); +	} else { +		port->stats_busy = BFA_FALSE; +		port->stats_status = BFA_STATUS_OK; +	} +} + +static void +bfa_port_stats_timeout(void *cbarg) +{ +	struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg; + +	bfa_trc(port->bfa, port->stats_qfull); + +	if (port->stats_qfull) { +		bfa_reqq_wcancel(&port->stats_reqq_wait); +		port->stats_qfull = BFA_FALSE; +	} + +	port->stats_status = BFA_STATUS_ETIMER; +	bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats, port); +} + +#define BFA_PORT_STATS_TOV	1000 + +/** + * Fetch port attributes. + */ +bfa_status_t +bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats, +		    bfa_cb_pport_t cbfn, void *cbarg) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	if (port->stats_busy) { +		bfa_trc(bfa, port->stats_busy); +		return (BFA_STATUS_DEVBUSY); +	} + +	port->stats_busy = BFA_TRUE; +	port->stats_ret = stats; +	port->stats_cbfn = cbfn; +	port->stats_cbarg = cbarg; + +	bfa_port_stats_query(port); + +	bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port, +			BFA_PORT_STATS_TOV); +	return (BFA_STATUS_OK); +} + +bfa_status_t +bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	if (port->stats_busy) { +		bfa_trc(bfa, port->stats_busy); +		return (BFA_STATUS_DEVBUSY); +	} + +	port->stats_busy = BFA_TRUE; +	port->stats_cbfn = cbfn; +	port->stats_cbarg = cbarg; + +	bfa_port_stats_clear(port); + +	bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port, +			BFA_PORT_STATS_TOV); +	return (BFA_STATUS_OK); +} + +bfa_status_t +bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, bitmap); +	bfa_trc(bfa, pport->cfg.trunked); +	bfa_trc(bfa, pport->cfg.trunk_ports); + +	if (!bitmap || (bitmap & (bitmap - 1))) +		return BFA_STATUS_EINVAL; + +	pport->cfg.trunked = BFA_TRUE; +	pport->cfg.trunk_ports = bitmap; + +	return BFA_STATUS_OK; +} + +void +bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	qos_attr->state = bfa_os_ntohl(pport->qos_attr.state); +	qos_attr->total_bb_cr = bfa_os_ntohl(pport->qos_attr.total_bb_cr); +} + +void +bfa_pport_qos_get_vc_attr(struct bfa_s *bfa, +			  struct bfa_qos_vc_attr_s *qos_vc_attr) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); +	struct bfa_qos_vc_attr_s *bfa_vc_attr = &pport->qos_vc_attr; +	u32        i = 0; + +	qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count); +	qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit); +	qos_vc_attr->elp_opmode_flags = +		bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags); + +	/* +	 * Individual VC info +	 */ +	while (i < qos_vc_attr->total_vc_count) { +		qos_vc_attr->vc_info[i].vc_credit = +			bfa_vc_attr->vc_info[i].vc_credit; +		qos_vc_attr->vc_info[i].borrow_credit = +			bfa_vc_attr->vc_info[i].borrow_credit; +		qos_vc_attr->vc_info[i].priority = +			bfa_vc_attr->vc_info[i].priority; +		++i; +	} +} + +/** + * Fetch QoS Stats. + */ +bfa_status_t +bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats, +			bfa_cb_pport_t cbfn, void *cbarg) +{ +	/* +	 * QoS stats is embedded in port stats +	 */ +	return (bfa_pport_get_stats(bfa, stats, cbfn, cbarg)); +} + +bfa_status_t +bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	if (port->stats_busy) { +		bfa_trc(bfa, port->stats_busy); +		return (BFA_STATUS_DEVBUSY); +	} + +	port->stats_busy = BFA_TRUE; +	port->stats_cbfn = cbfn; +	port->stats_cbarg = cbarg; + +	bfa_port_qos_stats_clear(port); + +	bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port, +			BFA_PORT_STATS_TOV); +	return (BFA_STATUS_OK); +} + +/** + * Fetch port attributes. + */ +bfa_status_t +bfa_pport_trunk_disable(struct bfa_s *bfa) +{ +	return (BFA_STATUS_OK); +} + +bfa_boolean_t +bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	*bitmap = port->cfg.trunk_ports; +	return port->cfg.trunked; +} + +bfa_boolean_t +bfa_pport_is_disabled(struct bfa_s *bfa) +{ +	struct bfa_pport_s *port = BFA_PORT_MOD(bfa); + +	return (bfa_sm_to_state(hal_pport_sm_table, port->sm) == +		BFA_PPORT_ST_DISABLED); + +} + +bfa_boolean_t +bfa_pport_is_ratelim(struct bfa_s *bfa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +return (pport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE); + +} + +void +bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, on_off); +	bfa_trc(bfa, pport->cfg.qos_enabled); + +	pport->cfg.qos_enabled = on_off; +} + +void +bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, on_off); +	bfa_trc(bfa, pport->cfg.ratelimit); + +	pport->cfg.ratelimit = on_off; +	if (pport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN) +		pport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS; +} + +/** + * Configure default minimum ratelim speed + */ +bfa_status_t +bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, speed); + +	/* +	 * Auto and speeds greater than the supported speed, are invalid +	 */ +	if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > pport->speed_sup)) { +		bfa_trc(bfa, pport->speed_sup); +		return BFA_STATUS_UNSUPP_SPEED; +	} + +	pport->cfg.trl_def_speed = speed; + +	return (BFA_STATUS_OK); +} + +/** + * Get default minimum ratelim speed + */ +enum bfa_pport_speed +bfa_pport_get_ratelim_speed(struct bfa_s *bfa) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, pport->cfg.trl_def_speed); +	return (pport->cfg.trl_def_speed); + +} + +void +bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, status); +	bfa_trc(bfa, pport->diag_busy); + +	pport->diag_busy = status; +} + +void +bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon, +		 bfa_boolean_t link_e2e_beacon) +{ +	struct bfa_pport_s *pport = BFA_PORT_MOD(bfa); + +	bfa_trc(bfa, beacon); +	bfa_trc(bfa, link_e2e_beacon); +	bfa_trc(bfa, pport->beacon); +	bfa_trc(bfa, pport->link_e2e_beacon); + +	pport->beacon = beacon; +	pport->link_e2e_beacon = link_e2e_beacon; +} + +bfa_boolean_t +bfa_pport_is_linkup(struct bfa_s *bfa) +{ +	return bfa_sm_cmp_state(BFA_PORT_MOD(bfa), bfa_pport_sm_linkup); +} + + diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c new file mode 100644 index 00000000000..7cb39a306ea --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs.c BFA FCS main + */ + +#include <fcs/bfa_fcs.h> +#include "fcs_port.h" +#include "fcs_uf.h" +#include "fcs_vport.h" +#include "fcs_rport.h" +#include "fcs_fabric.h" +#include "fcs_fcpim.h" +#include "fcs_fcptm.h" +#include "fcbuild.h" +#include "fcs.h" +#include "bfad_drv.h" +#include <fcb/bfa_fcb.h> + +/** + * FCS sub-modules + */ +struct bfa_fcs_mod_s { +	void            (*modinit) (struct bfa_fcs_s *fcs); +	void            (*modexit) (struct bfa_fcs_s *fcs); +}; + +#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } + +static struct bfa_fcs_mod_s fcs_modules[] = { +	BFA_FCS_MODULE(bfa_fcs_pport), +	BFA_FCS_MODULE(bfa_fcs_uf), +	BFA_FCS_MODULE(bfa_fcs_fabric), +	BFA_FCS_MODULE(bfa_fcs_vport), +	BFA_FCS_MODULE(bfa_fcs_rport), +	BFA_FCS_MODULE(bfa_fcs_fcpim), +}; + +/** + *  fcs_api BFA FCS API + */ + +static void +bfa_fcs_exit_comp(void *fcs_cbarg) +{ +	struct bfa_fcs_s *fcs = fcs_cbarg; +	struct bfad_s *bfad = fcs->bfad; + +	complete(&bfad->comp); +} + + + +/** + *  fcs_api BFA FCS API + */ + +/** + * 		FCS instance initialization. + * + * 	param[in]		fcs		FCS instance + * 	param[in]		bfa		BFA instance + * 	param[in]		bfad		BFA driver instance + * + * 	return None + */ +void +bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, +			bfa_boolean_t min_cfg) +{ +	int             i; +	struct bfa_fcs_mod_s  *mod; + +	fcs->bfa = bfa; +	fcs->bfad = bfad; +	fcs->min_cfg = min_cfg; + +	bfa_attach_fcs(bfa); +	fcbuild_init(); + +	for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { +		mod = &fcs_modules[i]; +		mod->modinit(fcs); +	} +} + +/** + * Start FCS operations. + */ +void +bfa_fcs_start(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_fabric_modstart(fcs); +} + +/** + * 		FCS driver details initialization. + * + * 	param[in]		fcs		FCS instance + * 	param[in]		driver_info	Driver Details + * + * 	return None + */ +void +bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, +			struct bfa_fcs_driver_info_s *driver_info) +{ + +	fcs->driver_info = *driver_info; + +	bfa_fcs_fabric_psymb_init(&fcs->fabric); +} + +/** + * 		FCS instance cleanup and exit. + * + * 	param[in]		fcs			FCS instance + * 	return None + */ +void +bfa_fcs_exit(struct bfa_fcs_s *fcs) +{ +	struct bfa_fcs_mod_s  *mod; +	int             nmods, i; + +	bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); + +	nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]); + +	for (i = 0; i < nmods; i++) { +		bfa_wc_up(&fcs->wc); + +		mod = &fcs_modules[i]; +		mod->modexit(fcs); +	} + +	bfa_wc_wait(&fcs->wc); +} + + +void +bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod) +{ +	fcs->trcmod = trcmod; +} + + +void +bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod) +{ +	fcs->logm = logmod; +} + + +void +bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen) +{ +	fcs->aen = aen; +} + +void +bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs) +{ +	bfa_wc_down(&fcs->wc); +} + + diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c new file mode 100644 index 00000000000..8975ed041dc --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -0,0 +1,940 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_port.c BFA FCS port + */ + +#include <fcs/bfa_fcs.h> +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_rport.h> +#include <fcb/bfa_fcb_port.h> +#include <bfa_svc.h> +#include <log/bfa_log_fcs.h> +#include "fcs.h" +#include "fcs_lport.h" +#include "fcs_vport.h" +#include "fcs_rport.h" +#include "fcs_fcxp.h" +#include "fcs_trcmod.h" +#include "lport_priv.h" +#include <aen/bfa_aen_lport.h> + +BFA_TRC_FILE(FCS, PORT); + +/** + * Forward declarations + */ + +static void     bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, +				      enum bfa_lport_aen_event event); +static void     bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs, u8 reason_code, +			u8 reason_code_expl); +static void     bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs, +			struct fc_logi_s *plogi); +static void     bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_deleted(struct bfa_fcs_port_s *port); +static void     bfa_fcs_port_echo(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs, +			struct fc_echo_s *echo, u16 len); +static void     bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs, +			struct fc_rnid_cmd_s *rnid, u16 len); +static void     bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, +			struct fc_rnid_general_topology_data_s *gen_topo_data); + +static struct { +	void            (*init) (struct bfa_fcs_port_s *port); +	void            (*online) (struct bfa_fcs_port_s *port); +	void            (*offline) (struct bfa_fcs_port_s *port); +} __port_action[] = { +	{ +	bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online, +			bfa_fcs_port_unknown_offline}, { +	bfa_fcs_port_fab_init, bfa_fcs_port_fab_online, +			bfa_fcs_port_fab_offline}, { +	bfa_fcs_port_loop_init, bfa_fcs_port_loop_online, +			bfa_fcs_port_loop_offline}, { +bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online, +			bfa_fcs_port_n2n_offline},}; + +/** + *  fcs_port_sm FCS logical port state machine + */ + +enum bfa_fcs_port_event { +	BFA_FCS_PORT_SM_CREATE = 1, +	BFA_FCS_PORT_SM_ONLINE = 2, +	BFA_FCS_PORT_SM_OFFLINE = 3, +	BFA_FCS_PORT_SM_DELETE = 4, +	BFA_FCS_PORT_SM_DELRPORT = 5, +}; + +static void     bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, +				       enum bfa_fcs_port_event event); +static void     bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, +				     enum bfa_fcs_port_event event); +static void     bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, +				       enum bfa_fcs_port_event event); +static void     bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, +					enum bfa_fcs_port_event event); +static void     bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, +					 enum bfa_fcs_port_event event); + +static void +bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port, +			enum bfa_fcs_port_event event) +{ +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case BFA_FCS_PORT_SM_CREATE: +		bfa_sm_set_state(port, bfa_fcs_port_sm_init); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) +{ +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case BFA_FCS_PORT_SM_ONLINE: +		bfa_sm_set_state(port, bfa_fcs_port_sm_online); +		bfa_fcs_port_online_actions(port); +		break; + +	case BFA_FCS_PORT_SM_DELETE: +		bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); +		bfa_fcs_port_deleted(port); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port, +			enum bfa_fcs_port_event event) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe, *qen; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case BFA_FCS_PORT_SM_OFFLINE: +		bfa_sm_set_state(port, bfa_fcs_port_sm_offline); +		bfa_fcs_port_offline_actions(port); +		break; + +	case BFA_FCS_PORT_SM_DELETE: + +		__port_action[port->fabric->fab_type].offline(port); + +		if (port->num_rports == 0) { +			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); +			bfa_fcs_port_deleted(port); +		} else { +			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); +			list_for_each_safe(qe, qen, &port->rport_q) { +				rport = (struct bfa_fcs_rport_s *)qe; +				bfa_fcs_rport_delete(rport); +			} +		} +		break; + +	case BFA_FCS_PORT_SM_DELRPORT: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port, +			enum bfa_fcs_port_event event) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe, *qen; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case BFA_FCS_PORT_SM_ONLINE: +		bfa_sm_set_state(port, bfa_fcs_port_sm_online); +		bfa_fcs_port_online_actions(port); +		break; + +	case BFA_FCS_PORT_SM_DELETE: +		if (port->num_rports == 0) { +			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); +			bfa_fcs_port_deleted(port); +		} else { +			bfa_sm_set_state(port, bfa_fcs_port_sm_deleting); +			list_for_each_safe(qe, qen, &port->rport_q) { +				rport = (struct bfa_fcs_rport_s *)qe; +				bfa_fcs_rport_delete(rport); +			} +		} +		break; + +	case BFA_FCS_PORT_SM_DELRPORT: +	case BFA_FCS_PORT_SM_OFFLINE: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port, +			 enum bfa_fcs_port_event event) +{ +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case BFA_FCS_PORT_SM_DELRPORT: +		if (port->num_rports == 0) { +			bfa_sm_set_state(port, bfa_fcs_port_sm_uninit); +			bfa_fcs_port_deleted(port); +		} +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  fcs_port_pvt + */ + +/** + * Send AEN notification + */ +static void +bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port, +		      enum bfa_lport_aen_event event) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = port->fcs->logm; +	enum bfa_port_role role = port->port_cfg.roles; +	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(port); +	char            lpwwn_ptr[BFA_STRING_32]; +	char           *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = +		{ "Initiator", "Target", "IPFC" }; + +	wwn2str(lpwwn_ptr, lpwwn); + +	bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); + +	switch (event) { +	case BFA_LPORT_AEN_ONLINE: +		bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_OFFLINE: +		bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_NEW: +		bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_DELETE: +		bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_DISCONNECT: +		bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr, +			role_str[role / 2]); +		break; +	default: +		break; +	} + +	aen_data.lport.vf_id = port->fabric->vf_id; +	aen_data.lport.roles = role; +	aen_data.lport.ppwwn = +		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); +	aen_data.lport.lpwwn = lpwwn; +} + +/* + * Send a LS reject + */ +static void +bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +			 u8 reason_code, u8 reason_code_expl) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	struct bfa_rport_s *bfa_rport = NULL; +	int             len; + +	bfa_trc(port->fcs, rx_fchs->s_id); + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, +			      reason_code, reason_code_expl); + +	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, +		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, +		      FC_MAX_PDUSZ, 0); +} + +/** + * Process incoming plogi from a remote port. + */ +static void +bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +			struct fc_logi_s *plogi) +{ +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, rx_fchs->d_id); +	bfa_trc(port->fcs, rx_fchs->s_id); + +	/* +	 * If min cfg mode is enabled, drop any incoming PLOGIs +	 */ +	if (__fcs_min_cfg(port->fcs)) { +		bfa_trc(port->fcs, rx_fchs->s_id); +		return; +	} + +	if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) { +		bfa_trc(port->fcs, rx_fchs->s_id); +		/* +		 * send a LS reject +		 */ +		bfa_fcs_port_send_ls_rjt(port, rx_fchs, +					 FC_LS_RJT_RSN_PROTOCOL_ERROR, +					 FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); +		return; +	} + +	/** +* Direct Attach P2P mode : verify address assigned by the r-port. +	 */ +	if ((!bfa_fcs_fabric_is_switched(port->fabric)) +	    && +	    (memcmp +	     ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name, +	      sizeof(wwn_t)) < 0)) { +		if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) { +			/* +			 * Address assigned to us cannot be a WKA +			 */ +			bfa_fcs_port_send_ls_rjt(port, rx_fchs, +					FC_LS_RJT_RSN_PROTOCOL_ERROR, +					FC_LS_RJT_EXP_INVALID_NPORT_ID); +			return; +		} +		port->pid = rx_fchs->d_id; +	} + +	/** +	 * First, check if we know the device by pwwn. +	 */ +	rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name); +	if (rport) { +		/** +		 * Direct Attach P2P mode: handle address assigned by the rport. +		 */ +		if ((!bfa_fcs_fabric_is_switched(port->fabric)) +		    && +		    (memcmp +		     ((void *)&bfa_fcs_port_get_pwwn(port), +		      (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { +			port->pid = rx_fchs->d_id; +			rport->pid = rx_fchs->s_id; +		} +		bfa_fcs_rport_plogi(rport, rx_fchs, plogi); +		return; +	} + +	/** +	 * Next, lookup rport by PID. +	 */ +	rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id); +	if (!rport) { +		/** +		 * Inbound PLOGI from a new device. +		 */ +		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); +		return; +	} + +	/** +	 * Rport is known only by PID. +	 */ +	if (rport->pwwn) { +		/** +		 * This is a different device with the same pid. Old device +		 * disappeared. Send implicit LOGO to old device. +		 */ +		bfa_assert(rport->pwwn != plogi->port_name); +		bfa_fcs_rport_logo_imp(rport); + +		/** +		 * Inbound PLOGI from a new device (with old PID). +		 */ +		bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); +		return; +	} + +	/** +	 * PLOGI crossing each other. +	 */ +	bfa_assert(rport->pwwn == WWN_NULL); +	bfa_fcs_rport_plogi(rport, rx_fchs, plogi); +} + +/* + * Process incoming ECHO. + * Since it does not require a login, it is processed here. + */ +static void +bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +			struct fc_echo_s *echo, u16 rx_len) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	struct bfa_rport_s *bfa_rport = NULL; +	int             len, pyld_len; + +	bfa_trc(port->fcs, rx_fchs->s_id); +	bfa_trc(port->fcs, rx_fchs->d_id); +	bfa_trc(port->fcs, rx_len); + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); + +	/* +	 * Copy the payload (if any) from the echo frame +	 */ +	pyld_len = rx_len - sizeof(struct fchs_s); +	bfa_trc(port->fcs, pyld_len); + +	if (pyld_len > len) +		memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) + +		       sizeof(struct fc_echo_s), (echo + 1), +		       (pyld_len - sizeof(struct fc_echo_s))); + +	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, +		      BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, +		      FC_MAX_PDUSZ, 0); +} + +/* + * Process incoming RNID. + * Since it does not require a login, it is processed here. + */ +static void +bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +			struct fc_rnid_cmd_s *rnid, u16 rx_len) +{ +	struct fc_rnid_common_id_data_s common_id_data; +	struct fc_rnid_general_topology_data_s gen_topo_data; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	struct bfa_rport_s *bfa_rport = NULL; +	u16        len; +	u32        data_format; + +	bfa_trc(port->fcs, rx_fchs->s_id); +	bfa_trc(port->fcs, rx_fchs->d_id); +	bfa_trc(port->fcs, rx_len); + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	/* +	 * Check Node Indentification Data Format +	 * We only support General Topology Discovery Format. +	 * For any other requested Data Formats, we return Common Node Id Data +	 * only, as per FC-LS. +	 */ +	bfa_trc(port->fcs, rnid->node_id_data_format); +	if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { +		data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY; +		/* +		 * Get General topology data for this port +		 */ +		bfa_fs_port_get_gen_topo_data(port, &gen_topo_data); +	} else { +		data_format = RNID_NODEID_DATA_FORMAT_COMMON; +	} + +	/* +	 * Copy the Node Id Info +	 */ +	common_id_data.port_name = bfa_fcs_port_get_pwwn(port); +	common_id_data.node_name = bfa_fcs_port_get_nwwn(port); + +	len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +				bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, +				data_format, &common_id_data, &gen_topo_data); + +	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, +		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, +		      FC_MAX_PDUSZ, 0); + +	return; +} + +/* + *  Fill out General Topolpgy Discovery Data for RNID ELS. + */ +static void +bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port, +			struct fc_rnid_general_topology_data_s *gen_topo_data) +{ + +	bfa_os_memset(gen_topo_data, 0, +		      sizeof(struct fc_rnid_general_topology_data_s)); + +	gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST); +	gen_topo_data->phy_port_num = 0;	/* @todo */ +	gen_topo_data->num_attached_nodes = bfa_os_htonl(1); +} + +static void +bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port) +{ +	bfa_trc(port->fcs, port->fabric->oper_type); + +	__port_action[port->fabric->fab_type].init(port); +	__port_action[port->fabric->fab_type].online(port); + +	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE); +	bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles, +			port->fabric->vf_drv, (port->vport == NULL) ? +			NULL : port->vport->vport_drv); +} + +static void +bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port) +{ +	struct list_head *qe, *qen; +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, port->fabric->oper_type); + +	__port_action[port->fabric->fab_type].offline(port); + +	if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE) { +		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT); +	} else { +		bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_OFFLINE); +	} +	bfa_fcb_port_offline(port->fcs->bfad, port->port_cfg.roles, +			port->fabric->vf_drv, +			(port->vport == NULL) ? NULL : port->vport->vport_drv); + +	list_for_each_safe(qe, qen, &port->rport_q) { +		rport = (struct bfa_fcs_rport_s *)qe; +		bfa_fcs_rport_offline(rport); +	} +} + +static void +bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port) +{ +	bfa_assert(0); +} + +static void +bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port) +{ +	bfa_assert(0); +} + +static void +bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port) +{ +	bfa_assert(0); +} + +static void +bfa_fcs_port_deleted(struct bfa_fcs_port_s *port) +{ +	bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE); + +	/* +	 * Base port will be deleted by the OS driver +	 */ +	if (port->vport) { +		bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles, +			port->fabric->vf_drv, +			port->vport ? port->vport->vport_drv : NULL); +		bfa_fcs_vport_delete_comp(port->vport); +	} else { +		bfa_fcs_fabric_port_delete_comp(port->fabric); +	} +} + + + +/** + *  fcs_lport_api BFA FCS port API + */ +/** + *   Module initialization + */ +void +bfa_fcs_port_modinit(struct bfa_fcs_s *fcs) +{ + +} + +/** + *   Module cleanup + */ +void +bfa_fcs_port_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} + +/** + * 		Unsolicited frame receive handling. + */ +void +bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, +			u16 len) +{ +	u32        pid = fchs->s_id; +	struct bfa_fcs_rport_s *rport = NULL; +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	bfa_stats(lport, uf_recvs); + +	if (!bfa_fcs_port_is_online(lport)) { +		bfa_stats(lport, uf_recv_drops); +		return; +	} + +	/** +	 * First, handle ELSs that donot require a login. +	 */ +	/* +	 * Handle PLOGI first +	 */ +	if ((fchs->type == FC_TYPE_ELS) && +		(els_cmd->els_code == FC_ELS_PLOGI)) { +		bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); +		return; +	} + +	/* +	 * Handle ECHO separately. +	 */ +	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { +		bfa_fcs_port_echo(lport, fchs, +			(struct fc_echo_s *) els_cmd, len); +		return; +	} + +	/* +	 * Handle RNID separately. +	 */ +	if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { +		bfa_fcs_port_rnid(lport, fchs, +			(struct fc_rnid_cmd_s *) els_cmd, len); +		return; +	} + +	/** +	 * look for a matching remote port ID +	 */ +	rport = bfa_fcs_port_get_rport_by_pid(lport, pid); +	if (rport) { +		bfa_trc(rport->fcs, fchs->s_id); +		bfa_trc(rport->fcs, fchs->d_id); +		bfa_trc(rport->fcs, fchs->type); + +		bfa_fcs_rport_uf_recv(rport, fchs, len); +		return; +	} + +	/** +	 * Only handles ELS frames for now. +	 */ +	if (fchs->type != FC_TYPE_ELS) { +		bfa_trc(lport->fcs, fchs->type); +		bfa_assert(0); +		return; +	} + +	bfa_trc(lport->fcs, els_cmd->els_code); +	if (els_cmd->els_code == FC_ELS_RSCN) { +		bfa_fcs_port_scn_process_rscn(lport, fchs, len); +		return; +	} + +	if (els_cmd->els_code == FC_ELS_LOGO) { +		/** +		 * @todo Handle LOGO frames received. +		 */ +		bfa_trc(lport->fcs, els_cmd->els_code); +		return; +	} + +	if (els_cmd->els_code == FC_ELS_PRLI) { +		/** +		 * @todo Handle PRLI frames received. +		 */ +		bfa_trc(lport->fcs, els_cmd->els_code); +		return; +	} + +	/** +	 * Unhandled ELS frames. Send a LS_RJT. +	 */ +	bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, +				 FC_LS_RJT_EXP_NO_ADDL_INFO); + +} + +/** + *   PID based Lookup for a R-Port in the Port R-Port Queue + */ +struct bfa_fcs_rport_s * +bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe; + +	list_for_each(qe, &port->rport_q) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if (rport->pid == pid) +			return rport; +	} + +	bfa_trc(port->fcs, pid); +	return NULL; +} + +/** + *   PWWN based Lookup for a R-Port in the Port R-Port Queue + */ +struct bfa_fcs_rport_s * +bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe; + +	list_for_each(qe, &port->rport_q) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if (wwn_is_equal(rport->pwwn, pwwn)) +			return rport; +	} + +	bfa_trc(port->fcs, pwwn); +	return (NULL); +} + +/** + *   NWWN based Lookup for a R-Port in the Port R-Port Queue + */ +struct bfa_fcs_rport_s * +bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe; + +	list_for_each(qe, &port->rport_q) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if (wwn_is_equal(rport->nwwn, nwwn)) +			return rport; +	} + +	bfa_trc(port->fcs, nwwn); +	return (NULL); +} + +/** + * Called by rport module when new rports are discovered. + */ +void +bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, +		       struct bfa_fcs_rport_s *rport) +{ +	list_add_tail(&rport->qe, &port->rport_q); +	port->num_rports++; +} + +/** + * Called by rport module to when rports are deleted. + */ +void +bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, +		       struct bfa_fcs_rport_s *rport) +{ +	bfa_assert(bfa_q_is_on_q(&port->rport_q, rport)); +	list_del(&rport->qe); +	port->num_rports--; + +	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT); +} + +/** + * Called by fabric for base port when fabric login is complete. + * Called by vport for virtual ports when FDISC is complete. + */ +void +bfa_fcs_port_online(struct bfa_fcs_port_s *port) +{ +	bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); +} + +/** + * Called by fabric for base port when fabric goes offline. + * Called by vport for virtual ports when virtual port becomes offline. + */ +void +bfa_fcs_port_offline(struct bfa_fcs_port_s *port) +{ +	bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); +} + +/** + * Called by fabric to delete base lport and associated resources. + * + * Called by vport to delete lport and associated resources. Should call + * bfa_fcs_vport_delete_comp() for vports on completion. + */ +void +bfa_fcs_port_delete(struct bfa_fcs_port_s *port) +{ +	bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); +} + +/** + * Called by fabric in private loop topology to process LIP event. + */ +void +bfa_fcs_port_lip(struct bfa_fcs_port_s *port) +{ +} + +/** + * Return TRUE if port is online, else return FALSE + */ +bfa_boolean_t +bfa_fcs_port_is_online(struct bfa_fcs_port_s *port) +{ +	return (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)); +} + +/** + * Logical port initialization of base or virtual port. + * Called by fabric for base port or by vport for virtual ports. + */ +void +bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, +		   u16 vf_id, struct bfa_port_cfg_s *port_cfg, +		   struct bfa_fcs_vport_s *vport) +{ +	lport->fcs = fcs; +	lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); +	bfa_os_assign(lport->port_cfg, *port_cfg); +	lport->vport = vport; +	lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) : +			 bfa_lps_get_tag(lport->fabric->lps); + +	INIT_LIST_HEAD(&lport->rport_q); +	lport->num_rports = 0; + +	lport->bfad_port = +		bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles, +				lport->fabric->vf_drv, +				vport ? vport->vport_drv : NULL); +	bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW); + +	bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit); +	bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); +} + + + +/** + *  fcs_lport_api + */ + +void +bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, +		      struct bfa_port_attr_s *port_attr) +{ +	if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online)) +		port_attr->pid = port->pid; +	else +		port_attr->pid = 0; + +	port_attr->port_cfg = port->port_cfg; + +	if (port->fabric) { +		port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric); +		port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric); +		port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port); +		memcpy(port_attr->fabric_ip_addr, +		       bfa_fcs_port_get_fabric_ipaddr(port), +		       BFA_FCS_FABRIC_IPADDR_SZ); + +		if (port->vport != NULL) +			port_attr->port_type = BFA_PPORT_TYPE_VPORT; + +	} else { +		port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN; +		port_attr->state = BFA_PORT_UNINIT; +	} + +} + + diff --git a/drivers/scsi/bfa/bfa_fcs_port.c b/drivers/scsi/bfa/bfa_fcs_port.c new file mode 100644 index 00000000000..9c4b24e62de --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcs_port.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_pport.c BFA FCS PPORT ( physical port) + */ + +#include <fcs/bfa_fcs.h> +#include <bfa_svc.h> +#include <fcs/bfa_fcs_fabric.h> +#include "fcs_trcmod.h" +#include "fcs.h" +#include "fcs_fabric.h" +#include "fcs_port.h" + +BFA_TRC_FILE(FCS, PPORT); + +static void +bfa_fcs_pport_event_handler(void *cbarg, bfa_pport_event_t event) +{ +	struct bfa_fcs_s      *fcs = cbarg; + +	bfa_trc(fcs, event); + +	switch (event) { +	case BFA_PPORT_LINKUP: +		bfa_fcs_fabric_link_up(&fcs->fabric); +		break; + +	case BFA_PPORT_LINKDOWN: +		bfa_fcs_fabric_link_down(&fcs->fabric); +		break; + +	case BFA_PPORT_TRUNK_LINKDOWN: +		bfa_assert(0); +		break; + +	default: +		bfa_assert(0); +	} +} + +void +bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs) +{ +	bfa_pport_event_register(fcs->bfa, bfa_fcs_pport_event_handler, +				     fcs); +} + +void +bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} diff --git a/drivers/scsi/bfa/bfa_fcs_uf.c b/drivers/scsi/bfa/bfa_fcs_uf.c new file mode 100644 index 00000000000..ad01db6444b --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcs_uf.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_uf.c BFA FCS UF ( Unsolicited Frames) + */ + +#include <fcs/bfa_fcs.h> +#include <bfa_svc.h> +#include <fcs/bfa_fcs_fabric.h> +#include "fcs.h" +#include "fcs_trcmod.h" +#include "fcs_fabric.h" +#include "fcs_uf.h" + +BFA_TRC_FILE(FCS, UF); + +/** + * 		BFA callback for unsolicited frame receive handler. + * + * @param[in]		cbarg		callback arg for receive handler + * @param[in]		uf		unsolicited frame descriptor + * + * @return None + */ +static void +bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) +{ +	struct bfa_fcs_s      *fcs = (struct bfa_fcs_s *) cbarg; +	struct fchs_s         *fchs = bfa_uf_get_frmbuf(uf); +	u16        len = bfa_uf_get_frmlen(uf); +	struct fc_vft_s       *vft; +	struct bfa_fcs_fabric_s *fabric; + +	/** +	 * check for VFT header +	 */ +	if (fchs->routing == FC_RTG_EXT_HDR && +		fchs->cat_info == FC_CAT_VFT_HDR) { +		bfa_stats(fcs, uf.tagged); +		vft = bfa_uf_get_frmbuf(uf); +		if (fcs->port_vfid == vft->vf_id) +			fabric = &fcs->fabric; +		else +			fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id); + +		/** +		 * drop frame if vfid is unknown +		 */ +		if (!fabric) { +			bfa_assert(0); +			bfa_stats(fcs, uf.vfid_unknown); +			bfa_uf_free(uf); +			return; +		} + +		/** +		 * skip vft header +		 */ +		fchs = (struct fchs_s *) (vft + 1); +		len -= sizeof(struct fc_vft_s); + +		bfa_trc(fcs, vft->vf_id); +	} else { +		bfa_stats(fcs, uf.untagged); +		fabric = &fcs->fabric; +	} + +	bfa_trc(fcs, ((u32 *) fchs)[0]); +	bfa_trc(fcs, ((u32 *) fchs)[1]); +	bfa_trc(fcs, ((u32 *) fchs)[2]); +	bfa_trc(fcs, ((u32 *) fchs)[3]); +	bfa_trc(fcs, ((u32 *) fchs)[4]); +	bfa_trc(fcs, ((u32 *) fchs)[5]); +	bfa_trc(fcs, len); + +	bfa_fcs_fabric_uf_recv(fabric, fchs, len); +	bfa_uf_free(uf); +} + +void +bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs) +{ +	bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); +} + +void +bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c new file mode 100644 index 00000000000..4754a0e9006 --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcxp.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfi/bfi_uf.h> +#include <cs/bfa_debug.h> + +BFA_TRC_FILE(HAL, FCXP); +BFA_MODULE(fcxp); + +/** + * forward declarations + */ +static void     __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); +static void     hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, +				 struct bfi_fcxp_send_rsp_s *fcxp_rsp); +static void     hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, +				 struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); +static void	bfa_fcxp_qresume(void *cbarg); +static void	bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, +			       struct bfi_fcxp_send_req_s *send_req); + +/** + *  fcxp_pvt BFA FCXP private functions + */ + +static void +claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ +	u8        *dm_kva = NULL; +	u64        dm_pa; +	u32        buf_pool_sz; + +	dm_kva = bfa_meminfo_dma_virt(mi); +	dm_pa = bfa_meminfo_dma_phys(mi); + +	buf_pool_sz = mod->req_pld_sz * mod->num_fcxps; + +	/* +	 * Initialize the fcxp req payload list +	 */ +	mod->req_pld_list_kva = dm_kva; +	mod->req_pld_list_pa = dm_pa; +	dm_kva += buf_pool_sz; +	dm_pa += buf_pool_sz; +	bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz); + +	/* +	 * Initialize the fcxp rsp payload list +	 */ +	buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps; +	mod->rsp_pld_list_kva = dm_kva; +	mod->rsp_pld_list_pa = dm_pa; +	dm_kva += buf_pool_sz; +	dm_pa += buf_pool_sz; +	bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz); + +	bfa_meminfo_dma_virt(mi) = dm_kva; +	bfa_meminfo_dma_phys(mi) = dm_pa; +} + +static void +claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi) +{ +	u16        i; +	struct bfa_fcxp_s *fcxp; + +	fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi); +	bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); + +	INIT_LIST_HEAD(&mod->fcxp_free_q); +	INIT_LIST_HEAD(&mod->fcxp_active_q); + +	mod->fcxp_list = fcxp; + +	for (i = 0; i < mod->num_fcxps; i++) { +		fcxp->fcxp_mod = mod; +		fcxp->fcxp_tag = i; + +		list_add_tail(&fcxp->qe, &mod->fcxp_free_q); +		bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); +		fcxp->reqq_waiting = BFA_FALSE; + +		fcxp = fcxp + 1; +	} + +	bfa_meminfo_kva(mi) = (void *)fcxp; +} + +static void +bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, +		u32 *dm_len) +{ +	u16        num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs; + +	if (num_fcxp_reqs == 0) +		return; + +	/* +	 * Account for req/rsp payload +	 */ +	*dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; +	if (cfg->drvcfg.min_cfg) +		*dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs; +	else +		*dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs; + +	/* +	 * Account for fcxp structs +	 */ +	*ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs; +} + +static void +bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		    struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + +	bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s)); +	mod->bfa = bfa; +	mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; + +	/** +	 * Initialize FCXP request and response payload sizes. +	 */ +	mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; +	if (!cfg->drvcfg.min_cfg) +		mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; + +	INIT_LIST_HEAD(&mod->wait_q); + +	claim_fcxp_req_rsp_mem(mod, meminfo); +	claim_fcxps_mem(mod, meminfo); +} + +static void +bfa_fcxp_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_start(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_fcxp_iocdisable(struct bfa_s *bfa) +{ +	struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); +	struct bfa_fcxp_s *fcxp; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &mod->fcxp_active_q) { +		fcxp = (struct bfa_fcxp_s *) qe; +		if (fcxp->caller == NULL) { +			fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, +					BFA_STATUS_IOC_FAILURE, 0, 0, NULL); +			bfa_fcxp_free(fcxp); +		} else { +			fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; +			bfa_cb_queue(bfa, &fcxp->hcb_qe, +				      __bfa_fcxp_send_cbfn, fcxp); +		} +	} +} + +static struct bfa_fcxp_s * +bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) +{ +	struct bfa_fcxp_s *fcxp; + +	bfa_q_deq(&fm->fcxp_free_q, &fcxp); + +	if (fcxp) +		list_add_tail(&fcxp->qe, &fm->fcxp_active_q); + +	return (fcxp); +} + +static void +bfa_fcxp_put(struct bfa_fcxp_s *fcxp) +{ +	struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; +	struct bfa_fcxp_wqe_s *wqe; + +	bfa_q_deq(&mod->wait_q, &wqe); +	if (wqe) { +		bfa_trc(mod->bfa, fcxp->fcxp_tag); +		wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); +		return; +	} + +	bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); +	list_del(&fcxp->qe); +	list_add_tail(&fcxp->qe, &mod->fcxp_free_q); +} + +static void +bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, +		       bfa_status_t req_status, u32 rsp_len, +		       u32 resid_len, struct fchs_s *rsp_fchs) +{ +	/**discarded fcxp completion */ +} + +static void +__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_fcxp_s *fcxp = cbarg; + +	if (complete) { +		fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, +				fcxp->rsp_status, fcxp->rsp_len, +				fcxp->residue_len, &fcxp->rsp_fchs); +	} else { +		bfa_fcxp_free(fcxp); +	} +} + +static void +hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) +{ +	struct bfa_fcxp_mod_s	*mod = BFA_FCXP_MOD(bfa); +	struct bfa_fcxp_s 	*fcxp; +	u16		fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag); + +	bfa_trc(bfa, fcxp_tag); + +	fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len); + +	/** +	 * @todo f/w should not set residue to non-0 when everything +	 *       is received. +	 */ +	if (fcxp_rsp->req_status == BFA_STATUS_OK) +		fcxp_rsp->residue_len = 0; +	else +		fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len); + +	fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); + +	bfa_assert(fcxp->send_cbfn != NULL); + +	hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); + +	if (fcxp->send_cbfn != NULL) { +		if (fcxp->caller == NULL) { +			bfa_trc(mod->bfa, fcxp->fcxp_tag); + +			fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, +					fcxp_rsp->req_status, fcxp_rsp->rsp_len, +					fcxp_rsp->residue_len, &fcxp_rsp->fchs); +			/* +			 * fcxp automatically freed on return from the callback +			 */ +			bfa_fcxp_free(fcxp); +		} else { +			bfa_trc(mod->bfa, fcxp->fcxp_tag); +			fcxp->rsp_status = fcxp_rsp->req_status; +			fcxp->rsp_len = fcxp_rsp->rsp_len; +			fcxp->residue_len = fcxp_rsp->residue_len; +			fcxp->rsp_fchs = fcxp_rsp->fchs; + +			bfa_cb_queue(bfa, &fcxp->hcb_qe, +				      __bfa_fcxp_send_cbfn, fcxp); +		} +	} else { +		bfa_trc(bfa, fcxp_tag); +	} +} + +static void +hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa) +{ +	union bfi_addr_u      sga_zero = { {0} }; + +	sge->sg_len = reqlen; +	sge->flags = BFI_SGE_DATA_LAST; +	bfa_dma_addr_set(sge[0].sga, req_pa); +	bfa_sge_to_be(sge); +	sge++; + +	sge->sga = sga_zero; +	sge->sg_len = reqlen; +	sge->flags = BFI_SGE_PGDLEN; +	bfa_sge_to_be(sge); +} + +static void +hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, +		 struct fchs_s *fchs) +{ +	/* +	 * TODO: TX ox_id +	 */ +	if (reqlen > 0) { +		if (fcxp->use_ireqbuf) { +			u32        pld_w0 = +				*((u32 *) BFA_FCXP_REQ_PLD(fcxp)); + +			bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, +				BFA_PL_EID_TX, +				reqlen + sizeof(struct fchs_s), fchs, pld_w0); +		} else { +			bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, +				BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s), +				fchs); +		} +	} else { +		bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, +			       reqlen + sizeof(struct fchs_s), fchs); +	} +} + +static void +hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, +		 struct bfi_fcxp_send_rsp_s *fcxp_rsp) +{ +	if (fcxp_rsp->rsp_len > 0) { +		if (fcxp->use_irspbuf) { +			u32        pld_w0 = +				*((u32 *) BFA_FCXP_RSP_PLD(fcxp)); + +			bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, +					      BFA_PL_EID_RX, +					      (u16) fcxp_rsp->rsp_len, +					      &fcxp_rsp->fchs, pld_w0); +		} else { +			bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, +				       BFA_PL_EID_RX, +				       (u16) fcxp_rsp->rsp_len, +				       &fcxp_rsp->fchs); +		} +	} else { +		bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, +			       (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); +	} +} + +/** + * Handler to resume sending fcxp when space in available in cpe queue. + */ +static void +bfa_fcxp_qresume(void *cbarg) +{ +	struct bfa_fcxp_s		*fcxp = cbarg; +	struct bfa_s			*bfa = fcxp->fcxp_mod->bfa; +	struct bfi_fcxp_send_req_s	*send_req; + +	fcxp->reqq_waiting = BFA_FALSE; +	send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); +	bfa_fcxp_queue(fcxp, send_req); +} + +/** + * Queue fcxp send request to foimrware. + */ +static void +bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) +{ +	struct bfa_s      		*bfa = fcxp->fcxp_mod->bfa; +	struct bfa_fcxp_req_info_s	*reqi = &fcxp->req_info; +	struct bfa_fcxp_rsp_info_s	*rspi = &fcxp->rsp_info; +	struct bfa_rport_s		*rport = reqi->bfa_rport; + +	bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, +			bfa_lpuid(bfa)); + +	send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag); +	if (rport) { +		send_req->rport_fw_hndl = rport->fw_handle; +		send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz); +		if (send_req->max_frmsz == 0) +			send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); +	} else { +		send_req->rport_fw_hndl = 0; +		send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ); +	} + +	send_req->vf_id = bfa_os_htons(reqi->vf_id); +	send_req->lp_tag = reqi->lp_tag; +	send_req->class = reqi->class; +	send_req->rsp_timeout = rspi->rsp_timeout; +	send_req->cts = reqi->cts; +	send_req->fchs = reqi->fchs; + +	send_req->req_len = bfa_os_htonl(reqi->req_tot_len); +	send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen); + +	/* +	 * setup req sgles +	 */ +	if (fcxp->use_ireqbuf == 1) { +		hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len, +					BFA_FCXP_REQ_PLD_PA(fcxp)); +	} else { +		if (fcxp->nreq_sgles > 0) { +			bfa_assert(fcxp->nreq_sgles == 1); +			hal_fcxp_set_local_sges(send_req->req_sge, +						reqi->req_tot_len, +						fcxp->req_sga_cbfn(fcxp->caller, +								   0)); +		} else { +			bfa_assert(reqi->req_tot_len == 0); +			hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); +		} +	} + +	/* +	 * setup rsp sgles +	 */ +	if (fcxp->use_irspbuf == 1) { +		bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ); + +		hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen, +					BFA_FCXP_RSP_PLD_PA(fcxp)); + +	} else { +		if (fcxp->nrsp_sgles > 0) { +			bfa_assert(fcxp->nrsp_sgles == 1); +			hal_fcxp_set_local_sges(send_req->rsp_sge, +						rspi->rsp_maxlen, +						fcxp->rsp_sga_cbfn(fcxp->caller, +								   0)); +		} else { +			bfa_assert(rspi->rsp_maxlen == 0); +			hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0); +		} +	} + +	hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); + +	bfa_reqq_produce(bfa, BFA_REQQ_FCXP); + +	bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); +	bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); +} + + +/** + *  hal_fcxp_api BFA FCXP API + */ + +/** + * Allocate an FCXP instance to send a response or to send a request + * that has a response. Request/response buffers are allocated by caller. + * + * @param[in]	bfa		BFA bfa instance + * @param[in]	nreq_sgles	Number of SG elements required for request + * 				buffer. 0, if fcxp internal buffers are	used. + * 				Use bfa_fcxp_get_reqbuf() to get the + * 				internal req buffer. + * @param[in]	req_sgles	SG elements describing request buffer. Will be + * 				copied in by BFA and hence can be freed on + * 				return from this function. + * @param[in]	get_req_sga	function ptr to be called to get a request SG + * 				Address (given the sge index). + * @param[in]	get_req_sglen	function ptr to be called to get a request SG + * 				len (given the sge index). + * @param[in]	get_rsp_sga	function ptr to be called to get a response SG + * 				Address (given the sge index). + * @param[in]	get_rsp_sglen	function ptr to be called to get a response SG + * 				len (given the sge index). + * + * @return FCXP instance. NULL on failure. + */ +struct bfa_fcxp_s * +bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, +			int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, +			bfa_fcxp_get_sglen_t req_sglen_cbfn, +			bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, +			bfa_fcxp_get_sglen_t rsp_sglen_cbfn) +{ +	struct bfa_fcxp_s *fcxp = NULL; +	u32        nreq_sgpg, nrsp_sgpg; + +	bfa_assert(bfa != NULL); + +	fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); +	if (fcxp == NULL) +		return (NULL); + +	bfa_trc(bfa, fcxp->fcxp_tag); + +	fcxp->caller = caller; + +	if (nreq_sgles == 0) { +		fcxp->use_ireqbuf = 1; +	} else { +		bfa_assert(req_sga_cbfn != NULL); +		bfa_assert(req_sglen_cbfn != NULL); + +		fcxp->use_ireqbuf = 0; +		fcxp->req_sga_cbfn = req_sga_cbfn; +		fcxp->req_sglen_cbfn = req_sglen_cbfn; + +		fcxp->nreq_sgles = nreq_sgles; + +		/* +		 * alloc required sgpgs +		 */ +		if (nreq_sgles > BFI_SGE_INLINE) { +			nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles); + +			if (bfa_sgpg_malloc +			    (bfa, &fcxp->req_sgpg_q, nreq_sgpg) +			    != BFA_STATUS_OK) { +				/* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe, +				nreq_sgpg); */ +				/* +				 * TODO +				 */ +			} +		} +	} + +	if (nrsp_sgles == 0) { +		fcxp->use_irspbuf = 1; +	} else { +		bfa_assert(rsp_sga_cbfn != NULL); +		bfa_assert(rsp_sglen_cbfn != NULL); + +		fcxp->use_irspbuf = 0; +		fcxp->rsp_sga_cbfn = rsp_sga_cbfn; +		fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn; + +		fcxp->nrsp_sgles = nrsp_sgles; +		/* +		 * alloc required sgpgs +		 */ +		if (nrsp_sgles > BFI_SGE_INLINE) { +			nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles); + +			if (bfa_sgpg_malloc +			    (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg) +			    != BFA_STATUS_OK) { +				/* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe, +				nrsp_sgpg); */ +				/* +				 * TODO +				 */ +			} +		} +	} + +	return (fcxp); +} + +/** + * Get the internal request buffer pointer + * + * @param[in]	fcxp	BFA fcxp pointer + * + * @return 		pointer to the internal request buffer + */ +void * +bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) +{ +	struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; +	void	*reqbuf; + +	bfa_assert(fcxp->use_ireqbuf == 1); +	reqbuf = ((u8 *)mod->req_pld_list_kva) + +			fcxp->fcxp_tag * mod->req_pld_sz; +	return reqbuf; +} + +u32 +bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) +{ +	struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + +	return mod->req_pld_sz; +} + +/** + * Get the internal response buffer pointer + * + * @param[in]	fcxp	BFA fcxp pointer + * + * @return		pointer to the internal request buffer + */ +void * +bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) +{ +	struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; +	void	*rspbuf; + +	bfa_assert(fcxp->use_irspbuf == 1); + +	rspbuf = ((u8 *)mod->rsp_pld_list_kva) + +			fcxp->fcxp_tag * mod->rsp_pld_sz; +	return rspbuf; +} + +/** + * 		Free the BFA FCXP + * + * @param[in]	fcxp			BFA fcxp pointer + * + * @return 		void + */ +void +bfa_fcxp_free(struct bfa_fcxp_s *fcxp) +{ +	struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; + +	bfa_assert(fcxp != NULL); +	bfa_trc(mod->bfa, fcxp->fcxp_tag); +	bfa_fcxp_put(fcxp); +} + +/** + * Send a FCXP request + * + * @param[in]	fcxp	BFA fcxp pointer + * @param[in]	rport	BFA rport pointer. Could be left NULL for WKA rports + * @param[in]	vf_id	virtual Fabric ID + * @param[in]	lp_tag  lport tag + * @param[in]	cts	use Continous sequence + * @param[in]	cos	fc Class of Service + * @param[in]	reqlen	request length, does not include FCHS length + * @param[in]	fchs	fc Header Pointer. The header content will be copied + *			in by BFA. + * + * @param[in]	cbfn	call back function to be called on receiving + * 								the response + * @param[in]	cbarg	arg for cbfn + * @param[in]	rsp_timeout + *			response timeout + * + * @return		bfa_status_t + */ +void +bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, +		u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, +		u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, +		void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) +{ +	struct bfa_s			*bfa  = fcxp->fcxp_mod->bfa; +	struct bfa_fcxp_req_info_s	*reqi = &fcxp->req_info; +	struct bfa_fcxp_rsp_info_s	*rspi = &fcxp->rsp_info; +	struct bfi_fcxp_send_req_s	*send_req; + +	bfa_trc(bfa, fcxp->fcxp_tag); + +	/** +	 * setup request/response info +	 */ +	reqi->bfa_rport = rport; +	reqi->vf_id = vf_id; +	reqi->lp_tag = lp_tag; +	reqi->class = cos; +	rspi->rsp_timeout = rsp_timeout; +	reqi->cts = cts; +	reqi->fchs = *fchs; +	reqi->req_tot_len = reqlen; +	rspi->rsp_maxlen = rsp_maxlen; +	fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; +	fcxp->send_cbarg = cbarg; + +	/** +	 * If no room in CPE queue, wait for +	 */ +	send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); +	if (!send_req) { +		bfa_trc(bfa, fcxp->fcxp_tag); +		fcxp->reqq_waiting = BFA_TRUE; +		bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); +		return; +	} + +	bfa_fcxp_queue(fcxp, send_req); +} + +/** + * Abort a BFA FCXP + * + * @param[in]	fcxp	BFA fcxp pointer + * + * @return 		void + */ +bfa_status_t +bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) +{ +	bfa_assert(0); +	return (BFA_STATUS_OK); +} + +void +bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, +			bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg) +{ +	struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + +	bfa_assert(list_empty(&mod->fcxp_free_q)); + +	wqe->alloc_cbfn = alloc_cbfn; +	wqe->alloc_cbarg = alloc_cbarg; +	list_add_tail(&wqe->qe, &mod->wait_q); +} + +void +bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) +{ +	struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + +	bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe)); +	list_del(&wqe->qe); +} + +void +bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) +{ +	/** +	 * If waiting for room in request queue, cancel reqq wait +	 * and free fcxp. +	 */ +	if (fcxp->reqq_waiting) { +		fcxp->reqq_waiting = BFA_FALSE; +		bfa_reqq_wcancel(&fcxp->reqq_wqe); +		bfa_fcxp_free(fcxp); +		return; +	} + +	fcxp->send_cbfn = bfa_fcxp_null_comp; +} + + + +/** + *  hal_fcxp_public BFA FCXP public functions + */ + +void +bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ +	switch (msg->mhdr.msg_id) { +	case BFI_FCXP_I2H_SEND_RSP: +		hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); +		break; + +	default: +		bfa_trc(bfa, msg->mhdr.msg_id); +		bfa_assert(0); +	} +} + +u32 +bfa_fcxp_get_maxrsp(struct bfa_s *bfa) +{ +	struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); + +	return mod->rsp_pld_sz; +} + + diff --git a/drivers/scsi/bfa/bfa_fcxp_priv.h b/drivers/scsi/bfa/bfa_fcxp_priv.h new file mode 100644 index 00000000000..4cda49397da --- /dev/null +++ b/drivers/scsi/bfa/bfa_fcxp_priv.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCXP_PRIV_H__ +#define __BFA_FCXP_PRIV_H__ + +#include <cs/bfa_sm.h> +#include <protocol/fc.h> +#include <bfa_svc.h> +#include <bfi/bfi_fcxp.h> + +#define BFA_FCXP_MIN     	(1) +#define BFA_FCXP_MAX_IBUF_SZ	(2 * 1024 + 256) +#define BFA_FCXP_MAX_LBUF_SZ	(4 * 1024 + 256) + +struct bfa_fcxp_mod_s { +	struct bfa_s      *bfa;		/*  backpointer to BFA */ +	struct bfa_fcxp_s *fcxp_list;	/*  array of FCXPs */ +	u16        num_fcxps;	/*  max num FCXP requests */ +	struct list_head fcxp_free_q;	/*  free FCXPs */ +	struct list_head fcxp_active_q;	/*  active FCXPs */ +	void	*req_pld_list_kva;	/*  list of FCXP req pld */ +	u64 req_pld_list_pa;	/*  list of FCXP req pld */ +	void *rsp_pld_list_kva;		/*  list of FCXP resp pld */ +	u64 rsp_pld_list_pa;	/*  list of FCXP resp pld */ +	struct list_head  wait_q;		/*  wait queue for free fcxp */ +	u32	req_pld_sz; +	u32	rsp_pld_sz; +}; + +#define BFA_FCXP_MOD(__bfa)		(&(__bfa)->modules.fcxp_mod) +#define BFA_FCXP_FROM_TAG(__mod, __tag)	(&(__mod)->fcxp_list[__tag]) + +typedef void    (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, +				   void *cb_arg, bfa_status_t req_status, +				   u32 rsp_len, u32 resid_len, +				   struct fchs_s *rsp_fchs); + +/** + * Information needed for a FCXP request + */ +struct bfa_fcxp_req_info_s { +	struct bfa_rport_s *bfa_rport;	/*  Pointer to the bfa rport that was +					 *returned from bfa_rport_create(). +					 *This could be left NULL for WKA or for +					 *FCXP interactions before the rport +					 *nexus is established +					 */ +	struct fchs_s   fchs;	/*  request FC header structure */ +	u8 cts;		/*  continous sequence */ +	u8 class;		/*  FC class for the request/response */ +	u16 max_frmsz;	/*  max send frame size */ +	u16 vf_id;		/*  vsan tag if applicable */ +	u8	lp_tag;		/*  lport tag */ +	u32 req_tot_len;	/*  request payload total length */ +}; + +struct bfa_fcxp_rsp_info_s { +	struct fchs_s rsp_fchs;		/*  Response frame's FC header will +					 * be *sent back in this field */ +	u8         rsp_timeout;	/*  timeout in seconds, 0-no response +					 */ +	u8         rsvd2[3]; +	u32        rsp_maxlen;	/*  max response length expected */ +}; + +struct bfa_fcxp_s { +	struct list_head 	qe;		/*  fcxp queue element */ +	bfa_sm_t        sm;             /*  state machine */ +	void           	*caller;	/*  driver or fcs */ +	struct bfa_fcxp_mod_s *fcxp_mod; +					/*  back pointer to fcxp mod */ +	u16        fcxp_tag;	/*  internal tag */ +	struct bfa_fcxp_req_info_s req_info; +					/*  request info */ +	struct bfa_fcxp_rsp_info_s rsp_info; +					/*  response info */ +	u8 	use_ireqbuf;	/*  use internal req buf */ +	u8         use_irspbuf;	/*  use internal rsp buf */ +	u32        nreq_sgles;	/*  num request SGLEs */ +	u32        nrsp_sgles;	/*  num response SGLEs */ +	struct list_head req_sgpg_q;	/*  SG pages for request buf */ +	struct list_head req_sgpg_wqe;	/*  wait queue for req SG page */ +	struct list_head rsp_sgpg_q;	/*  SG pages for response buf */ +	struct list_head rsp_sgpg_wqe;	/*  wait queue for rsp SG page */ + +	bfa_fcxp_get_sgaddr_t req_sga_cbfn; +					/*  SG elem addr user function */ +	bfa_fcxp_get_sglen_t req_sglen_cbfn; +					/*  SG elem len user function */ +	bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; +					/*  SG elem addr user function */ +	bfa_fcxp_get_sglen_t rsp_sglen_cbfn; +					/*  SG elem len user function */ +	bfa_cb_fcxp_send_t send_cbfn;   /*  send completion callback */ +	void		*send_cbarg;	/*  callback arg */ +	struct bfa_sge_s   req_sge[BFA_FCXP_MAX_SGES]; +					/*  req SG elems */ +	struct bfa_sge_s   rsp_sge[BFA_FCXP_MAX_SGES]; +					/*  rsp SG elems */ +	u8         rsp_status;	/*  comp: rsp status */ +	u32        rsp_len;	/*  comp: actual response len */ +	u32        residue_len;	/*  comp: residual rsp length */ +	struct fchs_s          rsp_fchs;	/*  comp: response fchs */ +	struct bfa_cb_qe_s    hcb_qe;	/*  comp: callback qelem */ +	struct bfa_reqq_wait_s	reqq_wqe; +	bfa_boolean_t	reqq_waiting; +}; + +#define BFA_FCXP_REQ_PLD(_fcxp) 	(bfa_fcxp_get_reqbuf(_fcxp)) + +#define BFA_FCXP_RSP_FCHS(_fcxp) 	(&((_fcxp)->rsp_info.fchs)) +#define BFA_FCXP_RSP_PLD(_fcxp) 	(bfa_fcxp_get_rspbuf(_fcxp)) + +#define BFA_FCXP_REQ_PLD_PA(_fcxp)					\ +	((_fcxp)->fcxp_mod->req_pld_list_pa +				\ +		((_fcxp)->fcxp_mod->req_pld_sz  * (_fcxp)->fcxp_tag)) + +#define BFA_FCXP_RSP_PLD_PA(_fcxp) 					\ +	((_fcxp)->fcxp_mod->rsp_pld_list_pa +				\ +		((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag)) + +void	bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +#endif /* __BFA_FCXP_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h new file mode 100644 index 00000000000..1ec1355924d --- /dev/null +++ b/drivers/scsi/bfa/bfa_fwimg_priv.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FWIMG_PRIV_H__ +#define __BFA_FWIMG_PRIV_H__ + +#define	BFI_FLASH_CHUNK_SZ		256	/*  Flash chunk size */ +#define	BFI_FLASH_CHUNK_SZ_WORDS	(BFI_FLASH_CHUNK_SZ/sizeof(u32)) + +extern u32 *bfi_image_ct_get_chunk(u32 off); +extern u32 bfi_image_ct_size; +extern u32 *bfi_image_cb_get_chunk(u32 off); +extern u32 bfi_image_cb_size; +extern u32 *bfi_image_cb; +extern u32 *bfi_image_ct; + +#endif /* __BFA_FWIMG_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c new file mode 100644 index 00000000000..ede1438619e --- /dev/null +++ b/drivers/scsi/bfa/bfa_hw_cb.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa_priv.h> +#include <bfi/bfi_cbreg.h> + +void +bfa_hwcb_reginit(struct bfa_s *bfa) +{ +	struct bfa_iocfc_regs_s	*bfa_regs = &bfa->iocfc.bfa_regs; +	bfa_os_addr_t		kva = bfa_ioc_bar0(&bfa->ioc); +	int             	i, q, fn = bfa_ioc_pcifn(&bfa->ioc); + +	if (fn == 0) { +		bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); +		bfa_regs->intr_mask   = (kva + HOSTFN0_INT_MSK); +	} else { +		bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); +		bfa_regs->intr_mask   = (kva + HOSTFN1_INT_MSK); +	} + +	for (i = 0; i < BFI_IOC_MAX_CQS; i++) { +		/* +		 * CPE registers +		 */ +		q = CPE_Q_NUM(fn, i); +		bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q)); +		bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q)); +		bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q)); + +		/* +		 * RME registers +		 */ +		q = CPE_Q_NUM(fn, i); +		bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q)); +		bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q)); +		bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q)); +	} +} + +void +bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq) +{ +} + +static void +bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq) +{ +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, +		__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq)); +} + +void +bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, +		 u32 *num_vecs, u32 *max_vec_bit) +{ +#define __HFN_NUMINTS	13 +	if (bfa_ioc_pcifn(&bfa->ioc) == 0) { +		*msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | +				   __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | +				   __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | +				   __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | +				   __HFN_INT_MBOX_LPU0); +		*max_vec_bit = __HFN_INT_MBOX_LPU0; +	} else { +		*msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | +				   __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | +				   __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | +				   __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | +				   __HFN_INT_MBOX_LPU1); +		*max_vec_bit = __HFN_INT_MBOX_LPU1; +	} + +	*msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | +			    __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS); +	*num_vecs = __HFN_NUMINTS; +} + +/** + * No special setup required for crossbow -- vector assignments are implicit. + */ +void +bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs) +{ +	int i; + +	bfa_assert((nvecs == 1) || (nvecs == __HFN_NUMINTS)); + +	bfa->msix.nvecs = nvecs; +	if (nvecs == 1) { +		for (i = 0; i < BFA_MSIX_CB_MAX; i++) +			bfa->msix.handler[i] = bfa_msix_all; +		return; +	} + +	for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q7; i++) +		bfa->msix.handler[i] = bfa_msix_reqq; + +	for (i = BFA_MSIX_RME_Q0; i <= BFA_MSIX_RME_Q7; i++) +		bfa->msix.handler[i] = bfa_msix_rspq; + +	for (; i < BFA_MSIX_CB_MAX; i++) +		bfa->msix.handler[i] = bfa_msix_lpu_err; +} + +/** + * Crossbow -- dummy, interrupts are masked + */ +void +bfa_hwcb_msix_install(struct bfa_s *bfa) +{ +} + +void +bfa_hwcb_msix_uninstall(struct bfa_s *bfa) +{ +} + +/** + * No special enable/disable -- vector assignments are implicit. + */ +void +bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) +{ +	bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix; +} + + diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c new file mode 100644 index 00000000000..51ae5740e6e --- /dev/null +++ b/drivers/scsi/bfa/bfa_hw_ct.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa_priv.h> +#include <bfi/bfi_ctreg.h> +#include <bfa_ioc.h> + +BFA_TRC_FILE(HAL, IOCFC_CT); + +static u32 __ct_msix_err_vec_reg[] = { +	HOST_MSIX_ERR_INDEX_FN0, +	HOST_MSIX_ERR_INDEX_FN1, +	HOST_MSIX_ERR_INDEX_FN2, +	HOST_MSIX_ERR_INDEX_FN3, +}; + +static void +bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec) +{ +	int fn = bfa_ioc_pcifn(&bfa->ioc); +	bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc); + +	if (msix) +		bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], vec); +	else +		bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], 0); +} + +/** + * Dummy interrupt handler for handling spurious interrupt during chip-reinit. + */ +static void +bfa_hwct_msix_dummy(struct bfa_s *bfa, int vec) +{ +} + +void +bfa_hwct_reginit(struct bfa_s *bfa) +{ +	struct bfa_iocfc_regs_s	*bfa_regs = &bfa->iocfc.bfa_regs; +	bfa_os_addr_t		kva = bfa_ioc_bar0(&bfa->ioc); +	int             	i, q, fn = bfa_ioc_pcifn(&bfa->ioc); + +	if (fn == 0) { +		bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); +		bfa_regs->intr_mask   = (kva + HOSTFN0_INT_MSK); +	} else { +		bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); +		bfa_regs->intr_mask   = (kva + HOSTFN1_INT_MSK); +	} + +	for (i = 0; i < BFI_IOC_MAX_CQS; i++) { +		/* +		 * CPE registers +		 */ +		q = CPE_Q_NUM(fn, i); +		bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5)); +		bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5)); +		bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5)); +		bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5)); + +		/* +		 * RME registers +		 */ +		q = CPE_Q_NUM(fn, i); +		bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5)); +		bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5)); +		bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5)); +		bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5)); +	} +} + +void +bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq) +{ +	u32	r32; + +	r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]); +	bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32); +} + +void +bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, +		 u32 *num_vecs, u32 *max_vec_bit) +{ +	*msix_vecs_bmap = (1 << BFA_MSIX_CT_MAX) - 1; +	*max_vec_bit = (1 << (BFA_MSIX_CT_MAX - 1)); +	*num_vecs = BFA_MSIX_CT_MAX; +} + +/** + * Setup MSI-X vector for catapult + */ +void +bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) +{ +	bfa_assert((nvecs == 1) || (nvecs == BFA_MSIX_CT_MAX)); +	bfa_trc(bfa, nvecs); + +	bfa->msix.nvecs = nvecs; +	bfa_hwct_msix_uninstall(bfa); +} + +void +bfa_hwct_msix_install(struct bfa_s *bfa) +{ +	int i; + +	if (bfa->msix.nvecs == 0) +		return; + +	if (bfa->msix.nvecs == 1) { +		for (i = 0; i < BFA_MSIX_CT_MAX; i++) +			bfa->msix.handler[i] = bfa_msix_all; +		return; +	} + +	for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q3; i++) +		bfa->msix.handler[i] = bfa_msix_reqq; + +	for (; i <= BFA_MSIX_RME_Q3; i++) +		bfa->msix.handler[i] = bfa_msix_rspq; + +	bfa_assert(i == BFA_MSIX_LPU_ERR); +	bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err; +} + +void +bfa_hwct_msix_uninstall(struct bfa_s *bfa) +{ +	int i; + +	for (i = 0; i < BFA_MSIX_CT_MAX; i++) +		bfa->msix.handler[i] = bfa_hwct_msix_dummy; +} + +/** + * Enable MSI-X vectors + */ +void +bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) +{ +	bfa_trc(bfa, 0); +	bfa_hwct_msix_lpu_err_set(bfa, msix, BFA_MSIX_LPU_ERR); +	bfa_ioc_isr_mode_set(&bfa->ioc, msix); +} + + diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c new file mode 100644 index 00000000000..0ca125712a0 --- /dev/null +++ b/drivers/scsi/bfa/bfa_intr.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <bfa.h> +#include <bfi/bfi_cbreg.h> +#include <bfa_port_priv.h> +#include <bfa_intr_priv.h> +#include <cs/bfa_debug.h> + +BFA_TRC_FILE(HAL, INTR); + +static void +bfa_msix_errint(struct bfa_s *bfa, u32 intr) +{ +	bfa_ioc_error_isr(&bfa->ioc); +} + +static void +bfa_msix_lpu(struct bfa_s *bfa) +{ +	bfa_ioc_mbox_isr(&bfa->ioc); +} + +void +bfa_msix_all(struct bfa_s *bfa, int vec) +{ +	bfa_intx(bfa); +} + +/** + *  hal_intr_api + */ +bfa_boolean_t +bfa_intx(struct bfa_s *bfa) +{ +	u32        intr, qintr; +	int             queue; + +	intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); +	if (!intr) +		return BFA_FALSE; + +	/** +	 * RME completion queue interrupt +	 */ +	qintr = intr & __HFN_INT_RME_MASK; +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); + +	for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue ++) { +		if (intr & (__HFN_INT_RME_Q0 << queue)) +			bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); +	} +	intr &= ~qintr; +	if (!intr) +		return BFA_TRUE; + +	/** +	 * CPE completion queue interrupt +	 */ +	qintr = intr & __HFN_INT_CPE_MASK; +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr); + +	for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) { +		if (intr & (__HFN_INT_CPE_Q0 << queue)) +			bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1)); +	} +	intr &= ~qintr; +	if (!intr) +		return BFA_TRUE; + +	bfa_msix_lpu_err(bfa, intr); + +	return BFA_TRUE; +} + +void +bfa_isr_enable(struct bfa_s *bfa) +{ +	u32        intr_unmask; +	int             pci_func = bfa_ioc_pcifn(&bfa->ioc); + +	bfa_trc(bfa, pci_func); + +	bfa_msix_install(bfa); +	intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | +		       __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS); + +	if (pci_func == 0) +		intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | +				__HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | +				__HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | +				__HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | +				__HFN_INT_MBOX_LPU0); +	else +		intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | +				__HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | +				__HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | +				__HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | +				__HFN_INT_MBOX_LPU1); + +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask); +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask); +	bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); +} + +void +bfa_isr_disable(struct bfa_s *bfa) +{ +	bfa_isr_mode_set(bfa, BFA_FALSE); +	bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L); +	bfa_msix_uninstall(bfa); +} + +void +bfa_msix_reqq(struct bfa_s *bfa, int qid) +{ +	struct list_head 		*waitq, *qe, *qen; +	struct bfa_reqq_wait_s	*wqe; + +	qid &= (BFI_IOC_MAX_CQS - 1); + +	waitq = bfa_reqq(bfa, qid); +	list_for_each_safe(qe, qen, waitq) { +		/** +		 * Callback only as long as there is room in request queue +		 */ +		if (bfa_reqq_full(bfa, qid)) +			break; + +		list_del(qe); +		wqe = (struct bfa_reqq_wait_s *) qe; +		wqe->qresume(wqe->cbarg); +	} +} + +void +bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	bfa_trc(bfa, m->mhdr.msg_class); +	bfa_trc(bfa, m->mhdr.msg_id); +	bfa_trc(bfa, m->mhdr.mtag.i2htok); +	bfa_assert(0); +	bfa_trc_stop(bfa->trcmod); +} + +void +bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid) +{ +	struct bfi_msg_s      *m; +	u32        pi, ci; + +	bfa_trc_fp(bfa, rsp_qid); + +	rsp_qid &= (BFI_IOC_MAX_CQS - 1); + +	bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid); + +	ci = bfa_rspq_ci(bfa, rsp_qid); +	pi = bfa_rspq_pi(bfa, rsp_qid); + +	bfa_trc_fp(bfa, ci); +	bfa_trc_fp(bfa, pi); + +	if (bfa->rme_process) { +		while (ci != pi) { +			m = bfa_rspq_elem(bfa, rsp_qid, ci); +			bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX); + +			bfa_isrs[m->mhdr.msg_class] (bfa, m); + +			CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); +		} +	} + +	/** +	 * update CI +	 */ +	bfa_rspq_ci(bfa, rsp_qid) = pi; +	bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi); +	bfa_os_mmiowb(); +} + +void +bfa_msix_lpu_err(struct bfa_s *bfa, int vec) +{ +	u32 intr; + +	intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status); + +	if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1)) +		bfa_msix_lpu(bfa); + +	if (intr & (__HFN_INT_ERR_EMC | +		    __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | +		    __HFN_INT_ERR_PSS)) +		bfa_msix_errint(bfa, intr); +} + +void +bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func) +{ +	bfa_isrs[mc] = isr_func; +} + + diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h new file mode 100644 index 00000000000..8ce6e6b105c --- /dev/null +++ b/drivers/scsi/bfa/bfa_intr_priv.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_INTR_PRIV_H__ +#define __BFA_INTR_PRIV_H__ + +/** + * Message handler + */ +typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); +void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); +void bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func); + + +#define bfa_reqq_pi(__bfa, __reqq)	(__bfa)->iocfc.req_cq_pi[__reqq] +#define bfa_reqq_ci(__bfa, __reqq)					\ +	*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva) + +#define bfa_reqq_full(__bfa, __reqq)				\ +	(((bfa_reqq_pi(__bfa, __reqq) + 1) &			\ +	  ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) ==	\ +	 bfa_reqq_ci(__bfa, __reqq)) + +#define bfa_reqq_next(__bfa, __reqq)				\ +	(bfa_reqq_full(__bfa, __reqq) ? NULL :			\ +	 ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ +			  + bfa_reqq_pi((__bfa), (__reqq))))) + +#define bfa_reqq_produce(__bfa, __reqq)	do {				\ +	(__bfa)->iocfc.req_cq_pi[__reqq]++;				\ +	(__bfa)->iocfc.req_cq_pi[__reqq] &=				\ +		((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1);      \ +	bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq],		\ +				(__bfa)->iocfc.req_cq_pi[__reqq]);      \ +	bfa_os_mmiowb();      \ +} while (0) + +#define bfa_rspq_pi(__bfa, __rspq)					\ +	*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva) + +#define bfa_rspq_ci(__bfa, __rspq)	(__bfa)->iocfc.rsp_cq_ci[__rspq] +#define bfa_rspq_elem(__bfa, __rspq, __ci)				\ +	&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci] + +#define CQ_INCR(__index, __size)					\ +			(__index)++; (__index) &= ((__size) - 1) + +/** + * Queue element to wait for room in request queue. FIFO order is + * maintained when fullfilling requests. + */ +struct bfa_reqq_wait_s { +	struct list_head 	qe; +	void		(*qresume) (void *cbarg); +	void		*cbarg; +}; + +/** + * Circular queue usage assignments + */ +enum { +	BFA_REQQ_IOC	= 0,	/*  all low-priority IOC msgs	*/ +	BFA_REQQ_FCXP	= 0,	/*  all FCXP messages		*/ +	BFA_REQQ_LPS	= 0,	/*  all lport service msgs	*/ +	BFA_REQQ_PORT	= 0,	/*  all port messages		*/ +	BFA_REQQ_FLASH	= 0,	/*  for flash module		*/ +	BFA_REQQ_DIAG	= 0,	/*  for diag module		*/ +	BFA_REQQ_RPORT	= 0,	/*  all port messages		*/ +	BFA_REQQ_SBOOT	= 0,	/*  all san boot messages	*/ +	BFA_REQQ_QOS_LO	= 1,	/*  all low priority IO	*/ +	BFA_REQQ_QOS_MD	= 2,	/*  all medium priority IO	*/ +	BFA_REQQ_QOS_HI	= 3,	/*  all high priority IO	*/ +}; + +static inline void +bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), +			void *cbarg) +{ +	wqe->qresume = qresume; +	wqe->cbarg = cbarg; +} + +#define bfa_reqq(__bfa, __reqq)	&(__bfa)->reqq_waitq[__reqq] + +/** + * static inline void + * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe) + */ +#define bfa_reqq_wait(__bfa, __reqq, __wqe) do {			\ +									\ +		struct list_head *waitq = bfa_reqq(__bfa, __reqq);      \ +									\ +		bfa_assert(((__reqq) < BFI_IOC_MAX_CQS));      \ +		bfa_assert((__wqe)->qresume && (__wqe)->cbarg);      \ +									\ +		list_add_tail(&(__wqe)->qe, waitq);      \ +} while (0) + +#define bfa_reqq_wcancel(__wqe)	list_del(&(__wqe)->qe) + +#endif /* __BFA_INTR_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c new file mode 100644 index 00000000000..149348934ce --- /dev/null +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -0,0 +1,2382 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_ioc.h> +#include <bfa_fwimg_priv.h> +#include <bfa_trcmod_priv.h> +#include <cs/bfa_debug.h> +#include <bfi/bfi_ioc.h> +#include <bfi/bfi_ctreg.h> +#include <aen/bfa_aen_ioc.h> +#include <aen/bfa_aen.h> +#include <log/bfa_log_hal.h> +#include <defs/bfa_defs_pci.h> + +BFA_TRC_FILE(HAL, IOC); + +/** + * IOC local definitions + */ +#define BFA_IOC_TOV		2000	/* msecs */ +#define BFA_IOC_HB_TOV		1000	/* msecs */ +#define BFA_IOC_HB_FAIL_MAX	4 +#define BFA_IOC_HWINIT_MAX	2 +#define BFA_IOC_FWIMG_MINSZ     (16 * 1024) +#define BFA_IOC_TOV_RECOVER	(BFA_IOC_HB_FAIL_MAX * BFA_IOC_HB_TOV \ +				+ BFA_IOC_TOV) + +#define bfa_ioc_timer_start(__ioc)					\ +	bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer,	\ +			bfa_ioc_timeout, (__ioc), BFA_IOC_TOV) +#define bfa_ioc_timer_stop(__ioc)   bfa_timer_stop(&(__ioc)->ioc_timer) + +#define BFA_DBG_FWTRC_ENTS	(BFI_IOC_TRC_ENTS) +#define BFA_DBG_FWTRC_LEN					\ +	(BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) +	\ +	 (sizeof(struct bfa_trc_mod_s) -			\ +	  BFA_TRC_MAX * sizeof(struct bfa_trc_s))) +#define BFA_DBG_FWTRC_OFF(_fn)	(BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn)) +#define bfa_ioc_stats(_ioc, _stats)	(_ioc)->stats._stats ++ + +#define BFA_FLASH_CHUNK_NO(off)         (off / BFI_FLASH_CHUNK_SZ_WORDS) +#define BFA_FLASH_OFFSET_IN_CHUNK(off)  (off % BFI_FLASH_CHUNK_SZ_WORDS) +#define BFA_FLASH_CHUNK_ADDR(chunkno)   (chunkno * BFI_FLASH_CHUNK_SZ_WORDS) +bfa_boolean_t   bfa_auto_recover = BFA_FALSE; + +/* + * forward declarations + */ +static void     bfa_ioc_aen_post(struct bfa_ioc_s *bfa, +				 enum bfa_ioc_aen_event event); +static void     bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc); +static void     bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc); +static void     bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc); +static void     bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force); +static void     bfa_ioc_timeout(void *ioc); +static void     bfa_ioc_send_enable(struct bfa_ioc_s *ioc); +static void     bfa_ioc_send_disable(struct bfa_ioc_s *ioc); +static void     bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); +static void     bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); +static void     bfa_ioc_hb_stop(struct bfa_ioc_s *ioc); +static void     bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force); +static void     bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); +static void     bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); +static void     bfa_ioc_recover(struct bfa_ioc_s *ioc); +static bfa_boolean_t bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc); +static void     bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc); +static void     bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); +static void     bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); + +/** + *  bfa_ioc_sm + */ + +/** + * IOC state machine events + */ +enum ioc_event { +	IOC_E_ENABLE = 1,	/*  IOC enable request */ +	IOC_E_DISABLE = 2,	/*  IOC disable request */ +	IOC_E_TIMEOUT = 3,	/*  f/w response timeout */ +	IOC_E_FWREADY = 4,	/*  f/w initialization done */ +	IOC_E_FWRSP_GETATTR = 5,	/*  IOC get attribute response */ +	IOC_E_FWRSP_ENABLE = 6,	/*  enable f/w response */ +	IOC_E_FWRSP_DISABLE = 7,	/*  disable f/w response */ +	IOC_E_HBFAIL = 8,	/*  heartbeat failure */ +	IOC_E_HWERROR = 9,	/*  hardware error interrupt */ +	IOC_E_SEMLOCKED = 10,	/*  h/w semaphore is locked */ +	IOC_E_DETACH = 11,	/*  driver detach cleanup */ +}; + +bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); +bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); + +static struct bfa_sm_table_s ioc_sm_table[] = { +	{BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, +	{BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH}, +	{BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH}, +	{BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT}, +	{BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT}, +	{BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT}, +	{BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR}, +	{BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL}, +	{BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL}, +	{BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL}, +	{BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING}, +	{BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED}, +}; + +/** + * Reset entry actions -- initialize state machine + */ +static void +bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc) +{ +	ioc->retry_count = 0; +	ioc->auto_recover = bfa_auto_recover; +} + +/** + * Beginning state. IOC is in reset state. + */ +static void +bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_ENABLE: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_disable_comp(ioc); +		break; + +	case IOC_E_DETACH: +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + +/** + * Semaphore should be acquired for version check. + */ +static void +bfa_ioc_sm_fwcheck_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_hw_sem_get(ioc); +} + +/** + * Awaiting h/w semaphore to continue with version check. + */ +static void +bfa_ioc_sm_fwcheck(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_SEMLOCKED: +		if (bfa_ioc_firmware_lock(ioc)) { +			ioc->retry_count = 0; +			bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); +		} else { +			bfa_ioc_hw_sem_release(ioc); +			bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch); +		} +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_disable_comp(ioc); +		/* +		 * fall through +		 */ + +	case IOC_E_DETACH: +		bfa_ioc_hw_sem_get_cancel(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); +		break; + +	case IOC_E_FWREADY: +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + +/** + * Notify enable completion callback and generate mismatch AEN. + */ +static void +bfa_ioc_sm_mismatch_entry(struct bfa_ioc_s *ioc) +{ +	/** +	 * Provide enable completion callback and AEN notification only once. +	 */ +	if (ioc->retry_count == 0) { +		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); +		bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH); +	} +	ioc->retry_count++; +	bfa_ioc_timer_start(ioc); +} + +/** + * Awaiting firmware version match. + */ +static void +bfa_ioc_sm_mismatch(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_TIMEOUT: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_disable_comp(ioc); +		/* +		 * fall through +		 */ + +	case IOC_E_DETACH: +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); +		break; + +	case IOC_E_FWREADY: +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + +/** + * Request for semaphore. + */ +static void +bfa_ioc_sm_semwait_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_hw_sem_get(ioc); +} + +/** + * Awaiting semaphore for h/w initialzation. + */ +static void +bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_SEMLOCKED: +		ioc->retry_count = 0; +		bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_hw_sem_get_cancel(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_hwinit_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_timer_start(ioc); +	bfa_ioc_reset(ioc, BFA_FALSE); +} + +/** + * Hardware is being initialized. Interrupts are enabled. + * Holding hardware semaphore lock. + */ +static void +bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_FWREADY: +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); +		break; + +	case IOC_E_HWERROR: +		bfa_ioc_timer_stop(ioc); +		/* +		 * fall through +		 */ + +	case IOC_E_TIMEOUT: +		ioc->retry_count++; +		if (ioc->retry_count < BFA_IOC_HWINIT_MAX) { +			bfa_ioc_timer_start(ioc); +			bfa_ioc_reset(ioc, BFA_TRUE); +			break; +		} + +		bfa_ioc_hw_sem_release(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_hw_sem_release(ioc); +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_timer_start(ioc); +	bfa_ioc_send_enable(ioc); +} + +/** + * Host IOC function is being enabled, awaiting response from firmware. + * Semaphore is acquired. + */ +static void +bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_FWRSP_ENABLE: +		bfa_ioc_timer_stop(ioc); +		bfa_ioc_hw_sem_release(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); +		break; + +	case IOC_E_HWERROR: +		bfa_ioc_timer_stop(ioc); +		/* +		 * fall through +		 */ + +	case IOC_E_TIMEOUT: +		ioc->retry_count++; +		if (ioc->retry_count < BFA_IOC_HWINIT_MAX) { +			bfa_reg_write(ioc->ioc_regs.ioc_fwstate, +				      BFI_IOC_UNINIT); +			bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit); +			break; +		} + +		bfa_ioc_hw_sem_release(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_timer_stop(ioc); +		bfa_ioc_hw_sem_release(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	case IOC_E_FWREADY: +		bfa_ioc_send_enable(ioc); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_timer_start(ioc); +	bfa_ioc_send_getattr(ioc); +} + +/** + * IOC configuration in progress. Timer is active. + */ +static void +bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_FWRSP_GETATTR: +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_op); +		break; + +	case IOC_E_HWERROR: +		bfa_ioc_timer_stop(ioc); +		/* +		 * fall through +		 */ + +	case IOC_E_TIMEOUT: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail); +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) +{ +	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); +	bfa_ioc_hb_monitor(ioc); +	bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE); +} + +static void +bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_ENABLE: +		break; + +	case IOC_E_DISABLE: +		bfa_ioc_hb_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); +		break; + +	case IOC_E_HWERROR: +	case IOC_E_FWREADY: +		/** +		 * Hard error or IOC recovery by other function. +		 * Treat it same as heartbeat failure. +		 */ +		bfa_ioc_hb_stop(ioc); +		/* +		 * !!! fall through !!! +		 */ + +	case IOC_E_HBFAIL: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE); +	bfa_ioc_timer_start(ioc); +	bfa_ioc_send_disable(ioc); +} + +/** + * IOC is being disabled + */ +static void +bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_HWERROR: +	case IOC_E_FWRSP_DISABLE: +		bfa_ioc_timer_stop(ioc); +		/* +		 * !!! fall through !!! +		 */ + +	case IOC_E_TIMEOUT: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + +/** + * IOC disable completion entry. + */ +static void +bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_disable_comp(ioc); +} + +static void +bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_ENABLE: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); +		break; + +	case IOC_E_DISABLE: +		ioc->cbfn->disable_cbfn(ioc->bfa); +		break; + +	case IOC_E_FWREADY: +		break; + +	case IOC_E_DETACH: +		bfa_ioc_firmware_unlock(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc) +{ +	ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); +	bfa_ioc_timer_start(ioc); +} + +/** + * Hardware initialization failed. + */ +static void +bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { +	case IOC_E_DISABLE: +		bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	case IOC_E_DETACH: +		bfa_ioc_timer_stop(ioc); +		bfa_ioc_firmware_unlock(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); +		break; + +	case IOC_E_TIMEOUT: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + +static void +bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc) +{ +	struct list_head *qe; +	struct bfa_ioc_hbfail_notify_s *notify; + +	/** +	 * Mark IOC as failed in hardware and stop firmware. +	 */ +	bfa_ioc_lpu_stop(ioc); +	bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_HBFAIL); + +	if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) { +		bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P); +		/* +		 * Wait for halt to take effect +		 */ +		bfa_reg_read(ioc->ioc_regs.ll_halt); +	} + +	/** +	 * Notify driver and common modules registered for notification. +	 */ +	ioc->cbfn->hbfail_cbfn(ioc->bfa); +	list_for_each(qe, &ioc->hb_notify_q) { +		notify = (struct bfa_ioc_hbfail_notify_s *)qe; +		notify->cbfn(notify->cbarg); +	} + +	/** +	 * Flush any queued up mailbox requests. +	 */ +	bfa_ioc_mbox_hbfail(ioc); +	bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL); + +	/** +	 * Trigger auto-recovery after a delay. +	 */ +	if (ioc->auto_recover) { +		bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, +				bfa_ioc_timeout, ioc, BFA_IOC_TOV_RECOVER); +	} +} + +/** + * IOC heartbeat failure. + */ +static void +bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event) +{ +	bfa_trc(ioc, event); + +	switch (event) { + +	case IOC_E_ENABLE: +		ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); +		break; + +	case IOC_E_DISABLE: +		if (ioc->auto_recover) +			bfa_ioc_timer_stop(ioc); +		bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); +		break; + +	case IOC_E_TIMEOUT: +		bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait); +		break; + +	case IOC_E_FWREADY: +		/** +		 * Recovery is already initiated by other function. +		 */ +		break; + +	default: +		bfa_sm_fault(ioc, event); +	} +} + + + +/** + *  bfa_ioc_pvt BFA IOC private functions + */ + +static void +bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) +{ +	struct list_head *qe; +	struct bfa_ioc_hbfail_notify_s *notify; + +	ioc->cbfn->disable_cbfn(ioc->bfa); + +	/** +	 * Notify common modules registered for notification. +	 */ +	list_for_each(qe, &ioc->hb_notify_q) { +		notify = (struct bfa_ioc_hbfail_notify_s *)qe; +		notify->cbfn(notify->cbarg); +	} +} + +static void +bfa_ioc_sem_timeout(void *ioc_arg) +{ +	struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg; + +	bfa_ioc_hw_sem_get(ioc); +} + +static void +bfa_ioc_usage_sem_get(struct bfa_ioc_s *ioc) +{ +	u32        r32; +	int             cnt = 0; +#define BFA_SEM_SPINCNT	1000 + +	do { +		r32 = bfa_reg_read(ioc->ioc_regs.ioc_usage_sem_reg); +		cnt++; +		if (cnt > BFA_SEM_SPINCNT) +			break; +	} while (r32 != 0); +	bfa_assert(cnt < BFA_SEM_SPINCNT); +} + +static void +bfa_ioc_usage_sem_release(struct bfa_ioc_s *ioc) +{ +	bfa_reg_write(ioc->ioc_regs.ioc_usage_sem_reg, 1); +} + +static void +bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) +{ +	u32        r32; + +	/** +	 * First read to the semaphore register will return 0, subsequent reads +	 * will return 1. Semaphore is released by writing 0 to the register +	 */ +	r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg); +	if (r32 == 0) { +		bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED); +		return; +	} + +	bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout, +			ioc, BFA_IOC_TOV); +} + +static void +bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc) +{ +	bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1); +} + +static void +bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc) +{ +	bfa_timer_stop(&ioc->sem_timer); +} + +/** + * Initialize LPU local memory (aka secondary memory / SRAM) + */ +static void +bfa_ioc_lmem_init(struct bfa_ioc_s *ioc) +{ +	u32        pss_ctl; +	int             i; +#define PSS_LMEM_INIT_TIME  10000 + +	pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg); +	pss_ctl &= ~__PSS_LMEM_RESET; +	pss_ctl |= __PSS_LMEM_INIT_EN; +	pss_ctl |= __PSS_I2C_CLK_DIV(3UL); /* i2c workaround 12.5khz clock */ +	bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl); + +	/** +	 * wait for memory initialization to be complete +	 */ +	i = 0; +	do { +		pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg); +		i++; +	} while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME)); + +	/** +	 * If memory initialization is not successful, IOC timeout will catch +	 * such failures. +	 */ +	bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE); +	bfa_trc(ioc, pss_ctl); + +	pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN); +	bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl); +} + +static void +bfa_ioc_lpu_start(struct bfa_ioc_s *ioc) +{ +	u32        pss_ctl; + +	/** +	 * Take processor out of reset. +	 */ +	pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg); +	pss_ctl &= ~__PSS_LPU0_RESET; + +	bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl); +} + +static void +bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc) +{ +	u32        pss_ctl; + +	/** +	 * Put processors in reset. +	 */ +	pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg); +	pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET); + +	bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl); +} + +/** + * Get driver and firmware versions. + */ +static void +bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) +{ +	u32        pgnum, pgoff; +	u32        loff = 0; +	int             i; +	u32       *fwsig = (u32 *) fwhdr; + +	pgnum = bfa_ioc_smem_pgnum(ioc, loff); +	pgoff = bfa_ioc_smem_pgoff(ioc, loff); +	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + +	for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32)); +	     i++) { +		fwsig[i] = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); +		loff += sizeof(u32); +	} +} + +static u32 * +bfa_ioc_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off) +{ +	if (ioc->ctdev) +		return bfi_image_ct_get_chunk(off); +	return bfi_image_cb_get_chunk(off); +} + +static          u32 +bfa_ioc_fwimg_get_size(struct bfa_ioc_s *ioc) +{ +return (ioc->ctdev) ? bfi_image_ct_size : bfi_image_cb_size; +} + +/** + * Returns TRUE if same. + */ +static          bfa_boolean_t +bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) +{ +	struct bfi_ioc_image_hdr_s *drv_fwhdr; +	int             i; + +	drv_fwhdr = +		(struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0); + +	for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { +		if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { +			bfa_trc(ioc, i); +			bfa_trc(ioc, fwhdr->md5sum[i]); +			bfa_trc(ioc, drv_fwhdr->md5sum[i]); +			return BFA_FALSE; +		} +	} + +	bfa_trc(ioc, fwhdr->md5sum[0]); +	return BFA_TRUE; +} + +/** + * Return true if current running version is valid. Firmware signature and + * execution context (driver/bios) must match. + */ +static          bfa_boolean_t +bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc) +{ +	struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr; + +	/** +	 * If bios/efi boot (flash based) -- return true +	 */ +	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) +		return BFA_TRUE; + +	bfa_ioc_fwver_get(ioc, &fwhdr); +	drv_fwhdr = +		(struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0); + +	if (fwhdr.signature != drv_fwhdr->signature) { +		bfa_trc(ioc, fwhdr.signature); +		bfa_trc(ioc, drv_fwhdr->signature); +		return BFA_FALSE; +	} + +	if (fwhdr.exec != drv_fwhdr->exec) { +		bfa_trc(ioc, fwhdr.exec); +		bfa_trc(ioc, drv_fwhdr->exec); +		return BFA_FALSE; +	} + +	return bfa_ioc_fwver_cmp(ioc, &fwhdr); +} + +/** + * Return true if firmware of current driver matches the running firmware. + */ +static          bfa_boolean_t +bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc) +{ +	enum bfi_ioc_state ioc_fwstate; +	u32        usecnt; +	struct bfi_ioc_image_hdr_s fwhdr; + +	/** +	 * Firmware match check is relevant only for CNA. +	 */ +	if (!ioc->cna) +		return BFA_TRUE; + +	/** +	 * If bios boot (flash based) -- do not increment usage count +	 */ +	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) +		return BFA_TRUE; + +	bfa_ioc_usage_sem_get(ioc); +	usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); + +	/** +	 * If usage count is 0, always return TRUE. +	 */ +	if (usecnt == 0) { +		bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1); +		bfa_ioc_usage_sem_release(ioc); +		bfa_trc(ioc, usecnt); +		return BFA_TRUE; +	} + +	ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); +	bfa_trc(ioc, ioc_fwstate); + +	/** +	 * Use count cannot be non-zero and chip in uninitialized state. +	 */ +	bfa_assert(ioc_fwstate != BFI_IOC_UNINIT); + +	/** +	 * Check if another driver with a different firmware is active +	 */ +	bfa_ioc_fwver_get(ioc, &fwhdr); +	if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { +		bfa_ioc_usage_sem_release(ioc); +		bfa_trc(ioc, usecnt); +		return BFA_FALSE; +	} + +	/** +	 * Same firmware version. Increment the reference count. +	 */ +	usecnt++; +	bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); +	bfa_ioc_usage_sem_release(ioc); +	bfa_trc(ioc, usecnt); +	return BFA_TRUE; +} + +static void +bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc) +{ +	u32        usecnt; + +	/** +	 * Firmware lock is relevant only for CNA. +	 * If bios boot (flash based) -- do not decrement usage count +	 */ +	if (!ioc->cna || (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)) +		return; + +	/** +	 * decrement usage count +	 */ +	bfa_ioc_usage_sem_get(ioc); +	usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg); +	bfa_assert(usecnt > 0); + +	usecnt--; +	bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt); +	bfa_trc(ioc, usecnt); + +	bfa_ioc_usage_sem_release(ioc); +} + +/** + * Conditionally flush any pending message from firmware at start. + */ +static void +bfa_ioc_msgflush(struct bfa_ioc_s *ioc) +{ +	u32        r32; + +	r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd); +	if (r32) +		bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1); +} + + +static void +bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) +{ +	enum bfi_ioc_state ioc_fwstate; +	bfa_boolean_t   fwvalid; + +	ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate); + +	if (force) +		ioc_fwstate = BFI_IOC_UNINIT; + +	bfa_trc(ioc, ioc_fwstate); + +	/** +	 * check if firmware is valid +	 */ +	fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? +			BFA_FALSE : bfa_ioc_fwver_valid(ioc); + +	if (!fwvalid) { +		bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); +		return; +	} + +	/** +	 * If hardware initialization is in progress (initialized by other IOC), +	 * just wait for an initialization completion interrupt. +	 */ +	if (ioc_fwstate == BFI_IOC_INITING) { +		bfa_trc(ioc, ioc_fwstate); +		ioc->cbfn->reset_cbfn(ioc->bfa); +		return; +	} + +	/** +	 * If IOC function is disabled and firmware version is same, +	 * just re-enable IOC. +	 */ +	if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) { +		bfa_trc(ioc, ioc_fwstate); + +		/** +		 * When using MSI-X any pending firmware ready event should +		 * be flushed. Otherwise MSI-X interrupts are not delivered. +		 */ +		bfa_ioc_msgflush(ioc); +		ioc->cbfn->reset_cbfn(ioc->bfa); +		bfa_fsm_send_event(ioc, IOC_E_FWREADY); +		return; +	} + +	/** +	 * Initialize the h/w for any other states. +	 */ +	bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); +} + +static void +bfa_ioc_timeout(void *ioc_arg) +{ +	struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg; + +	bfa_trc(ioc, 0); +	bfa_fsm_send_event(ioc, IOC_E_TIMEOUT); +} + +void +bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len) +{ +	u32       *msgp = (u32 *) ioc_msg; +	u32        i; + +	bfa_trc(ioc, msgp[0]); +	bfa_trc(ioc, len); + +	bfa_assert(len <= BFI_IOC_MSGLEN_MAX); + +	/* +	 * first write msg to mailbox registers +	 */ +	for (i = 0; i < len / sizeof(u32); i++) +		bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), +			      bfa_os_wtole(msgp[i])); + +	for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++) +		bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0); + +	/* +	 * write 1 to mailbox CMD to trigger LPU event +	 */ +	bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1); +	(void)bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd); +} + +static void +bfa_ioc_send_enable(struct bfa_ioc_s *ioc) +{ +	struct bfi_ioc_ctrl_req_s enable_req; + +	bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, +		    bfa_ioc_portid(ioc)); +	enable_req.ioc_class = ioc->ioc_mc; +	bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s)); +} + +static void +bfa_ioc_send_disable(struct bfa_ioc_s *ioc) +{ +	struct bfi_ioc_ctrl_req_s disable_req; + +	bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ, +		    bfa_ioc_portid(ioc)); +	bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s)); +} + +static void +bfa_ioc_send_getattr(struct bfa_ioc_s *ioc) +{ +	struct bfi_ioc_getattr_req_s attr_req; + +	bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ, +		    bfa_ioc_portid(ioc)); +	bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa); +	bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req)); +} + +static void +bfa_ioc_hb_check(void *cbarg) +{ +	struct bfa_ioc_s *ioc = cbarg; +	u32        hb_count; + +	hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat); +	if (ioc->hb_count == hb_count) { +		ioc->hb_fail++; +	} else { +		ioc->hb_count = hb_count; +		ioc->hb_fail = 0; +	} + +	if (ioc->hb_fail >= BFA_IOC_HB_FAIL_MAX) { +		bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE, hb_count); +		ioc->hb_fail = 0; +		bfa_ioc_recover(ioc); +		return; +	} + +	bfa_ioc_mbox_poll(ioc); +	bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc, +			BFA_IOC_HB_TOV); +} + +static void +bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc) +{ +	ioc->hb_fail = 0; +	ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat); +	bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc, +			BFA_IOC_HB_TOV); +} + +static void +bfa_ioc_hb_stop(struct bfa_ioc_s *ioc) +{ +	bfa_timer_stop(&ioc->ioc_timer); +} + +/** + * Host to LPU mailbox message addresses + */ +static struct { +	u32        hfn_mbox, lpu_mbox, hfn_pgn; +} iocreg_fnreg[] = { +	{ +	HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0}, { +	HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1}, { +	HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2}, { +	HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3} +}; + +/** + * Host <-> LPU mailbox command/status registers - port 0 + */ +static struct { +	u32        hfn, lpu; +} iocreg_mbcmd_p0[] = { +	{ +	HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT}, { +	HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT}, { +	HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT}, { +	HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT} +}; + +/** + * Host <-> LPU mailbox command/status registers - port 1 + */ +static struct { +	u32        hfn, lpu; +} iocreg_mbcmd_p1[] = { +	{ +	HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT}, { +	HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT}, { +	HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT}, { +	HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT} +}; + +/** + * Shared IRQ handling in INTX mode + */ +static struct { +	u32        isr, msk; +} iocreg_shirq_next[] = { +	{ +	HOSTFN1_INT_STATUS, HOSTFN1_INT_MSK}, { +	HOSTFN2_INT_STATUS, HOSTFN2_INT_MSK}, { +	HOSTFN3_INT_STATUS, HOSTFN3_INT_MSK}, { +HOSTFN0_INT_STATUS, HOSTFN0_INT_MSK},}; + +static void +bfa_ioc_reg_init(struct bfa_ioc_s *ioc) +{ +	bfa_os_addr_t   rb; +	int             pcifn = bfa_ioc_pcifn(ioc); + +	rb = bfa_ioc_bar0(ioc); + +	ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; +	ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; +	ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; + +	if (ioc->port_id == 0) { +		ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; +		ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; +		ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn; +		ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu; +		ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; +	} else { +		ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); +		ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); +		ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn; +		ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu; +		ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; +	} + +	/** +	 * Shared IRQ handling in INTX mode +	 */ +	ioc->ioc_regs.shirq_isr_next = rb + iocreg_shirq_next[pcifn].isr; +	ioc->ioc_regs.shirq_msk_next = rb + iocreg_shirq_next[pcifn].msk; + +	/* +	 * PSS control registers +	 */ +	ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); +	ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG); +	ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG); + +	/* +	 * IOC semaphore registers and serialization +	 */ +	ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); +	ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); +	ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); + +	/** +	 * sram memory access +	 */ +	ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); +	ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB; +	if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) +		ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; +} + +/** + *      Initiate a full firmware download. + */ +static void +bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, +		    u32 boot_param) +{ +	u32       *fwimg; +	u32        pgnum, pgoff; +	u32        loff = 0; +	u32        chunkno = 0; +	u32        i; + +	/** +	 * Initialize LMEM first before code download +	 */ +	bfa_ioc_lmem_init(ioc); + +	/** +	 * Flash based firmware boot +	 */ +	bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc)); +	if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) +		boot_type = BFI_BOOT_TYPE_FLASH; +	fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno); +	fwimg[BFI_BOOT_TYPE_OFF / sizeof(u32)] = bfa_os_swap32(boot_type); +	fwimg[BFI_BOOT_PARAM_OFF / sizeof(u32)] = +		bfa_os_swap32(boot_param); + +	pgnum = bfa_ioc_smem_pgnum(ioc, loff); +	pgoff = bfa_ioc_smem_pgoff(ioc, loff); + +	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + +	for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) { + +		if (BFA_FLASH_CHUNK_NO(i) != chunkno) { +			chunkno = BFA_FLASH_CHUNK_NO(i); +			fwimg = bfa_ioc_fwimg_get_chunk(ioc, +					BFA_FLASH_CHUNK_ADDR(chunkno)); +		} + +		/** +		 * write smem +		 */ +		bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, +			      fwimg[BFA_FLASH_OFFSET_IN_CHUNK(i)]); + +		loff += sizeof(u32); + +		/** +		 * handle page offset wrap around +		 */ +		loff = PSS_SMEM_PGOFF(loff); +		if (loff == 0) { +			pgnum++; +			bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); +		} +	} + +	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, +		      bfa_ioc_smem_pgnum(ioc, 0)); +} + +static void +bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force) +{ +	bfa_ioc_hwinit(ioc, force); +} + +/** + * Update BFA configuration from firmware configuration. + */ +static void +bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) +{ +	struct bfi_ioc_attr_s *attr = ioc->attr; + +	attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop); +	attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize); + +	bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); +} + +/** + * Attach time initialization of mbox logic. + */ +static void +bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	int             mc; + +	INIT_LIST_HEAD(&mod->cmd_q); +	for (mc = 0; mc < BFI_MC_MAX; mc++) { +		mod->mbhdlr[mc].cbfn = NULL; +		mod->mbhdlr[mc].cbarg = ioc->bfa; +	} +} + +/** + * Mbox poll timer -- restarts any pending mailbox requests. + */ +static void +bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	struct bfa_mbox_cmd_s *cmd; +	u32        stat; + +	/** +	 * If no command pending, do nothing +	 */ +	if (list_empty(&mod->cmd_q)) +		return; + +	/** +	 * If previous command is not yet fetched by firmware, do nothing +	 */ +	stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd); +	if (stat) +		return; + +	/** +	 * Enqueue command to firmware. +	 */ +	bfa_q_deq(&mod->cmd_q, &cmd); +	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg)); +} + +/** + * Cleanup any pending requests. + */ +static void +bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	struct bfa_mbox_cmd_s *cmd; + +	while (!list_empty(&mod->cmd_q)) +		bfa_q_deq(&mod->cmd_q, &cmd); +} + +/** + * Initialize IOC to port mapping. + */ + +#define FNC_PERS_FN_SHIFT(__fn)	((__fn) * 8) +static void +bfa_ioc_map_port(struct bfa_ioc_s *ioc) +{ +	bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva; +	u32        r32; + +	/** +	 * For crossbow, port id is same as pci function. +	 */ +	if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT) { +		ioc->port_id = bfa_ioc_pcifn(ioc); +		return; +	} + +	/** +	 * For catapult, base port id on personality register and IOC type +	 */ +	r32 = bfa_reg_read(rb + FNC_PERS_REG); +	r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)); +	ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH; + +	bfa_trc(ioc, bfa_ioc_pcifn(ioc)); +	bfa_trc(ioc, ioc->port_id); +} + + + +/** + *  bfa_ioc_public + */ + +/** +* Set interrupt mode for a function: INTX or MSIX + */ +void +bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) +{ +	bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva; +	u32        r32, mode; + +	r32 = bfa_reg_read(rb + FNC_PERS_REG); +	bfa_trc(ioc, r32); + +	mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) & +		__F0_INTX_STATUS; + +	/** +	 * If already in desired mode, do not change anything +	 */ +	if (!msix && mode) +		return; + +	if (msix) +		mode = __F0_INTX_STATUS_MSIX; +	else +		mode = __F0_INTX_STATUS_INTA; + +	r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); +	r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); +	bfa_trc(ioc, r32); + +	bfa_reg_write(rb + FNC_PERS_REG, r32); +} + +bfa_status_t +bfa_ioc_pll_init(struct bfa_ioc_s *ioc) +{ +	bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva; +	u32        pll_sclk, pll_fclk, r32; + +	if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) { +		pll_sclk = +			__APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN | +			__APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) | +			__APP_PLL_312_JITLMT0_1(3U) | +			__APP_PLL_312_CNTLMT0_1(1U); +		pll_fclk = +			__APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN | +			__APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) | +			__APP_PLL_425_JITLMT0_1(3U) | +			__APP_PLL_425_CNTLMT0_1(1U); + +		/** +		 * 	For catapult, choose operational mode FC/FCoE +		 */ +		if (ioc->fcmode) { +			bfa_reg_write((rb + OP_MODE), 0); +			bfa_reg_write((rb + ETH_MAC_SER_REG), +				      __APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 +				      | __APP_EMS_CHANNEL_SEL); +		} else { +			ioc->pllinit = BFA_TRUE; +			bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE); +			bfa_reg_write((rb + ETH_MAC_SER_REG), +				      __APP_EMS_REFCKBUFEN1); +		} +	} else { +		pll_sclk = +			__APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN | +			__APP_PLL_312_P0_1(3U) | __APP_PLL_312_JITLMT0_1(3U) | +			__APP_PLL_312_CNTLMT0_1(3U); +		pll_fclk = +			__APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN | +			__APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) | +			__APP_PLL_425_JITLMT0_1(3U) | +			__APP_PLL_425_CNTLMT0_1(3U); +	} + +	bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT); +	bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT); + +	bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU); + +	bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, +		      __APP_PLL_312_LOGIC_SOFT_RESET); +	bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, +		      __APP_PLL_312_BYPASS | __APP_PLL_312_LOGIC_SOFT_RESET); +	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, +		      __APP_PLL_425_LOGIC_SOFT_RESET); +	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, +		      __APP_PLL_425_BYPASS | __APP_PLL_425_LOGIC_SOFT_RESET); +	bfa_os_udelay(2); +	bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, +		      __APP_PLL_312_LOGIC_SOFT_RESET); +	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, +		      __APP_PLL_425_LOGIC_SOFT_RESET); + +	bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, +		      pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET); +	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, +		      pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET); + +	/** +	 * Wait for PLLs to lock. +	 */ +	bfa_os_udelay(2000); +	bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU); +	bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU); + +	bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk); +	bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk); + +	if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) { +		bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START); +		bfa_os_udelay(1000); +		r32 = bfa_reg_read((rb + MBIST_STAT_REG)); +		bfa_trc(ioc, r32); +	} + +	return BFA_STATUS_OK; +} + +/** + * Interface used by diag module to do firmware boot with memory test + * as the entry vector. + */ +void +bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param) +{ +	bfa_os_addr_t   rb; + +	bfa_ioc_stats(ioc, ioc_boots); + +	if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) +		return; + +	/** +	 * Initialize IOC state of all functions on a chip reset. +	 */ +	rb = ioc->pcidev.pci_bar_kva; +	if (boot_param == BFI_BOOT_TYPE_MEMTEST) { +		bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST); +		bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST); +	} else { +		bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING); +		bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING); +	} + +	bfa_ioc_download_fw(ioc, boot_type, boot_param); + +	/** +	 * Enable interrupts just before starting LPU +	 */ +	ioc->cbfn->reset_cbfn(ioc->bfa); +	bfa_ioc_lpu_start(ioc); +} + +/** + * Enable/disable IOC failure auto recovery. + */ +void +bfa_ioc_auto_recover(bfa_boolean_t auto_recover) +{ +	bfa_auto_recover = BFA_FALSE; +} + + +bfa_boolean_t +bfa_ioc_is_operational(struct bfa_ioc_s *ioc) +{ +	return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op); +} + +void +bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) +{ +	u32       *msgp = mbmsg; +	u32        r32; +	int             i; + +	/** +	 * read the MBOX msg +	 */ +	for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32)); +	     i++) { +		r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox + +				   i * sizeof(u32)); +		msgp[i] = bfa_os_htonl(r32); +	} + +	/** +	 * turn off mailbox interrupt by clearing mailbox status +	 */ +	bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1); +	bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd); +} + +void +bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) +{ +	union bfi_ioc_i2h_msg_u *msg; + +	msg = (union bfi_ioc_i2h_msg_u *)m; + +	bfa_ioc_stats(ioc, ioc_isrs); + +	switch (msg->mh.msg_id) { +	case BFI_IOC_I2H_HBEAT: +		break; + +	case BFI_IOC_I2H_READY_EVENT: +		bfa_fsm_send_event(ioc, IOC_E_FWREADY); +		break; + +	case BFI_IOC_I2H_ENABLE_REPLY: +		bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE); +		break; + +	case BFI_IOC_I2H_DISABLE_REPLY: +		bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE); +		break; + +	case BFI_IOC_I2H_GETATTR_REPLY: +		bfa_ioc_getattr_reply(ioc); +		break; + +	default: +		bfa_trc(ioc, msg->mh.msg_id); +		bfa_assert(0); +	} +} + +/** + * IOC attach time initialization and setup. + * + * @param[in]	ioc	memory for IOC + * @param[in]	bfa	driver instance structure + * @param[in]	trcmod	kernel trace module + * @param[in]	aen	kernel aen event module + * @param[in]	logm	kernel logging module + */ +void +bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, +	       struct bfa_timer_mod_s *timer_mod, struct bfa_trc_mod_s *trcmod, +	       struct bfa_aen_s *aen, struct bfa_log_mod_s *logm) +{ +	ioc->bfa = bfa; +	ioc->cbfn = cbfn; +	ioc->timer_mod = timer_mod; +	ioc->trcmod = trcmod; +	ioc->aen = aen; +	ioc->logm = logm; +	ioc->fcmode = BFA_FALSE; +	ioc->pllinit = BFA_FALSE; +	ioc->dbg_fwsave_once = BFA_TRUE; + +	bfa_ioc_mbox_attach(ioc); +	INIT_LIST_HEAD(&ioc->hb_notify_q); + +	bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); +} + +/** + * Driver detach time IOC cleanup. + */ +void +bfa_ioc_detach(struct bfa_ioc_s *ioc) +{ +	bfa_fsm_send_event(ioc, IOC_E_DETACH); +} + +/** + * Setup IOC PCI properties. + * + * @param[in]	pcidev	PCI device information for this IOC + */ +void +bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, +		 enum bfi_mclass mc) +{ +	ioc->ioc_mc = mc; +	ioc->pcidev = *pcidev; +	ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT); +	ioc->cna = ioc->ctdev && !ioc->fcmode; + +	bfa_ioc_map_port(ioc); +	bfa_ioc_reg_init(ioc); +} + +/** + * Initialize IOC dma memory + * + * @param[in]	dm_kva	kernel virtual address of IOC dma memory + * @param[in]	dm_pa	physical address of IOC dma memory + */ +void +bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa) +{ +	/** +	 * dma memory for firmware attribute +	 */ +	ioc->attr_dma.kva = dm_kva; +	ioc->attr_dma.pa = dm_pa; +	ioc->attr = (struct bfi_ioc_attr_s *)dm_kva; +} + +/** + * Return size of dma memory required. + */ +u32 +bfa_ioc_meminfo(void) +{ +	return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ); +} + +void +bfa_ioc_enable(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_stats(ioc, ioc_enables); +	ioc->dbg_fwsave_once = BFA_TRUE; + +	bfa_fsm_send_event(ioc, IOC_E_ENABLE); +} + +void +bfa_ioc_disable(struct bfa_ioc_s *ioc) +{ +	bfa_ioc_stats(ioc, ioc_disables); +	bfa_fsm_send_event(ioc, IOC_E_DISABLE); +} + +/** + * Returns memory required for saving firmware trace in case of crash. + * Driver must call this interface to allocate memory required for + * automatic saving of firmware trace. Driver should call + * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this + * trace memory. + */ +int +bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover) +{ +return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0; +} + +/** + * Initialize memory for saving firmware trace. Driver must initialize + * trace memory before call bfa_ioc_enable(). + */ +void +bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) +{ +	bfa_assert(ioc->auto_recover); +	ioc->dbg_fwsave = dbg_fwsave; +	ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover); +} + +u32 +bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr) +{ +	return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr); +} + +u32 +bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr) +{ +	return PSS_SMEM_PGOFF(fmaddr); +} + +/** + * Register mailbox message handler functions + * + * @param[in]	ioc		IOC instance + * @param[in]	mcfuncs		message class handler functions + */ +void +bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	int             mc; + +	for (mc = 0; mc < BFI_MC_MAX; mc++) +		mod->mbhdlr[mc].cbfn = mcfuncs[mc]; +} + +/** + * Register mailbox message handler function, to be called by common modules + */ +void +bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, +		    bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; + +	mod->mbhdlr[mc].cbfn = cbfn; +	mod->mbhdlr[mc].cbarg = cbarg; +} + +/** + * Queue a mailbox command request to firmware. Waits if mailbox is busy. + * Responsibility of caller to serialize + * + * @param[in]	ioc	IOC instance + * @param[i]	cmd	Mailbox command + */ +void +bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	u32        stat; + +	/** +	 * If a previous command is pending, queue new command +	 */ +	if (!list_empty(&mod->cmd_q)) { +		list_add_tail(&cmd->qe, &mod->cmd_q); +		return; +	} + +	/** +	 * If mailbox is busy, queue command for poll timer +	 */ +	stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd); +	if (stat) { +		list_add_tail(&cmd->qe, &mod->cmd_q); +		return; +	} + +	/** +	 * mailbox is free -- queue command to firmware +	 */ +	bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg)); +} + +/** + * Handle mailbox interrupts + */ +void +bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc) +{ +	struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; +	struct bfi_mbmsg_s m; +	int             mc; + +	bfa_ioc_msgget(ioc, &m); + +	/** +	 * Treat IOC message class as special. +	 */ +	mc = m.mh.msg_class; +	if (mc == BFI_MC_IOC) { +		bfa_ioc_isr(ioc, &m); +		return; +	} + +	if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) +		return; + +	mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); +} + +void +bfa_ioc_error_isr(struct bfa_ioc_s *ioc) +{ +	bfa_fsm_send_event(ioc, IOC_E_HWERROR); +} + +#ifndef BFA_BIOS_BUILD + +/** + * return true if IOC is disabled + */ +bfa_boolean_t +bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) +{ +	return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) +		|| bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)); +} + +/** + * return true if IOC firmware is different. + */ +bfa_boolean_t +bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc) +{ +	return (bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) +		|| bfa_fsm_cmp_state(ioc, bfa_ioc_sm_fwcheck) +		|| bfa_fsm_cmp_state(ioc, bfa_ioc_sm_mismatch)); +} + +#define bfa_ioc_state_disabled(__sm)		\ +	(((__sm) == BFI_IOC_UNINIT) ||		\ +	 ((__sm) == BFI_IOC_INITING) ||		\ +	 ((__sm) == BFI_IOC_HWINIT) ||		\ +	 ((__sm) == BFI_IOC_DISABLED) ||	\ +	 ((__sm) == BFI_IOC_HBFAIL) ||		\ +	 ((__sm) == BFI_IOC_CFG_DISABLED)) + +/** + * Check if adapter is disabled -- both IOCs should be in a disabled + * state. + */ +bfa_boolean_t +bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) +{ +	u32        ioc_state; +	bfa_os_addr_t   rb = ioc->pcidev.pci_bar_kva; + +	if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)) +		return BFA_FALSE; + +	ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG); +	if (!bfa_ioc_state_disabled(ioc_state)) +		return BFA_FALSE; + +	ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG); +	if (!bfa_ioc_state_disabled(ioc_state)) +		return BFA_FALSE; + +	return BFA_TRUE; +} + +/** + * Add to IOC heartbeat failure notification queue. To be used by common + * modules such as + */ +void +bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc, +			struct bfa_ioc_hbfail_notify_s *notify) +{ +	list_add_tail(¬ify->qe, &ioc->hb_notify_q); +} + +#define BFA_MFG_NAME "Brocade" +void +bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, +			 struct bfa_adapter_attr_s *ad_attr) +{ +	struct bfi_ioc_attr_s *ioc_attr; +	char            model[BFA_ADAPTER_MODEL_NAME_LEN]; + +	ioc_attr = ioc->attr; +	bfa_os_memcpy((void *)&ad_attr->serial_num, +		      (void *)ioc_attr->brcd_serialnum, +		      BFA_ADAPTER_SERIAL_NUM_LEN); + +	bfa_os_memcpy(&ad_attr->fw_ver, ioc_attr->fw_version, BFA_VERSION_LEN); +	bfa_os_memcpy(&ad_attr->optrom_ver, ioc_attr->optrom_version, +		      BFA_VERSION_LEN); +	bfa_os_memcpy(&ad_attr->manufacturer, BFA_MFG_NAME, +		      BFA_ADAPTER_MFG_NAME_LEN); +	bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd, +		      sizeof(struct bfa_mfg_vpd_s)); + +	ad_attr->nports = BFI_ADAPTER_GETP(NPORTS, ioc_attr->adapter_prop); +	ad_attr->max_speed = BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop); + +	/** +	 * model name +	 */ +	if (BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop) == 10) { +		strcpy(model, "BR-10?0"); +		model[5] = '0' + ad_attr->nports; +	} else { +		strcpy(model, "Brocade-??5"); +		model[8] = +			'0' + BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop); +		model[9] = '0' + ad_attr->nports; +	} + +	if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop)) +		ad_attr->prototype = 1; +	else +		ad_attr->prototype = 0; + +	bfa_os_memcpy(&ad_attr->model, model, BFA_ADAPTER_MODEL_NAME_LEN); +	bfa_os_memcpy(&ad_attr->model_descr, &ad_attr->model, +		      BFA_ADAPTER_MODEL_NAME_LEN); + +	ad_attr->pwwn = bfa_ioc_get_pwwn(ioc); +	ad_attr->mac = bfa_ioc_get_mac(ioc); + +	ad_attr->pcie_gen = ioc_attr->pcie_gen; +	ad_attr->pcie_lanes = ioc_attr->pcie_lanes; +	ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig; +	ad_attr->asic_rev = ioc_attr->asic_rev; +	ad_attr->hw_ver[0] = 'R'; +	ad_attr->hw_ver[1] = 'e'; +	ad_attr->hw_ver[2] = 'v'; +	ad_attr->hw_ver[3] = '-'; +	ad_attr->hw_ver[4] = ioc_attr->asic_rev; +	ad_attr->hw_ver[5] = '\0'; + +	ad_attr->cna_capable = ioc->cna; +} + +void +bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) +{ +	bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s)); + +	ioc_attr->state = bfa_sm_to_state(ioc_sm_table, ioc->fsm); +	ioc_attr->port_id = ioc->port_id; + +	if (!ioc->ctdev) +		ioc_attr->ioc_type = BFA_IOC_TYPE_FC; +	else if (ioc->ioc_mc == BFI_MC_IOCFC) +		ioc_attr->ioc_type = BFA_IOC_TYPE_FCoE; +	else if (ioc->ioc_mc == BFI_MC_LL) +		ioc_attr->ioc_type = BFA_IOC_TYPE_LL; + +	bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr); + +	ioc_attr->pci_attr.device_id = ioc->pcidev.device_id; +	ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func; +	ioc_attr->pci_attr.chip_rev[0] = 'R'; +	ioc_attr->pci_attr.chip_rev[1] = 'e'; +	ioc_attr->pci_attr.chip_rev[2] = 'v'; +	ioc_attr->pci_attr.chip_rev[3] = '-'; +	ioc_attr->pci_attr.chip_rev[4] = ioc_attr->adapter_attr.asic_rev; +	ioc_attr->pci_attr.chip_rev[5] = '\0'; +} + +/** + *  hal_wwn_public + */ +wwn_t +bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc) +{ +	union { +		wwn_t           wwn; +		u8         byte[sizeof(wwn_t)]; +	} +	w; + +	w.wwn = ioc->attr->mfg_wwn; + +	if (bfa_ioc_portid(ioc) == 1) +		w.byte[7]++; + +	return w.wwn; +} + +wwn_t +bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc) +{ +	union { +		wwn_t           wwn; +		u8         byte[sizeof(wwn_t)]; +	} +	w; + +	w.wwn = ioc->attr->mfg_wwn; + +	if (bfa_ioc_portid(ioc) == 1) +		w.byte[7]++; + +	w.byte[0] = 0x20; + +	return w.wwn; +} + +wwn_t +bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst) +{ +	union { +		wwn_t           wwn; +		u8         byte[sizeof(wwn_t)]; +	} +	w              , w5; + +	bfa_trc(ioc, inst); + +	w.wwn = ioc->attr->mfg_wwn; +	w5.byte[0] = 0x50 | w.byte[2] >> 4; +	w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4; +	w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4; +	w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4; +	w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4; +	w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4; +	w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8; +	w5.byte[7] = (inst & 0xff); + +	return w5.wwn; +} + +u64 +bfa_ioc_get_adid(struct bfa_ioc_s *ioc) +{ +	return ioc->attr->mfg_wwn; +} + +mac_t +bfa_ioc_get_mac(struct bfa_ioc_s *ioc) +{ +	mac_t           mac; + +	mac = ioc->attr->mfg_mac; +	mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc); + +	return mac; +} + +void +bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) +{ +	ioc->fcmode = BFA_TRUE; +	ioc->port_id = bfa_ioc_pcifn(ioc); +} + +bfa_boolean_t +bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) +{ +	return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT); +} + +/** + * Return true if interrupt should be claimed. + */ +bfa_boolean_t +bfa_ioc_intx_claim(struct bfa_ioc_s *ioc) +{ +	u32        isr, msk; + +	/** +	 * Always claim if not catapult. +	 */ +	if (!ioc->ctdev) +		return BFA_TRUE; + +	/** +	 * FALSE if next device is claiming interrupt. +	 * TRUE if next device is not interrupting or not present. +	 */ +	msk = bfa_reg_read(ioc->ioc_regs.shirq_msk_next); +	isr = bfa_reg_read(ioc->ioc_regs.shirq_isr_next); +	return !(isr & ~msk); +} + +/** + * Send AEN notification + */ +static void +bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = ioc->logm; +	s32         inst_num = 0; +	struct bfa_ioc_attr_s ioc_attr; + +	switch (event) { +	case BFA_IOC_AEN_HBGOOD: +		bfa_log(logmod, BFA_AEN_IOC_HBGOOD, inst_num); +		break; +	case BFA_IOC_AEN_HBFAIL: +		bfa_log(logmod, BFA_AEN_IOC_HBFAIL, inst_num); +		break; +	case BFA_IOC_AEN_ENABLE: +		bfa_log(logmod, BFA_AEN_IOC_ENABLE, inst_num); +		break; +	case BFA_IOC_AEN_DISABLE: +		bfa_log(logmod, BFA_AEN_IOC_DISABLE, inst_num); +		break; +	case BFA_IOC_AEN_FWMISMATCH: +		bfa_log(logmod, BFA_AEN_IOC_FWMISMATCH, inst_num); +		break; +	default: +		break; +	} + +	memset(&aen_data.ioc.pwwn, 0, sizeof(aen_data.ioc.pwwn)); +	memset(&aen_data.ioc.mac, 0, sizeof(aen_data.ioc.mac)); +	bfa_ioc_get_attr(ioc, &ioc_attr); +	switch (ioc_attr.ioc_type) { +	case BFA_IOC_TYPE_FC: +		aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc); +		break; +	case BFA_IOC_TYPE_FCoE: +		aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc); +		aen_data.ioc.mac = bfa_ioc_get_mac(ioc); +		break; +	case BFA_IOC_TYPE_LL: +		aen_data.ioc.mac = bfa_ioc_get_mac(ioc); +		break; +	default: +		bfa_assert(ioc_attr.ioc_type == BFA_IOC_TYPE_FC); +		break; +	} +	aen_data.ioc.ioc_type = ioc_attr.ioc_type; +} + +/** + * Retrieve saved firmware trace from a prior IOC failure. + */ +bfa_status_t +bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) +{ +	int             tlen; + +	if (ioc->dbg_fwsave_len == 0) +		return BFA_STATUS_ENOFSAVE; + +	tlen = *trclen; +	if (tlen > ioc->dbg_fwsave_len) +		tlen = ioc->dbg_fwsave_len; + +	bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen); +	*trclen = tlen; +	return BFA_STATUS_OK; +} + +/** + * Retrieve saved firmware trace from a prior IOC failure. + */ +bfa_status_t +bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) +{ +	u32        pgnum; +	u32        loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc)); +	int             i, tlen; +	u32       *tbuf = trcdata, r32; + +	bfa_trc(ioc, *trclen); + +	pgnum = bfa_ioc_smem_pgnum(ioc, loff); +	loff = bfa_ioc_smem_pgoff(ioc, loff); +	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); + +	tlen = *trclen; +	if (tlen > BFA_DBG_FWTRC_LEN) +		tlen = BFA_DBG_FWTRC_LEN; +	tlen /= sizeof(u32); + +	bfa_trc(ioc, tlen); + +	for (i = 0; i < tlen; i++) { +		r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); +		tbuf[i] = bfa_os_ntohl(r32); +		loff += sizeof(u32); + +		/** +		 * handle page offset wrap around +		 */ +		loff = PSS_SMEM_PGOFF(loff); +		if (loff == 0) { +			pgnum++; +			bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); +		} +	} +	bfa_reg_write(ioc->ioc_regs.host_page_num_fn, +		      bfa_ioc_smem_pgnum(ioc, 0)); +	bfa_trc(ioc, pgnum); + +	*trclen = tlen * sizeof(u32); +	return BFA_STATUS_OK; +} + +/** + * Save firmware trace if configured. + */ +static void +bfa_ioc_debug_save(struct bfa_ioc_s *ioc) +{ +	int             tlen; + +	if (ioc->dbg_fwsave_len) { +		tlen = ioc->dbg_fwsave_len; +		bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen); +	} +} + +/** + * Firmware failure detected. Start recovery actions. + */ +static void +bfa_ioc_recover(struct bfa_ioc_s *ioc) +{ +	if (ioc->dbg_fwsave_once) { +		ioc->dbg_fwsave_once = BFA_FALSE; +		bfa_ioc_debug_save(ioc); +	} + +	bfa_ioc_stats(ioc, ioc_hbfails); +	bfa_fsm_send_event(ioc, IOC_E_HBFAIL); +} + +#else + +static void +bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) +{ +} + +static void +bfa_ioc_recover(struct bfa_ioc_s *ioc) +{ +	bfa_assert(0); +} + +#endif + + diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h new file mode 100644 index 00000000000..58efd4b1314 --- /dev/null +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_IOC_H__ +#define __BFA_IOC_H__ + +#include <cs/bfa_sm.h> +#include <bfi/bfi.h> +#include <bfi/bfi_ioc.h> +#include <bfi/bfi_boot.h> +#include <bfa_timer.h> + +/** + * PCI device information required by IOC + */ +struct bfa_pcidev_s { +	int             pci_slot; +	u8         pci_func; +	u16	device_id; +	bfa_os_addr_t   pci_bar_kva; +}; + +/** + * Structure used to remember the DMA-able memory block's KVA and Physical + * Address + */ +struct bfa_dma_s { +	void		*kva;	/*! Kernel virtual address	*/ +	u64	pa;	/*! Physical address		*/ +}; + +#define BFA_DMA_ALIGN_SZ	256 +#define BFA_ROUNDUP(_l, _s)	(((_l) + ((_s) - 1)) & ~((_s) - 1)) + + + +#define bfa_dma_addr_set(dma_addr, pa)	\ +		__bfa_dma_addr_set(&dma_addr, (u64)pa) + +static inline void +__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa) +{ +	dma_addr->a32.addr_lo = (u32) pa; +	dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa)); +} + + +#define bfa_dma_be_addr_set(dma_addr, pa)	\ +		__bfa_dma_be_addr_set(&dma_addr, (u64)pa) +static inline void +__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) +{ +	dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa); +	dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa)); +} + +struct bfa_ioc_regs_s { +	bfa_os_addr_t   hfn_mbox_cmd; +	bfa_os_addr_t   hfn_mbox; +	bfa_os_addr_t   lpu_mbox_cmd; +	bfa_os_addr_t   lpu_mbox; +	bfa_os_addr_t   pss_ctl_reg; +	bfa_os_addr_t   app_pll_fast_ctl_reg; +	bfa_os_addr_t   app_pll_slow_ctl_reg; +	bfa_os_addr_t   ioc_sem_reg; +	bfa_os_addr_t   ioc_usage_sem_reg; +	bfa_os_addr_t   ioc_usage_reg; +	bfa_os_addr_t   host_page_num_fn; +	bfa_os_addr_t   heartbeat; +	bfa_os_addr_t   ioc_fwstate; +	bfa_os_addr_t   ll_halt; +	bfa_os_addr_t   shirq_isr_next; +	bfa_os_addr_t   shirq_msk_next; +	bfa_os_addr_t   smem_page_start; +	u32	smem_pg0; +}; + +#define bfa_reg_read(_raddr)	bfa_os_reg_read(_raddr) +#define bfa_reg_write(_raddr, _val)	bfa_os_reg_write(_raddr, _val) +#define bfa_mem_read(_raddr, _off)	bfa_os_mem_read(_raddr, _off) +#define bfa_mem_write(_raddr, _off, _val)	\ +					bfa_os_mem_write(_raddr, _off, _val) +/** + * IOC Mailbox structures + */ +struct bfa_mbox_cmd_s { +	struct list_head		qe; +	u32	msg[BFI_IOC_MSGSZ]; +}; + +/** + * IOC mailbox module + */ +typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m); +struct bfa_ioc_mbox_mod_s { +	struct list_head	cmd_q;		/*  pending mbox queue	*/ +	int		nmclass;	/*  number of handlers */ +	struct { +		bfa_ioc_mbox_mcfunc_t	cbfn;	/*  message handlers	*/ +		void			*cbarg; +	} mbhdlr[BFI_MC_MAX]; +}; + +/** + * IOC callback function interfaces + */ +typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status); +typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa); +typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa); +typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa); +struct bfa_ioc_cbfn_s { +	bfa_ioc_enable_cbfn_t	enable_cbfn; +	bfa_ioc_disable_cbfn_t	disable_cbfn; +	bfa_ioc_hbfail_cbfn_t	hbfail_cbfn; +	bfa_ioc_reset_cbfn_t	reset_cbfn; +}; + +/** + * Heartbeat failure notification queue element. + */ +struct bfa_ioc_hbfail_notify_s { +	struct list_head		qe; +	bfa_ioc_hbfail_cbfn_t	cbfn; +	void			*cbarg; +}; + +/** + * Initialize a heartbeat failure notification structure + */ +#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do {	\ +	(__notify)->cbfn = (__cbfn);      \ +	(__notify)->cbarg = (__cbarg);      \ +} while (0) + +struct bfa_ioc_s { +	bfa_fsm_t		fsm; +	struct bfa_s		*bfa; +	struct bfa_pcidev_s	pcidev; +	struct bfa_timer_mod_s 	*timer_mod; +	struct bfa_timer_s 	ioc_timer; +	struct bfa_timer_s 	sem_timer; +	u32		hb_count; +	u32		hb_fail; +	u32		retry_count; +	struct list_head		hb_notify_q; +	void			*dbg_fwsave; +	int			dbg_fwsave_len; +	bfa_boolean_t		dbg_fwsave_once; +	enum bfi_mclass		ioc_mc; +	struct bfa_ioc_regs_s 	ioc_regs; +	struct bfa_trc_mod_s	*trcmod; +	struct bfa_aen_s	*aen; +	struct bfa_log_mod_s	*logm; +	struct bfa_ioc_drv_stats_s	stats; +	bfa_boolean_t		auto_recover; +	bfa_boolean_t		fcmode; +	bfa_boolean_t		ctdev; +	bfa_boolean_t		cna; +	bfa_boolean_t		pllinit; +	u8			port_id; + +	struct bfa_dma_s	attr_dma; +	struct bfi_ioc_attr_s	*attr; +	struct bfa_ioc_cbfn_s	*cbfn; +	struct bfa_ioc_mbox_mod_s mbox_mod; +}; + +#define bfa_ioc_pcifn(__ioc)		(__ioc)->pcidev.pci_func +#define bfa_ioc_devid(__ioc)		(__ioc)->pcidev.device_id +#define bfa_ioc_bar0(__ioc)		(__ioc)->pcidev.pci_bar_kva +#define bfa_ioc_portid(__ioc)		((__ioc)->port_id) +#define bfa_ioc_fetch_stats(__ioc, __stats) \ +		((__stats)->drv_stats) = (__ioc)->stats +#define bfa_ioc_clr_stats(__ioc)	\ +		bfa_os_memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats)) +#define bfa_ioc_maxfrsize(__ioc)	(__ioc)->attr->maxfrsize +#define bfa_ioc_rx_bbcredit(__ioc)	(__ioc)->attr->rx_bbcredit +#define bfa_ioc_speed_sup(__ioc)	\ +	BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop) + +/** + * IOC mailbox interface + */ +void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd); +void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, +		bfa_ioc_mbox_mcfunc_t *mcfuncs); +void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc); +void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len); +void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); +void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, +		bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg); + +/** + * IOC interfaces + */ +void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, +		struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod, +		struct bfa_trc_mod_s *trcmod, +		struct bfa_aen_s *aen, struct bfa_log_mod_s *logm); +void bfa_ioc_detach(struct bfa_ioc_s *ioc); +void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, +		enum bfi_mclass mc); +u32 bfa_ioc_meminfo(void); +void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc,  u8 *dm_kva, u64 dm_pa); +void bfa_ioc_enable(struct bfa_ioc_s *ioc); +void bfa_ioc_disable(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc); + +void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param); +void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); +void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); +void bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t intx); +bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc); +void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc); +void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr); +void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, +		struct bfa_adapter_attr_s *ad_attr); +int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover); +void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave); +bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, +		int *trclen); +bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, +				 int *trclen); +u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr); +u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr); +void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc); +bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc); +void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc, +	struct bfa_ioc_hbfail_notify_s *notify); + +/* + * bfa mfg wwn API functions + */ +wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc); +wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc); +wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst); +mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc); +u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc); + +#endif /* __BFA_IOC_H__ */ + diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c new file mode 100644 index 00000000000..12350b022d6 --- /dev/null +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <cs/bfa_debug.h> +#include <bfa_priv.h> +#include <log/bfa_log_hal.h> +#include <bfi/bfi_boot.h> +#include <bfi/bfi_cbreg.h> +#include <aen/bfa_aen_ioc.h> +#include <defs/bfa_defs_iocfc.h> +#include <defs/bfa_defs_pci.h> +#include "bfa_callback_priv.h" +#include "bfad_drv.h" + +BFA_TRC_FILE(HAL, IOCFC); + +/** + * IOC local definitions + */ +#define BFA_IOCFC_TOV		5000	/* msecs */ + +enum { +	BFA_IOCFC_ACT_NONE	= 0, +	BFA_IOCFC_ACT_INIT	= 1, +	BFA_IOCFC_ACT_STOP	= 2, +	BFA_IOCFC_ACT_DISABLE	= 3, +}; + +/* + * forward declarations + */ +static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status); +static void bfa_iocfc_disable_cbfn(void *bfa_arg); +static void bfa_iocfc_hbfail_cbfn(void *bfa_arg); +static void bfa_iocfc_reset_cbfn(void *bfa_arg); +static void bfa_iocfc_stats_clear(void *bfa_arg); +static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, +			struct bfa_fw_stats_s *s); +static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete); +static void bfa_iocfc_stats_clr_timeout(void *bfa_arg); +static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete); +static void bfa_iocfc_stats_timeout(void *bfa_arg); + +static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn; + +/** + *  bfa_ioc_pvt BFA IOC private functions + */ + +static void +bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ +	int             i, per_reqq_sz, per_rspq_sz; + +	per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), +							BFA_DMA_ALIGN_SZ); +	per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), +							BFA_DMA_ALIGN_SZ); + +	/* +	 * Calculate CQ size +	 */ +	for (i = 0; i < cfg->fwcfg.num_cqs; i++) { +		*dm_len = *dm_len + per_reqq_sz; +		*dm_len = *dm_len + per_rspq_sz; +	} + +	/* +	 * Calculate Shadow CI/PI size +	 */ +	for (i = 0; i < cfg->fwcfg.num_cqs; i++) +		*dm_len += (2 * BFA_CACHELINE_SZ); +} + +static void +bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len) +{ +	*dm_len += +		BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); +	*dm_len += +		BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), +			    BFA_CACHELINE_SZ); +	*dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); +} + +/** + * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ + */ +static void +bfa_iocfc_send_cfg(void *bfa_arg) +{ +	struct bfa_s *bfa = bfa_arg; +	struct bfa_iocfc_s *iocfc = &bfa->iocfc; +	struct bfi_iocfc_cfg_req_s cfg_req; +	struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; +	struct bfa_iocfc_cfg_s  *cfg = &iocfc->cfg; +	int             i; + +	bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS); +	bfa_trc(bfa, cfg->fwcfg.num_cqs); + +	iocfc->cfgdone = BFA_FALSE; +	bfa_iocfc_reset_queues(bfa); + +	/** +	 * initialize IOC configuration info +	 */ +	cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; +	cfg_info->num_cqs = cfg->fwcfg.num_cqs; + +	bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); +	bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa); + +	/** +	 * dma map REQ and RSP circular queues and shadow pointers +	 */ +	for (i = 0; i < cfg->fwcfg.num_cqs; i++) { +		bfa_dma_be_addr_set(cfg_info->req_cq_ba[i], +				       iocfc->req_cq_ba[i].pa); +		bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i], +				       iocfc->req_cq_shadow_ci[i].pa); +		cfg_info->req_cq_elems[i] = +			bfa_os_htons(cfg->drvcfg.num_reqq_elems); + +		bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i], +				       iocfc->rsp_cq_ba[i].pa); +		bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i], +				       iocfc->rsp_cq_shadow_pi[i].pa); +		cfg_info->rsp_cq_elems[i] = +			bfa_os_htons(cfg->drvcfg.num_rspq_elems); +	} + +	/** +	 * dma map IOC configuration itself +	 */ +	bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, +			bfa_lpuid(bfa)); +	bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); + +	bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, +			sizeof(struct bfi_iocfc_cfg_req_s)); +} + +static void +bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		    struct bfa_pcidev_s *pcidev) +{ +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	bfa->bfad = bfad; +	iocfc->bfa = bfa; +	iocfc->action = BFA_IOCFC_ACT_NONE; + +	bfa_os_assign(iocfc->cfg, *cfg); + +	/** +	 * Initialize chip specific handlers. +	 */ +	if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) { +		iocfc->hwif.hw_reginit = bfa_hwct_reginit; +		iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; +		iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; +		iocfc->hwif.hw_msix_install = bfa_hwct_msix_install; +		iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; +		iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; +		iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; +	} else { +		iocfc->hwif.hw_reginit = bfa_hwcb_reginit; +		iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; +		iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; +		iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install; +		iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; +		iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; +		iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; +	} + +	iocfc->hwif.hw_reginit(bfa); +	bfa->msix.nvecs = 0; +} + +static void +bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, +		      struct bfa_meminfo_s *meminfo) +{ +	u8        *dm_kva; +	u64        dm_pa; +	int             i, per_reqq_sz, per_rspq_sz; +	struct bfa_iocfc_s  *iocfc = &bfa->iocfc; +	int		dbgsz; + +	dm_kva = bfa_meminfo_dma_virt(meminfo); +	dm_pa = bfa_meminfo_dma_phys(meminfo); + +	/* +	 * First allocate dma memory for IOC. +	 */ +	bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa); +	dm_kva += bfa_ioc_meminfo(); +	dm_pa  += bfa_ioc_meminfo(); + +	/* +	 * Claim DMA-able memory for the request/response queues and for shadow +	 * ci/pi registers +	 */ +	per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), +							BFA_DMA_ALIGN_SZ); +	per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), +							BFA_DMA_ALIGN_SZ); + +	for (i = 0; i < cfg->fwcfg.num_cqs; i++) { +		iocfc->req_cq_ba[i].kva = dm_kva; +		iocfc->req_cq_ba[i].pa = dm_pa; +		bfa_os_memset(dm_kva, 0, per_reqq_sz); +		dm_kva += per_reqq_sz; +		dm_pa += per_reqq_sz; + +		iocfc->rsp_cq_ba[i].kva = dm_kva; +		iocfc->rsp_cq_ba[i].pa = dm_pa; +		bfa_os_memset(dm_kva, 0, per_rspq_sz); +		dm_kva += per_rspq_sz; +		dm_pa += per_rspq_sz; +	} + +	for (i = 0; i < cfg->fwcfg.num_cqs; i++) { +		iocfc->req_cq_shadow_ci[i].kva = dm_kva; +		iocfc->req_cq_shadow_ci[i].pa = dm_pa; +		dm_kva += BFA_CACHELINE_SZ; +		dm_pa += BFA_CACHELINE_SZ; + +		iocfc->rsp_cq_shadow_pi[i].kva = dm_kva; +		iocfc->rsp_cq_shadow_pi[i].pa = dm_pa; +		dm_kva += BFA_CACHELINE_SZ; +		dm_pa += BFA_CACHELINE_SZ; +	} + +	/* +	 * Claim DMA-able memory for the config info page +	 */ +	bfa->iocfc.cfg_info.kva = dm_kva; +	bfa->iocfc.cfg_info.pa = dm_pa; +	bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; +	dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); +	dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); + +	/* +	 * Claim DMA-able memory for the config response +	 */ +	bfa->iocfc.cfgrsp_dma.kva = dm_kva; +	bfa->iocfc.cfgrsp_dma.pa = dm_pa; +	bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; + +	dm_kva += +		BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), +			    BFA_CACHELINE_SZ); +	dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), +			     BFA_CACHELINE_SZ); + +	/* +	 * Claim DMA-able memory for iocfc stats +	 */ +	bfa->iocfc.stats_kva = dm_kva; +	bfa->iocfc.stats_pa = dm_pa; +	bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva; +	dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); +	dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ); + +	bfa_meminfo_dma_virt(meminfo) = dm_kva; +	bfa_meminfo_dma_phys(meminfo) = dm_pa; + +	dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover); +	if (dbgsz > 0) { +		bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo)); +		bfa_meminfo_kva(meminfo) += dbgsz; +	} +} + +/** + * BFA submodules initialization completion notification. + */ +static void +bfa_iocfc_initdone_submod(struct bfa_s *bfa) +{ +	int             i; + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->initdone(bfa); +} + +/** + * Start BFA submodules. + */ +static void +bfa_iocfc_start_submod(struct bfa_s *bfa) +{ +	int             i; + +	bfa->rme_process = BFA_TRUE; + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->start(bfa); +} + +/** + * Disable BFA submodules. + */ +static void +bfa_iocfc_disable_submod(struct bfa_s *bfa) +{ +	int             i; + +	for (i = 0; hal_mods[i]; i++) +		hal_mods[i]->iocdisable(bfa); +} + +static void +bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete) +{ +	struct bfa_s	*bfa = bfa_arg; + +	if (complete) { +		if (bfa->iocfc.cfgdone) +			bfa_cb_init(bfa->bfad, BFA_STATUS_OK); +		else +			bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED); +	} else +		bfa->iocfc.action = BFA_IOCFC_ACT_NONE; +} + +static void +bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) +{ +	struct bfa_s  *bfa = bfa_arg; +	struct bfad_s *bfad = bfa->bfad; + +	if (compl) +		complete(&bfad->comp); + +	else +		bfa->iocfc.action = BFA_IOCFC_ACT_NONE; +} + +static void +bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) +{ +	struct bfa_s  *bfa = bfa_arg; +	struct bfad_s *bfad = bfa->bfad; + +	if (compl) +		complete(&bfad->disable_comp); +} + +/** + * Update BFA configuration from firmware configuration. + */ +static void +bfa_iocfc_cfgrsp(struct bfa_s *bfa) +{ +	struct bfa_iocfc_s		*iocfc	 = &bfa->iocfc; +	struct bfi_iocfc_cfgrsp_s	*cfgrsp  = iocfc->cfgrsp; +	struct bfa_iocfc_fwcfg_s	*fwcfg   = &cfgrsp->fwcfg; +	struct bfi_iocfc_cfg_s 		*cfginfo = iocfc->cfginfo; + +	fwcfg->num_cqs        = fwcfg->num_cqs; +	fwcfg->num_ioim_reqs  = bfa_os_ntohs(fwcfg->num_ioim_reqs); +	fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs); +	fwcfg->num_fcxp_reqs  = bfa_os_ntohs(fwcfg->num_fcxp_reqs); +	fwcfg->num_uf_bufs    = bfa_os_ntohs(fwcfg->num_uf_bufs); +	fwcfg->num_rports     = bfa_os_ntohs(fwcfg->num_rports); + +	cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce; +	cfginfo->intr_attr.delay    = bfa_os_ntohs(cfgrsp->intr_attr.delay); +	cfginfo->intr_attr.latency  = bfa_os_ntohs(cfgrsp->intr_attr.latency); + +	iocfc->cfgdone = BFA_TRUE; + +	/** +	 * Configuration is complete - initialize/start submodules +	 */ +	if (iocfc->action == BFA_IOCFC_ACT_INIT) +		bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa); +	else +		bfa_iocfc_start_submod(bfa); +} + +static void +bfa_iocfc_stats_clear(void *bfa_arg) +{ +	struct bfa_s		*bfa = bfa_arg; +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; +	struct bfi_iocfc_stats_req_s stats_req; + +	bfa_timer_start(bfa, &iocfc->stats_timer, +			    bfa_iocfc_stats_clr_timeout, bfa, +			    BFA_IOCFC_TOV); + +	bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ, +		bfa_lpuid(bfa)); +	bfa_ioc_mbox_send(&bfa->ioc, &stats_req, +		sizeof(struct bfi_iocfc_stats_req_s)); +} + +static void +bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s) +{ +	u32       *dip = (u32 *) d; +	u32       *sip = (u32 *) s; +	int             i; + +	for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++) +		dip[i] = bfa_os_ntohl(sip[i]); +} + +static void +bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete) +{ +	struct bfa_s *bfa = bfa_arg; +	struct bfa_iocfc_s *iocfc = &bfa->iocfc; + +	if (complete) { +		bfa_ioc_clr_stats(&bfa->ioc); +		iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); +	} else { +		iocfc->stats_busy = BFA_FALSE; +		iocfc->stats_status = BFA_STATUS_OK; +	} +} + +static void +bfa_iocfc_stats_clr_timeout(void *bfa_arg) +{ +	struct bfa_s		*bfa = bfa_arg; +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	bfa_trc(bfa, 0); + +	iocfc->stats_status = BFA_STATUS_ETIMER; +	bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa); +} + +static void +bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete) +{ +	struct bfa_s		*bfa = bfa_arg; +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	if (complete) { +		if (iocfc->stats_status == BFA_STATUS_OK) { +			bfa_os_memset(iocfc->stats_ret, 0, +				sizeof(*iocfc->stats_ret)); +			bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats, +				iocfc->fw_stats); +		} +		iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status); +	} else { +		iocfc->stats_busy = BFA_FALSE; +		iocfc->stats_status = BFA_STATUS_OK; +	} +} + +static void +bfa_iocfc_stats_timeout(void *bfa_arg) +{ +	struct bfa_s		*bfa = bfa_arg; +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	bfa_trc(bfa, 0); + +	iocfc->stats_status = BFA_STATUS_ETIMER; +	bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa); +} + +static void +bfa_iocfc_stats_query(struct bfa_s *bfa) +{ +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; +	struct bfi_iocfc_stats_req_s stats_req; + +	bfa_timer_start(bfa, &iocfc->stats_timer, +			    bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV); + +	bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ, +			bfa_lpuid(bfa)); +	bfa_ioc_mbox_send(&bfa->ioc, &stats_req, +		sizeof(struct bfi_iocfc_stats_req_s)); +} + +void +bfa_iocfc_reset_queues(struct bfa_s *bfa) +{ +	int             q; + +	for (q = 0; q < BFI_IOC_MAX_CQS; q++) { +		bfa_reqq_ci(bfa, q) = 0; +		bfa_reqq_pi(bfa, q) = 0; +		bfa_rspq_ci(bfa, q) = 0; +		bfa_rspq_pi(bfa, q) = 0; +	} +} + +/** + * IOC enable request is complete + */ +static void +bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) +{ +	struct bfa_s	*bfa = bfa_arg; + +	if (status != BFA_STATUS_OK) { +		bfa_isr_disable(bfa); +		if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) +			bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, +				     bfa_iocfc_init_cb, bfa); +		return; +	} + +	bfa_iocfc_initdone_submod(bfa); +	bfa_iocfc_send_cfg(bfa); +} + +/** + * IOC disable request is complete + */ +static void +bfa_iocfc_disable_cbfn(void *bfa_arg) +{ +	struct bfa_s	*bfa = bfa_arg; + +	bfa_isr_disable(bfa); +	bfa_iocfc_disable_submod(bfa); + +	if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP) +		bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb, +			     bfa); +	else { +		bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE); +		bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb, +			     bfa); +	} +} + +/** + * Notify sub-modules of hardware failure. + */ +static void +bfa_iocfc_hbfail_cbfn(void *bfa_arg) +{ +	struct bfa_s	*bfa = bfa_arg; + +	bfa->rme_process = BFA_FALSE; + +	bfa_isr_disable(bfa); +	bfa_iocfc_disable_submod(bfa); + +	if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT) +		bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb, +			     bfa); +} + +/** + * Actions on chip-reset completion. + */ +static void +bfa_iocfc_reset_cbfn(void *bfa_arg) +{ +	struct bfa_s	*bfa = bfa_arg; + +	bfa_iocfc_reset_queues(bfa); +	bfa_isr_enable(bfa); +} + + + +/** + *  bfa_ioc_public + */ + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len) +{ +	/* dma memory for IOC */ +	*dm_len += bfa_ioc_meminfo(); + +	bfa_iocfc_fw_cfg_sz(cfg, dm_len); +	bfa_iocfc_cqs_sz(cfg, dm_len); +	*km_len += bfa_ioc_debug_trcsz(bfa_auto_recover); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		   struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	int             i; + +	bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn; +	bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn; +	bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn; +	bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn; + +	bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod, +		bfa->trcmod, bfa->aen, bfa->logm); +	bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC); +	bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); + +	/** +	 * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode. +	 */ +	if (0) +		bfa_ioc_set_fcmode(&bfa->ioc); + +	bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); +	bfa_iocfc_mem_claim(bfa, cfg, meminfo); +	bfa_timer_init(&bfa->timer_mod); + +	INIT_LIST_HEAD(&bfa->comp_q); +	for (i = 0; i < BFI_IOC_MAX_CQS; i++) +		INIT_LIST_HEAD(&bfa->reqq_waitq[i]); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_detach(struct bfa_s *bfa) +{ +	bfa_ioc_detach(&bfa->ioc); +} + +/** + * Query IOC memory requirement information. + */ +void +bfa_iocfc_init(struct bfa_s *bfa) +{ +	bfa->iocfc.action = BFA_IOCFC_ACT_INIT; +	bfa_ioc_enable(&bfa->ioc); +	bfa_msix_install(bfa); +} + +/** + * IOC start called from bfa_start(). Called to start IOC operations + * at driver instantiation for this instance. + */ +void +bfa_iocfc_start(struct bfa_s *bfa) +{ +	if (bfa->iocfc.cfgdone) +		bfa_iocfc_start_submod(bfa); +} + +/** + * IOC stop called from bfa_stop(). Called only when driver is unloaded + * for this instance. + */ +void +bfa_iocfc_stop(struct bfa_s *bfa) +{ +	bfa->iocfc.action = BFA_IOCFC_ACT_STOP; + +	bfa->rme_process = BFA_FALSE; +	bfa_ioc_disable(&bfa->ioc); +} + +void +bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) +{ +	struct bfa_s		*bfa = bfaarg; +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; +	union bfi_iocfc_i2h_msg_u	*msg; + +	msg = (union bfi_iocfc_i2h_msg_u *) m; +	bfa_trc(bfa, msg->mh.msg_id); + +	switch (msg->mh.msg_id) { +	case BFI_IOCFC_I2H_CFG_REPLY: +		iocfc->cfg_reply = &msg->cfg_reply; +		bfa_iocfc_cfgrsp(bfa); +		break; + +	case BFI_IOCFC_I2H_GET_STATS_RSP: +		if (iocfc->stats_busy == BFA_FALSE +		    || iocfc->stats_status == BFA_STATUS_ETIMER) +			break; + +		bfa_timer_stop(&iocfc->stats_timer); +		iocfc->stats_status = BFA_STATUS_OK; +		bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, +			      bfa); +		break; +	case BFI_IOCFC_I2H_CLEAR_STATS_RSP: +		/* +		 * check for timer pop before processing the rsp +		 */ +		if (iocfc->stats_busy == BFA_FALSE +		    || iocfc->stats_status == BFA_STATUS_ETIMER) +			break; + +		bfa_timer_stop(&iocfc->stats_timer); +		iocfc->stats_status = BFA_STATUS_OK; +		bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, +			      bfa_iocfc_stats_clr_cb, bfa); +		break; +	case BFI_IOCFC_I2H_UPDATEQ_RSP: +		iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); +		break; +	default: +		bfa_assert(0); +	} +} + +#ifndef BFA_BIOS_BUILD +void +bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr) +{ +	bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr); +} + +u64 +bfa_adapter_get_id(struct bfa_s *bfa) +{ +	return bfa_ioc_get_adid(&bfa->ioc); +} + +void +bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) +{ +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	attr->intr_attr = iocfc->cfginfo->intr_attr; +	attr->config	= iocfc->cfg; +} + +bfa_status_t +bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) +{ +	struct bfa_iocfc_s		*iocfc = &bfa->iocfc; +	struct bfi_iocfc_set_intr_req_s *m; + +	iocfc->cfginfo->intr_attr = *attr; +	if (!bfa_iocfc_is_operational(bfa)) +		return BFA_STATUS_OK; + +	m = bfa_reqq_next(bfa, BFA_REQQ_IOC); +	if (!m) +		return BFA_STATUS_DEVBUSY; + +	bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, +			bfa_lpuid(bfa)); +	m->coalesce = attr->coalesce; +	m->delay    = bfa_os_htons(attr->delay); +	m->latency  = bfa_os_htons(attr->latency); + +	bfa_trc(bfa, attr->delay); +	bfa_trc(bfa, attr->latency); + +	bfa_reqq_produce(bfa, BFA_REQQ_IOC); +	return BFA_STATUS_OK; +} + +void +bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa) +{ +	struct bfa_iocfc_s      *iocfc = &bfa->iocfc; + +	iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); +	bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa); +} + +bfa_status_t +bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats, +		      bfa_cb_ioc_t cbfn, void *cbarg) +{ +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	if (iocfc->stats_busy) { +		bfa_trc(bfa, iocfc->stats_busy); +		return (BFA_STATUS_DEVBUSY); +	} + +	iocfc->stats_busy = BFA_TRUE; +	iocfc->stats_ret = stats; +	iocfc->stats_cbfn = cbfn; +	iocfc->stats_cbarg = cbarg; + +	bfa_iocfc_stats_query(bfa); + +	return (BFA_STATUS_OK); +} + +bfa_status_t +bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg) +{ +	struct bfa_iocfc_s	*iocfc = &bfa->iocfc; + +	if (iocfc->stats_busy) { +		bfa_trc(bfa, iocfc->stats_busy); +		return (BFA_STATUS_DEVBUSY); +	} + +	iocfc->stats_busy = BFA_TRUE; +	iocfc->stats_cbfn = cbfn; +	iocfc->stats_cbarg = cbarg; + +	bfa_iocfc_stats_clear(bfa); +	return (BFA_STATUS_OK); +} + +/** + * Enable IOC after it is disabled. + */ +void +bfa_iocfc_enable(struct bfa_s *bfa) +{ +	bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, +		     "IOC Enable"); +	bfa_ioc_enable(&bfa->ioc); +} + +void +bfa_iocfc_disable(struct bfa_s *bfa) +{ +	bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, +		     "IOC Disable"); +	bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE; + +	bfa->rme_process = BFA_FALSE; +	bfa_ioc_disable(&bfa->ioc); +} + + +bfa_boolean_t +bfa_iocfc_is_operational(struct bfa_s *bfa) +{ +	return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone; +} + +/** + * Return boot target port wwns -- read from boot information in flash. + */ +void +bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns) +{ +	struct bfa_iocfc_s		*iocfc	 = &bfa->iocfc; +	struct bfi_iocfc_cfgrsp_s	*cfgrsp  = iocfc->cfgrsp; + +	*nwwns = cfgrsp->bootwwns.nwwns; +	*wwns = cfgrsp->bootwwns.wwn; +} + +#endif + + diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h new file mode 100644 index 00000000000..7ad177ed4cf --- /dev/null +++ b/drivers/scsi/bfa/bfa_iocfc.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_IOCFC_H__ +#define __BFA_IOCFC_H__ + +#include <bfa_ioc.h> +#include <bfa.h> +#include <bfi/bfi_iocfc.h> +#include <bfa_callback_priv.h> + +#define BFA_REQQ_NELEMS_MIN	(4) +#define BFA_RSPQ_NELEMS_MIN	(4) + +struct bfa_iocfc_regs_s { +	bfa_os_addr_t   intr_status; +	bfa_os_addr_t   intr_mask; +	bfa_os_addr_t   cpe_q_pi[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   cpe_q_ci[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   cpe_q_depth[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   cpe_q_ctrl[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   rme_q_ci[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   rme_q_pi[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   rme_q_depth[BFI_IOC_MAX_CQS]; +	bfa_os_addr_t   rme_q_ctrl[BFI_IOC_MAX_CQS]; +}; + +/** + * MSIX vector handlers + */ +#define BFA_MSIX_MAX_VECTORS	22 +typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec); +struct bfa_msix_s { +	int	nvecs; +	bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS]; +}; + +/** + * Chip specific interfaces + */ +struct bfa_hwif_s { +	void (*hw_reginit)(struct bfa_s *bfa); +	void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq); +	void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); +	void (*hw_msix_install)(struct bfa_s *bfa); +	void (*hw_msix_uninstall)(struct bfa_s *bfa); +	void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); +	void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, +			u32 *nvecs, u32 *maxvec); +}; +typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status); + +struct bfa_iocfc_s { +	struct bfa_s 		*bfa; +	struct bfa_iocfc_cfg_s 	cfg; +	int			action; + +	u32        	req_cq_pi[BFI_IOC_MAX_CQS]; +	u32        	rsp_cq_ci[BFI_IOC_MAX_CQS]; + +	struct bfa_cb_qe_s	init_hcb_qe; +	struct bfa_cb_qe_s	stop_hcb_qe; +	struct bfa_cb_qe_s	dis_hcb_qe; +	struct bfa_cb_qe_s	stats_hcb_qe; +	bfa_boolean_t		cfgdone; + +	struct bfa_dma_s	cfg_info; +	struct bfi_iocfc_cfg_s *cfginfo; +	struct bfa_dma_s	cfgrsp_dma; +	struct bfi_iocfc_cfgrsp_s *cfgrsp; +	struct bfi_iocfc_cfg_reply_s *cfg_reply; + +	u8			*stats_kva; +	u64		stats_pa; +	struct bfa_fw_stats_s 	*fw_stats; +	struct bfa_timer_s 	stats_timer;	/*  timer */ +	struct bfa_iocfc_stats_s *stats_ret;	/*  driver stats location */ +	bfa_status_t		stats_status;	/*  stats/statsclr status */ +	bfa_boolean_t   	stats_busy;	/*  outstanding stats */ +	bfa_cb_ioc_t		stats_cbfn;	/*  driver callback function */ +	void           		*stats_cbarg;	/*  user callback arg */ + +	struct bfa_dma_s   	req_cq_ba[BFI_IOC_MAX_CQS]; +	struct bfa_dma_s   	req_cq_shadow_ci[BFI_IOC_MAX_CQS]; +	struct bfa_dma_s   	rsp_cq_ba[BFI_IOC_MAX_CQS]; +	struct bfa_dma_s   	rsp_cq_shadow_pi[BFI_IOC_MAX_CQS]; +	struct bfa_iocfc_regs_s	bfa_regs;	/*  BFA device registers */ +	struct bfa_hwif_s	hwif; + +	bfa_cb_iocfc_t		updateq_cbfn; /*  bios callback function */ +	void				*updateq_cbarg;	/*  bios callback arg */ +}; + +#define bfa_lpuid(__bfa)		bfa_ioc_portid(&(__bfa)->ioc) +#define bfa_msix_init(__bfa, __nvecs)	\ +	(__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs) +#define bfa_msix_install(__bfa)	\ +	(__bfa)->iocfc.hwif.hw_msix_install(__bfa) +#define bfa_msix_uninstall(__bfa)	\ +	(__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa) +#define bfa_isr_mode_set(__bfa, __msix)	\ +	(__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix) +#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)	\ +	(__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) + +/* + * FC specific IOC functions. + */ +void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len); +void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, +		struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, +		struct bfa_pcidev_s *pcidev); +void bfa_iocfc_detach(struct bfa_s *bfa); +void bfa_iocfc_init(struct bfa_s *bfa); +void bfa_iocfc_start(struct bfa_s *bfa); +void bfa_iocfc_stop(struct bfa_s *bfa); +void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); +void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa); +bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); +void bfa_iocfc_reset_queues(struct bfa_s *bfa); +void bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba, +			u32 reqq_sci, u32 rspq_spi, +			bfa_cb_iocfc_t cbfn, void *cbarg); + +void bfa_msix_all(struct bfa_s *bfa, int vec); +void bfa_msix_reqq(struct bfa_s *bfa, int vec); +void bfa_msix_rspq(struct bfa_s *bfa, int vec); +void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); + +void bfa_hwcb_reginit(struct bfa_s *bfa); +void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq); +void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); +void bfa_hwcb_msix_install(struct bfa_s *bfa); +void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); +void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); +void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, +			u32 *nvecs, u32 *maxvec); +void bfa_hwct_reginit(struct bfa_s *bfa); +void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq); +void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); +void bfa_hwct_msix_install(struct bfa_s *bfa); +void bfa_hwct_msix_uninstall(struct bfa_s *bfa); +void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); +void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, +			u32 *nvecs, u32 *maxvec); + +void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len); +void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi, +		bfa_boolean_t mincfg); +void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns); + +#endif /* __BFA_IOCFC_H__ */ + diff --git a/drivers/scsi/bfa/bfa_iocfc_q.c b/drivers/scsi/bfa/bfa_iocfc_q.c new file mode 100644 index 00000000000..500a17df40b --- /dev/null +++ b/drivers/scsi/bfa/bfa_iocfc_q.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include "bfa_intr_priv.h" + +BFA_TRC_FILE(HAL, IOCFC_Q); + +void +bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba, +				u32 reqq_sci, u32 rspq_spi, bfa_cb_iocfc_t cbfn, +				void *cbarg) +{ +	struct bfa_iocfc_s *iocfc = &bfa->iocfc; +	struct bfi_iocfc_updateq_req_s updateq_req; + +	iocfc->updateq_cbfn = cbfn; +	iocfc->updateq_cbarg = cbarg; + +	bfi_h2i_set(updateq_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_UPDATEQ_REQ, +			bfa_lpuid(bfa)); + +	updateq_req.reqq_ba = bfa_os_htonl(reqq_ba); +	updateq_req.rspq_ba = bfa_os_htonl(rspq_ba); +	updateq_req.reqq_sci = bfa_os_htonl(reqq_sci); +	updateq_req.rspq_spi = bfa_os_htonl(rspq_spi); + +	bfa_ioc_mbox_send(&bfa->ioc, &updateq_req, +			sizeof(struct bfi_iocfc_updateq_req_s)); +} diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c new file mode 100644 index 00000000000..7ae2552e1e1 --- /dev/null +++ b/drivers/scsi/bfa/bfa_ioim.c @@ -0,0 +1,1311 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <cs/bfa_debug.h> +#include <bfa_cb_ioim_macros.h> + +BFA_TRC_FILE(HAL, IOIM); + +/* + * forward declarations. + */ +static bfa_boolean_t	bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim); +static bfa_boolean_t	bfa_ioim_sge_setup(struct bfa_ioim_s *ioim); +static void		bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim); +static bfa_boolean_t	bfa_ioim_send_abort(struct bfa_ioim_s *ioim); +static void		bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim); +static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); + +/** + *  bfa_ioim_sm + */ + +/** + * IO state machine events + */ +enum bfa_ioim_event { +	BFA_IOIM_SM_START = 1,		/*  io start request from host */ +	BFA_IOIM_SM_COMP_GOOD = 2,	/*  io good comp, resource free */ +	BFA_IOIM_SM_COMP = 3,		/*  io comp, resource is free */ +	BFA_IOIM_SM_COMP_UTAG = 4,	/*  io comp, resource is free */ +	BFA_IOIM_SM_DONE = 5,		/*  io comp, resource not free */ +	BFA_IOIM_SM_FREE = 6,		/*  io resource is freed */ +	BFA_IOIM_SM_ABORT = 7,		/*  abort request from scsi stack */ +	BFA_IOIM_SM_ABORT_COMP = 8,	/*  abort from f/w */ +	BFA_IOIM_SM_ABORT_DONE = 9,	/*  abort completion from f/w */ +	BFA_IOIM_SM_QRESUME = 10,	/*  CQ space available to queue IO */ +	BFA_IOIM_SM_SGALLOCED = 11,	/*  SG page allocation successful */ +	BFA_IOIM_SM_SQRETRY = 12,	/*  sequence recovery retry */ +	BFA_IOIM_SM_HCB	= 13,		/*  bfa callback complete */ +	BFA_IOIM_SM_CLEANUP = 14,	/*  IO cleanup from itnim */ +	BFA_IOIM_SM_TMSTART = 15,	/*  IO cleanup from tskim */ +	BFA_IOIM_SM_TMDONE = 16,	/*  IO cleanup from tskim */ +	BFA_IOIM_SM_HWFAIL = 17,	/*  IOC h/w failure event */ +	BFA_IOIM_SM_IOTOV = 18,		/*  ITN offline TOV       */ +}; + +/* + * forward declaration of IO state machine + */ +static void     bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, +				       enum bfa_ioim_event event); +static void     bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, +					enum bfa_ioim_event event); +static void     bfa_ioim_sm_active(struct bfa_ioim_s *ioim, +				       enum bfa_ioim_event event); +static void     bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, +				      enum bfa_ioim_event event); +static void     bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, +					enum bfa_ioim_event event); +static void     bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, +				      enum bfa_ioim_event event); +static void     bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, +					    enum bfa_ioim_event event); +static void     bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, +					      enum bfa_ioim_event event); +static void     bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, +				    enum bfa_ioim_event event); +static void     bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, +					 enum bfa_ioim_event event); +static void     bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, +					enum bfa_ioim_event event); + +/** + * 		IO is not started (unallocated). + */ +static void +bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_trc_fp(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_START: +		if (!bfa_itnim_is_online(ioim->itnim)) { +			if (!bfa_itnim_hold_io(ioim->itnim)) { +				bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +				list_del(&ioim->qe); +				list_add_tail(&ioim->qe, +					&ioim->fcpim->ioim_comp_q); +				bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, +						__bfa_cb_ioim_pathtov, ioim); +			} else { +				list_del(&ioim->qe); +				list_add_tail(&ioim->qe, +					&ioim->itnim->pending_q); +			} +			break; +		} + +		if (ioim->nsges > BFI_SGE_INLINE) { +			if (!bfa_ioim_sge_setup(ioim)) { +				bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc); +				return; +			} +		} + +		if (!bfa_ioim_send_ioreq(ioim)) { +			bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); +			break; +		} + +		bfa_sm_set_state(ioim, bfa_ioim_sm_active); +		break; + +	case BFA_IOIM_SM_IOTOV: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, +				__bfa_cb_ioim_pathtov, ioim); +		break; + +	case BFA_IOIM_SM_ABORT: +		/** +		 * IO in pending queue can get abort requests. Complete abort +		 * requests immediately. +		 */ +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim)); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +				ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		IO is waiting for SG pages. + */ +static void +bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_SGALLOCED: +		if (!bfa_ioim_send_ioreq(ioim)) { +			bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); +			break; +		} +		bfa_sm_set_state(ioim, bfa_ioim_sm_active); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_ABORT: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		IO is active. + */ +static void +bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_trc_fp(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_COMP_GOOD: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, +			      __bfa_cb_ioim_good_comp, ioim); +		break; + +	case BFA_IOIM_SM_COMP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, +			      ioim); +		break; + +	case BFA_IOIM_SM_DONE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, +			      ioim); +		break; + +	case BFA_IOIM_SM_ABORT: +		ioim->iosp->abort_explicit = BFA_TRUE; +		ioim->io_cbfn = __bfa_cb_ioim_abort; + +		if (bfa_ioim_send_abort(ioim)) +			bfa_sm_set_state(ioim, bfa_ioim_sm_abort); +		else { +			bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull); +			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, +					  &ioim->iosp->reqq_wait); +		} +		break; + +	case BFA_IOIM_SM_CLEANUP: +		ioim->iosp->abort_explicit = BFA_FALSE; +		ioim->io_cbfn = __bfa_cb_ioim_failed; + +		if (bfa_ioim_send_abort(ioim)) +			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); +		else { +			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); +			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, +					  &ioim->iosp->reqq_wait); +		} +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		IO is being aborted, waiting for completion from firmware. + */ +static void +bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_COMP_GOOD: +	case BFA_IOIM_SM_COMP: +	case BFA_IOIM_SM_DONE: +	case BFA_IOIM_SM_FREE: +		break; + +	case BFA_IOIM_SM_ABORT_DONE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_ABORT_COMP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_COMP_UTAG: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); +		ioim->iosp->abort_explicit = BFA_FALSE; + +		if (bfa_ioim_send_abort(ioim)) +			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); +		else { +			bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); +			bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, +					  &ioim->iosp->reqq_wait); +		} +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * IO is being cleaned up (implicit abort), waiting for completion from + * firmware. + */ +static void +bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_COMP_GOOD: +	case BFA_IOIM_SM_COMP: +	case BFA_IOIM_SM_DONE: +	case BFA_IOIM_SM_FREE: +		break; + +	case BFA_IOIM_SM_ABORT: +		/** +		 * IO is already being aborted implicitly +		 */ +		ioim->io_cbfn = __bfa_cb_ioim_abort; +		break; + +	case BFA_IOIM_SM_ABORT_DONE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_ABORT_COMP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_COMP_UTAG: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		/** +		 * IO can be in cleanup state already due to TM command. 2nd cleanup +		 * request comes from ITN offline event. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		IO is waiting for room in request CQ + */ +static void +bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_QRESUME: +		bfa_sm_set_state(ioim, bfa_ioim_sm_active); +		bfa_ioim_send_ioreq(ioim); +		break; + +	case BFA_IOIM_SM_ABORT: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Active IO is being aborted, waiting for room in request CQ. + */ +static void +bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_QRESUME: +		bfa_sm_set_state(ioim, bfa_ioim_sm_abort); +		bfa_ioim_send_abort(ioim); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE); +		ioim->iosp->abort_explicit = BFA_FALSE; +		bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); +		break; + +	case BFA_IOIM_SM_COMP_GOOD: +	case BFA_IOIM_SM_COMP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_DONE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, +			      ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Active IO is being cleaned up, waiting for room in request CQ. + */ +static void +bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_QRESUME: +		bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); +		bfa_ioim_send_abort(ioim); +		break; + +	case BFA_IOIM_SM_ABORT: +		/** +		 * IO is alraedy being cleaned up implicitly +		 */ +		ioim->io_cbfn = __bfa_cb_ioim_abort; +		break; + +	case BFA_IOIM_SM_COMP_GOOD: +	case BFA_IOIM_SM_COMP: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_DONE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		bfa_reqq_wcancel(&ioim->iosp->reqq_wait); +		bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, +			      ioim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * IO bfa callback is pending. + */ +static void +bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_trc_fp(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_HCB: +		bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); +		bfa_ioim_free(ioim); +		bfa_cb_ioim_resfree(ioim->bfa->bfad); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * IO bfa callback is pending. IO resource cannot be freed. + */ +static void +bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_HCB: +		bfa_sm_set_state(ioim, bfa_ioim_sm_resfree); +		list_del(&ioim->qe); +		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q); +		break; + +	case BFA_IOIM_SM_FREE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * IO is completed, waiting resource free from firmware. + */ +static void +bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, event); + +	switch (event) { +	case BFA_IOIM_SM_FREE: +		bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); +		bfa_ioim_free(ioim); +		bfa_cb_ioim_resfree(ioim->bfa->bfad); +		break; + +	case BFA_IOIM_SM_CLEANUP: +		bfa_ioim_notify_cleanup(ioim); +		break; + +	case BFA_IOIM_SM_HWFAIL: +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  bfa_ioim_private + */ + +static void +__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); +		return; +	} + +	bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio); +} + +static void +__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_ioim_s	*ioim = cbarg; +	struct bfi_ioim_rsp_s *m; +	u8		*snsinfo = NULL; +	u8         sns_len = 0; +	s32         residue = 0; + +	if (!complete) { +		bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); +		return; +	} + +	m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; +	if (m->io_status == BFI_IOIM_STS_OK) { +		/** +		 * setup sense information, if present +		 */ +		if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION +					&& m->sns_len) { +			sns_len = m->sns_len; +			snsinfo = ioim->iosp->snsinfo; +		} + +		/** +		 * setup residue value correctly for normal completions +		 */ +		if (m->resid_flags == FCP_RESID_UNDER) +			residue = bfa_os_ntohl(m->residue); +		if (m->resid_flags == FCP_RESID_OVER) { +			residue = bfa_os_ntohl(m->residue); +			residue = -residue; +		} +	} + +	bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status, +			  m->scsi_status, sns_len, snsinfo, residue); +} + +static void +__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); +		return; +	} + +	bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, +			  0, 0, NULL, 0); +} + +static void +__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); +		return; +	} + +	bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, +			  0, 0, NULL, 0); +} + +static void +__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); +		return; +	} + +	bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); +} + +static void +bfa_ioim_sgpg_alloced(void *cbarg) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); +	list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q); +	bfa_ioim_sgpg_setup(ioim); +	bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED); +} + +/** + * Send I/O request to firmware. + */ +static          bfa_boolean_t +bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) +{ +	struct bfa_itnim_s *itnim = ioim->itnim; +	struct bfi_ioim_req_s *m; +	static struct fcp_cmnd_s cmnd_z0 = { 0 }; +	struct bfi_sge_s      *sge; +	u32        pgdlen = 0; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(ioim->bfa, itnim->reqq); +	if (!m) { +		bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, +				  &ioim->iosp->reqq_wait); +		return BFA_FALSE; +	} + +	/** +	 * build i/o request message next +	 */ +	m->io_tag = bfa_os_htons(ioim->iotag); +	m->rport_hdl = ioim->itnim->rport->fw_handle; +	m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio); + +	/** +	 * build inline IO SG element here +	 */ +	sge = &m->sges[0]; +	if (ioim->nsges) { +		sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0); +		pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0); +		sge->sg_len = pgdlen; +		sge->flags = (ioim->nsges > BFI_SGE_INLINE) ? +					BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST; +		bfa_sge_to_be(sge); +		sge++; +	} + +	if (ioim->nsges > BFI_SGE_INLINE) { +		sge->sga = ioim->sgpg->sgpg_pa; +	} else { +		sge->sga.a32.addr_lo = 0; +		sge->sga.a32.addr_hi = 0; +	} +	sge->sg_len = pgdlen; +	sge->flags = BFI_SGE_PGDLEN; +	bfa_sge_to_be(sge); + +	/** +	 * set up I/O command parameters +	 */ +	bfa_os_assign(m->cmnd, cmnd_z0); +	m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio); +	m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio); +	bfa_os_assign(m->cmnd.cdb, +			*(struct scsi_cdb_s *)bfa_cb_ioim_get_cdb(ioim->dio)); +	m->cmnd.fcp_dl = bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio)); + +	/** +	 * set up I/O message header +	 */ +	switch (m->cmnd.iodir) { +	case FCP_IODIR_READ: +		bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa)); +		bfa_stats(itnim, input_reqs); +		break; +	case FCP_IODIR_WRITE: +		bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa)); +		bfa_stats(itnim, output_reqs); +		break; +	case FCP_IODIR_RW: +		bfa_stats(itnim, input_reqs); +		bfa_stats(itnim, output_reqs); +	default: +		bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); +	} +	if (itnim->seq_rec || +	    (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1))) +		bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa)); + +#ifdef IOIM_ADVANCED +	m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio); +	m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio); +	m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio); + +	/** +	 * Handle large CDB (>16 bytes). +	 */ +	m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) - +					FCP_CMND_CDB_LEN) / sizeof(u32); +	if (m->cmnd.addl_cdb_len) { +		bfa_os_memcpy(&m->cmnd.cdb + 1, (struct scsi_cdb_s *) +				bfa_cb_ioim_get_cdb(ioim->dio) + 1, +				m->cmnd.addl_cdb_len * sizeof(u32)); +		fcp_cmnd_fcpdl(&m->cmnd) = +				bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio)); +	} +#endif + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(ioim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +/** + * Setup any additional SG pages needed.Inline SG element is setup + * at queuing time. + */ +static bfa_boolean_t +bfa_ioim_sge_setup(struct bfa_ioim_s *ioim) +{ +	u16        nsgpgs; + +	bfa_assert(ioim->nsges > BFI_SGE_INLINE); + +	/** +	 * allocate SG pages needed +	 */ +	nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); +	if (!nsgpgs) +		return BFA_TRUE; + +	if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs) +	    != BFA_STATUS_OK) { +		bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs); +		return BFA_FALSE; +	} + +	ioim->nsgpgs = nsgpgs; +	bfa_ioim_sgpg_setup(ioim); + +	return BFA_TRUE; +} + +static void +bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim) +{ +	int             sgeid, nsges, i; +	struct bfi_sge_s      *sge; +	struct bfa_sgpg_s *sgpg; +	u32        pgcumsz; + +	sgeid = BFI_SGE_INLINE; +	ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q); + +	do { +		sge = sgpg->sgpg->sges; +		nsges = ioim->nsges - sgeid; +		if (nsges > BFI_SGPG_DATA_SGES) +			nsges = BFI_SGPG_DATA_SGES; + +		pgcumsz = 0; +		for (i = 0; i < nsges; i++, sge++, sgeid++) { +			sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid); +			sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid); +			pgcumsz += sge->sg_len; + +			/** +			 * set flags +			 */ +			if (i < (nsges - 1)) +				sge->flags = BFI_SGE_DATA; +			else if (sgeid < (ioim->nsges - 1)) +				sge->flags = BFI_SGE_DATA_CPL; +			else +				sge->flags = BFI_SGE_DATA_LAST; +		} + +		sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg); + +		/** +		 * set the link element of each page +		 */ +		if (sgeid == ioim->nsges) { +			sge->flags = BFI_SGE_PGDLEN; +			sge->sga.a32.addr_lo = 0; +			sge->sga.a32.addr_hi = 0; +		} else { +			sge->flags = BFI_SGE_LINK; +			sge->sga = sgpg->sgpg_pa; +		} +		sge->sg_len = pgcumsz; +	} while (sgeid < ioim->nsges); +} + +/** + * Send I/O abort request to firmware. + */ +static          bfa_boolean_t +bfa_ioim_send_abort(struct bfa_ioim_s *ioim) +{ +	struct bfa_itnim_s          *itnim = ioim->itnim; +	struct bfi_ioim_abort_req_s *m; +	enum bfi_ioim_h2i       msgop; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(ioim->bfa, itnim->reqq); +	if (!m) +		return BFA_FALSE; + +	/** +	 * build i/o request message next +	 */ +	if (ioim->iosp->abort_explicit) +		msgop = BFI_IOIM_H2I_IOABORT_REQ; +	else +		msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; + +	bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa)); +	m->io_tag    = bfa_os_htons(ioim->iotag); +	m->abort_tag = ++ioim->abort_tag; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(ioim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +/** + * Call to resume any I/O requests waiting for room in request queue. + */ +static void +bfa_ioim_qresume(void *cbarg) +{ +	struct bfa_ioim_s *ioim = cbarg; + +	bfa_fcpim_stats(ioim->fcpim, qresumes); +	bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME); +} + + +static void +bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim) +{ +	/** +	 * Move IO from itnim queue to fcpim global queue since itnim will be +	 * freed. +	 */ +	list_del(&ioim->qe); +	list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); + +	if (!ioim->iosp->tskim) { +		if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) { +			bfa_cb_dequeue(&ioim->hcb_qe); +			list_del(&ioim->qe); +			list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q); +		} +		bfa_itnim_iodone(ioim->itnim); +	} else +		bfa_tskim_iodone(ioim->iosp->tskim); +} + +/** + * 		  or after the link comes back. + */ +void +bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) +{ +	/** +	 * If path tov timer expired, failback with PATHTOV status - these +	 * IO requests are not normally retried by IO stack. +	 * +	 * Otherwise device cameback online and fail it with normal failed +	 * status so that IO stack retries these failed IO requests. +	 */ +	if (iotov) +		ioim->io_cbfn = __bfa_cb_ioim_pathtov; +	else +		ioim->io_cbfn = __bfa_cb_ioim_failed; + +	bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); + +    /** +     * Move IO to fcpim global queue since itnim will be +     * freed. +     */ +    list_del(&ioim->qe); +    list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); +} + + + +/** + *  bfa_ioim_friend + */ + +/** + * Memory allocation and initialization. + */ +void +bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ +	struct bfa_ioim_s		*ioim; +	struct bfa_ioim_sp_s	*iosp; +	u16		i; +	u8			*snsinfo; +	u32		snsbufsz; + +	/** +	 * claim memory first +	 */ +	ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo); +	fcpim->ioim_arr = ioim; +	bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs); + +	iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo); +	fcpim->ioim_sp_arr = iosp; +	bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs); + +	/** +	 * Claim DMA memory for per IO sense data. +	 */ +	snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN; +	fcpim->snsbase.pa  = bfa_meminfo_dma_phys(minfo); +	bfa_meminfo_dma_phys(minfo) += snsbufsz; + +	fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo); +	bfa_meminfo_dma_virt(minfo) += snsbufsz; +	snsinfo = fcpim->snsbase.kva; +	bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa); + +	/** +	 * Initialize ioim free queues +	 */ +	INIT_LIST_HEAD(&fcpim->ioim_free_q); +	INIT_LIST_HEAD(&fcpim->ioim_resfree_q); +	INIT_LIST_HEAD(&fcpim->ioim_comp_q); + +	for (i = 0; i < fcpim->num_ioim_reqs; +	     i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) { +		/* +		 * initialize IOIM +		 */ +		bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s)); +		ioim->iotag   = i; +		ioim->bfa     = fcpim->bfa; +		ioim->fcpim   = fcpim; +		ioim->iosp    = iosp; +		iosp->snsinfo = snsinfo; +		INIT_LIST_HEAD(&ioim->sgpg_q); +		bfa_reqq_winit(&ioim->iosp->reqq_wait, +				   bfa_ioim_qresume, ioim); +		bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, +				   bfa_ioim_sgpg_alloced, ioim); +		bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); + +		list_add_tail(&ioim->qe, &fcpim->ioim_free_q); +	} +} + +/** + * Driver detach time call. + */ +void +bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim) +{ +} + +void +bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; +	struct bfa_ioim_s *ioim; +	u16        iotag; +	enum bfa_ioim_event evt = BFA_IOIM_SM_COMP; + +	iotag = bfa_os_ntohs(rsp->io_tag); + +	ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); +	bfa_assert(ioim->iotag == iotag); + +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_trc(ioim->bfa, rsp->io_status); +	bfa_trc(ioim->bfa, rsp->reuse_io_tag); + +	if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active)) +		bfa_os_assign(ioim->iosp->comp_rspmsg, *m); + +	switch (rsp->io_status) { +	case BFI_IOIM_STS_OK: +		bfa_fcpim_stats(fcpim, iocomp_ok); +		if (rsp->reuse_io_tag == 0) +			evt = BFA_IOIM_SM_DONE; +		else +			evt = BFA_IOIM_SM_COMP; +		break; + +	case BFI_IOIM_STS_TIMEDOUT: +	case BFI_IOIM_STS_ABORTED: +		rsp->io_status = BFI_IOIM_STS_ABORTED; +		bfa_fcpim_stats(fcpim, iocomp_aborted); +		if (rsp->reuse_io_tag == 0) +			evt = BFA_IOIM_SM_DONE; +		else +			evt = BFA_IOIM_SM_COMP; +		break; + +	case BFI_IOIM_STS_PROTO_ERR: +		bfa_fcpim_stats(fcpim, iocom_proto_err); +		bfa_assert(rsp->reuse_io_tag); +		evt = BFA_IOIM_SM_COMP; +		break; + +	case BFI_IOIM_STS_SQER_NEEDED: +		bfa_fcpim_stats(fcpim, iocom_sqer_needed); +		bfa_assert(rsp->reuse_io_tag == 0); +		evt = BFA_IOIM_SM_SQRETRY; +		break; + +	case BFI_IOIM_STS_RES_FREE: +		bfa_fcpim_stats(fcpim, iocom_res_free); +		evt = BFA_IOIM_SM_FREE; +		break; + +	case BFI_IOIM_STS_HOST_ABORTED: +		bfa_fcpim_stats(fcpim, iocom_hostabrts); +		if (rsp->abort_tag != ioim->abort_tag) { +			bfa_trc(ioim->bfa, rsp->abort_tag); +			bfa_trc(ioim->bfa, ioim->abort_tag); +			return; +		} + +		if (rsp->reuse_io_tag) +			evt = BFA_IOIM_SM_ABORT_COMP; +		else +			evt = BFA_IOIM_SM_ABORT_DONE; +		break; + +	case BFI_IOIM_STS_UTAG: +		bfa_fcpim_stats(fcpim, iocom_utags); +		evt = BFA_IOIM_SM_COMP_UTAG; +		break; + +	default: +		bfa_assert(0); +	} + +	bfa_sm_send_event(ioim, evt); +} + +void +bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; +	struct bfa_ioim_s *ioim; +	u16        iotag; + +	iotag = bfa_os_ntohs(rsp->io_tag); + +	ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); +	bfa_assert(ioim->iotag == iotag); + +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); +} + +/** + * Called by itnim to clean up IO while going offline. + */ +void +bfa_ioim_cleanup(struct bfa_ioim_s *ioim) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_fcpim_stats(ioim->fcpim, io_cleanups); + +	ioim->iosp->tskim = NULL; +	bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); +} + +void +bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_fcpim_stats(ioim->fcpim, io_tmaborts); + +	ioim->iosp->tskim = tskim; +	bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); +} + +/** + * IOC failure handling. + */ +void +bfa_ioim_iocdisable(struct bfa_ioim_s *ioim) +{ +	bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL); +} + +/** + * IO offline TOV popped. Fail the pending IO. + */ +void +bfa_ioim_tov(struct bfa_ioim_s *ioim) +{ +	bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV); +} + + + +/** + *  bfa_ioim_api + */ + +/** + * Allocate IOIM resource for initiator mode I/O request. + */ +struct bfa_ioim_s * +bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, +		struct bfa_itnim_s *itnim, u16 nsges) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfa_ioim_s *ioim; + +	/** +	 * alocate IOIM resource +	 */ +	bfa_q_deq(&fcpim->ioim_free_q, &ioim); +	if (!ioim) { +		bfa_fcpim_stats(fcpim, no_iotags); +		return NULL; +	} + +	ioim->dio = dio; +	ioim->itnim = itnim; +	ioim->nsges = nsges; +	ioim->nsgpgs = 0; + +	bfa_stats(fcpim, total_ios); +	bfa_stats(itnim, ios); +	fcpim->ios_active++; + +	list_add_tail(&ioim->qe, &itnim->io_q); +	bfa_trc_fp(ioim->bfa, ioim->iotag); + +	return ioim; +} + +void +bfa_ioim_free(struct bfa_ioim_s *ioim) +{ +	struct bfa_fcpim_mod_s *fcpim = ioim->fcpim; + +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit)); + +	bfa_assert_fp(list_empty(&ioim->sgpg_q) +		   || (ioim->nsges > BFI_SGE_INLINE)); + +	if (ioim->nsgpgs > 0) +		bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); + +	bfa_stats(ioim->itnim, io_comps); +	fcpim->ios_active--; + +	list_del(&ioim->qe); +	list_add_tail(&ioim->qe, &fcpim->ioim_free_q); +} + +void +bfa_ioim_start(struct bfa_ioim_s *ioim) +{ +	bfa_trc_fp(ioim->bfa, ioim->iotag); +	bfa_sm_send_event(ioim, BFA_IOIM_SM_START); +} + +/** + * Driver I/O abort request. + */ +void +bfa_ioim_abort(struct bfa_ioim_s *ioim) +{ +	bfa_trc(ioim->bfa, ioim->iotag); +	bfa_fcpim_stats(ioim->fcpim, io_aborts); +	bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT); +} + + diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c new file mode 100644 index 00000000000..4d5c61a4f85 --- /dev/null +++ b/drivers/scsi/bfa/bfa_itnim.c @@ -0,0 +1,1088 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_fcpim.h> +#include "bfa_fcpim_priv.h" + +BFA_TRC_FILE(HAL, ITNIM); + +#define BFA_ITNIM_FROM_TAG(_fcpim, _tag)				\ +	((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1))) + +#define bfa_fcpim_additn(__itnim)					\ +	list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q) +#define bfa_fcpim_delitn(__itnim)	do {				\ +	bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim));      \ +	list_del(&(__itnim)->qe);      \ +	bfa_assert(list_empty(&(__itnim)->io_q));      \ +	bfa_assert(list_empty(&(__itnim)->io_cleanup_q));      \ +	bfa_assert(list_empty(&(__itnim)->pending_q));      \ +} while (0) + +#define bfa_itnim_online_cb(__itnim) do {				\ +	if ((__itnim)->bfa->fcs)					\ +		bfa_cb_itnim_online((__itnim)->ditn);      \ +	else {								\ +		bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe,	\ +		__bfa_cb_itnim_online, (__itnim));      \ +	}								\ +} while (0) + +#define bfa_itnim_offline_cb(__itnim) do {				\ +	if ((__itnim)->bfa->fcs)					\ +		bfa_cb_itnim_offline((__itnim)->ditn);      \ +	else {								\ +		bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe,	\ +		__bfa_cb_itnim_offline, (__itnim));      \ +	}								\ +} while (0) + +#define bfa_itnim_sler_cb(__itnim) do {					\ +	if ((__itnim)->bfa->fcs)					\ +		bfa_cb_itnim_sler((__itnim)->ditn);      \ +	else {								\ +		bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe,	\ +		__bfa_cb_itnim_sler, (__itnim));      \ +	}								\ +} while (0) + +/* + * forward declarations + */ +static void     bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim); +static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim); +static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim); +static void     bfa_itnim_cleanp_comp(void *itnim_cbarg); +static void     bfa_itnim_cleanup(struct bfa_itnim_s *itnim); +static void     __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete); +static void     __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete); +static void     __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete); +static void     bfa_itnim_iotov_online(struct bfa_itnim_s *itnim); +static void     bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim); +static void     bfa_itnim_iotov(void *itnim_arg); +static void     bfa_itnim_iotov_start(struct bfa_itnim_s *itnim); +static void     bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim); +static void     bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim); + +/** + *  bfa_itnim_sm BFA itnim state machine + */ + + +enum bfa_itnim_event { +	BFA_ITNIM_SM_CREATE = 1,	/*  itnim is created */ +	BFA_ITNIM_SM_ONLINE = 2,	/*  itnim is online */ +	BFA_ITNIM_SM_OFFLINE = 3,	/*  itnim is offline */ +	BFA_ITNIM_SM_FWRSP = 4,		/*  firmware response */ +	BFA_ITNIM_SM_DELETE = 5,	/*  deleting an existing itnim */ +	BFA_ITNIM_SM_CLEANUP = 6,	/*  IO cleanup completion */ +	BFA_ITNIM_SM_SLER = 7,		/*  second level error recovery */ +	BFA_ITNIM_SM_HWFAIL = 8,	/*  IOC h/w failure event */ +	BFA_ITNIM_SM_QRESUME = 9,	/*  queue space available */ +}; + +static void     bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, +					enum bfa_itnim_event event); +static void     bfa_itnim_sm_created(struct bfa_itnim_s *itnim, +					 enum bfa_itnim_event event); +static void     bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); +static void	bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, +				enum bfa_itnim_event event); +static void     bfa_itnim_sm_online(struct bfa_itnim_s *itnim, +					enum bfa_itnim_event event); +static void     bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, +				      enum bfa_itnim_event event); +static void     bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, +						 enum bfa_itnim_event event); +static void     bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, +						enum bfa_itnim_event event); +static void     bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); +static void     bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, +					 enum bfa_itnim_event event); +static void     bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, +					    enum bfa_itnim_event event); +static void     bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); +static void     bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); +static void     bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); +static void     bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, +					  enum bfa_itnim_event event); + +/** + * 		Beginning/unallocated state - no events expected. + */ +static void +bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_CREATE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_created); +		itnim->is_online = BFA_FALSE; +		bfa_fcpim_additn(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Beginning state, only online event expected. + */ +static void +bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_ONLINE: +		if (bfa_itnim_send_fwcreate(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_fcpim_delitn(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Waiting for itnim create response from firmware. + */ +static void +bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_FWRSP: +		bfa_sm_set_state(itnim, bfa_itnim_sm_online); +		itnim->is_online = BFA_TRUE; +		bfa_itnim_iotov_online(itnim); +		bfa_itnim_online_cb(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending); +		break; + +	case BFA_ITNIM_SM_OFFLINE: +		if (bfa_itnim_send_fwdelete(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, +			enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_QRESUME: +		bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); +		bfa_itnim_send_fwcreate(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_reqq_wcancel(&itnim->reqq_wait); +		bfa_fcpim_delitn(itnim); +		break; + +	case BFA_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_offline); +		bfa_reqq_wcancel(&itnim->reqq_wait); +		bfa_itnim_offline_cb(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_reqq_wcancel(&itnim->reqq_wait); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 	Waiting for itnim create response from firmware, a delete is pending. + */ +static void +bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, +				enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_FWRSP: +		if (bfa_itnim_send_fwdelete(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_fcpim_delitn(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Online state - normal parking state. + */ +static void +bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); +		itnim->is_online = BFA_FALSE; +		bfa_itnim_iotov_start(itnim); +		bfa_itnim_cleanup(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); +		itnim->is_online = BFA_FALSE; +		bfa_itnim_cleanup(itnim); +		break; + +	case BFA_ITNIM_SM_SLER: +		bfa_sm_set_state(itnim, bfa_itnim_sm_sler); +		itnim->is_online = BFA_FALSE; +		bfa_itnim_iotov_start(itnim); +		bfa_itnim_sler_cb(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		itnim->is_online = BFA_FALSE; +		bfa_itnim_iotov_start(itnim); +		bfa_itnim_iocdisable_cleanup(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Second level error recovery need. + */ +static void +bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); +		bfa_itnim_cleanup(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); +		bfa_itnim_cleanup(itnim); +		bfa_itnim_iotov_delete(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_itnim_iocdisable_cleanup(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Going offline. Waiting for active IO cleanup. + */ +static void +bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, +				 enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_CLEANUP: +		if (bfa_itnim_send_fwdelete(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); +		bfa_itnim_iotov_delete(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_itnim_iocdisable_cleanup(itnim); +		bfa_itnim_offline_cb(itnim); +		break; + +	case BFA_ITNIM_SM_SLER: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Deleting itnim. Waiting for active IO cleanup. + */ +static void +bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, +				enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_CLEANUP: +		if (bfa_itnim_send_fwdelete(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_itnim_iocdisable_cleanup(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Rport offline. Fimrware itnim is being deleted - awaiting f/w response. + */ +static void +bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_FWRSP: +		bfa_sm_set_state(itnim, bfa_itnim_sm_offline); +		bfa_itnim_offline_cb(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_itnim_offline_cb(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, +			enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_QRESUME: +		bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); +		bfa_itnim_send_fwdelete(itnim); +		break; + +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		bfa_reqq_wcancel(&itnim->reqq_wait); +		bfa_itnim_offline_cb(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Offline state. + */ +static void +bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_itnim_iotov_delete(itnim); +		bfa_fcpim_delitn(itnim); +		break; + +	case BFA_ITNIM_SM_ONLINE: +		if (bfa_itnim_send_fwcreate(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		IOC h/w failed state. + */ +static void +bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, +			    enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_itnim_iotov_delete(itnim); +		bfa_fcpim_delitn(itnim); +		break; + +	case BFA_ITNIM_SM_OFFLINE: +		bfa_itnim_offline_cb(itnim); +		break; + +	case BFA_ITNIM_SM_ONLINE: +		if (bfa_itnim_send_fwcreate(itnim)) +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); +		else +			bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Itnim is deleted, waiting for firmware response to delete. + */ +static void +bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_FWRSP: +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_fcpim_delitn(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, +			enum bfa_itnim_event event) +{ +	bfa_trc(itnim->bfa, itnim->rport->rport_tag); +	bfa_trc(itnim->bfa, event); + +	switch (event) { +	case BFA_ITNIM_SM_QRESUME: +		bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); +		bfa_itnim_send_fwdelete(itnim); +		break; + +	case BFA_ITNIM_SM_HWFAIL: +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +		bfa_reqq_wcancel(&itnim->reqq_wait); +		bfa_fcpim_delitn(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  bfa_itnim_private + */ + +/** + * 		Initiate cleanup of all IOs on an IOC failure. + */ +static void +bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim) +{ +	struct bfa_tskim_s *tskim; +	struct bfa_ioim_s *ioim; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &itnim->tsk_q) { +		tskim = (struct bfa_tskim_s *) qe; +		bfa_tskim_iocdisable(tskim); +	} + +	list_for_each_safe(qe, qen, &itnim->io_q) { +		ioim = (struct bfa_ioim_s *) qe; +		bfa_ioim_iocdisable(ioim); +	} + +	/** +	 * For IO request in pending queue, we pretend an early timeout. +	 */ +	list_for_each_safe(qe, qen, &itnim->pending_q) { +		ioim = (struct bfa_ioim_s *) qe; +		bfa_ioim_tov(ioim); +	} + +	list_for_each_safe(qe, qen, &itnim->io_cleanup_q) { +		ioim = (struct bfa_ioim_s *) qe; +		bfa_ioim_iocdisable(ioim); +	} +} + +/** + * 		IO cleanup completion + */ +static void +bfa_itnim_cleanp_comp(void *itnim_cbarg) +{ +	struct bfa_itnim_s *itnim = itnim_cbarg; + +	bfa_stats(itnim, cleanup_comps); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP); +} + +/** + * 		Initiate cleanup of all IOs. + */ +static void +bfa_itnim_cleanup(struct bfa_itnim_s *itnim) +{ +	struct bfa_ioim_s  *ioim; +	struct bfa_tskim_s *tskim; +	struct list_head         *qe, *qen; + +	bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim); + +	list_for_each_safe(qe, qen, &itnim->io_q) { +		ioim = (struct bfa_ioim_s *) qe; + +		/** +		 * Move IO to a cleanup queue from active queue so that a later +		 * TM will not pickup this IO. +		 */ +		list_del(&ioim->qe); +		list_add_tail(&ioim->qe, &itnim->io_cleanup_q); + +		bfa_wc_up(&itnim->wc); +		bfa_ioim_cleanup(ioim); +	} + +	list_for_each_safe(qe, qen, &itnim->tsk_q) { +		tskim = (struct bfa_tskim_s *) qe; +		bfa_wc_up(&itnim->wc); +		bfa_tskim_cleanup(tskim); +	} + +	bfa_wc_wait(&itnim->wc); +} + +static void +__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_itnim_s *itnim = cbarg; + +	if (complete) +		bfa_cb_itnim_online(itnim->ditn); +} + +static void +__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_itnim_s *itnim = cbarg; + +	if (complete) +		bfa_cb_itnim_offline(itnim->ditn); +} + +static void +__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_itnim_s *itnim = cbarg; + +	if (complete) +		bfa_cb_itnim_sler(itnim->ditn); +} + +/** + * Call to resume any I/O requests waiting for room in request queue. + */ +static void +bfa_itnim_qresume(void *cbarg) +{ +	struct bfa_itnim_s *itnim = cbarg; + +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME); +} + + + + +/** + *  bfa_itnim_public + */ + +void +bfa_itnim_iodone(struct bfa_itnim_s *itnim) +{ +	bfa_wc_down(&itnim->wc); +} + +void +bfa_itnim_tskdone(struct bfa_itnim_s *itnim) +{ +	bfa_wc_down(&itnim->wc); +} + +void +bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len) +{ +	/** +	 * ITN memory +	 */ +	*km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s); +} + +void +bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ +	struct bfa_s      *bfa = fcpim->bfa; +	struct bfa_itnim_s *itnim; +	int             i; + +	INIT_LIST_HEAD(&fcpim->itnim_q); + +	itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo); +	fcpim->itnim_arr = itnim; + +	for (i = 0; i < fcpim->num_itnims; i++, itnim++) { +		bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s)); +		itnim->bfa = bfa; +		itnim->fcpim = fcpim; +		itnim->reqq = BFA_REQQ_QOS_LO; +		itnim->rport = BFA_RPORT_FROM_TAG(bfa, i); +		itnim->iotov_active = BFA_FALSE; +		bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim); + +		INIT_LIST_HEAD(&itnim->io_q); +		INIT_LIST_HEAD(&itnim->io_cleanup_q); +		INIT_LIST_HEAD(&itnim->pending_q); +		INIT_LIST_HEAD(&itnim->tsk_q); +		INIT_LIST_HEAD(&itnim->delay_comp_q); +		bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); +	} + +	bfa_meminfo_kva(minfo) = (u8 *) itnim; +} + +void +bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) +{ +	bfa_stats(itnim, ioc_disabled); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL); +} + +static bfa_boolean_t +bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) +{ +	struct bfi_itnim_create_req_s *m; + +	itnim->msg_no++; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(itnim->bfa, itnim->reqq); +	if (!m) { +		bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ, +			bfa_lpuid(itnim->bfa)); +	m->fw_handle = itnim->rport->fw_handle; +	m->class = FC_CLASS_3; +	m->seq_rec = itnim->seq_rec; +	m->msg_no = itnim->msg_no; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(itnim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +static bfa_boolean_t +bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) +{ +	struct bfi_itnim_delete_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(itnim->bfa, itnim->reqq); +	if (!m) { +		bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ, +			bfa_lpuid(itnim->bfa)); +	m->fw_handle = itnim->rport->fw_handle; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(itnim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +/** + * Cleanup all pending failed inflight requests. + */ +static void +bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov) +{ +	struct bfa_ioim_s *ioim; +	struct list_head *qe, *qen; + +	list_for_each_safe(qe, qen, &itnim->delay_comp_q) { +		ioim = (struct bfa_ioim_s *)qe; +		bfa_ioim_delayed_comp(ioim, iotov); +	} +} + +/** + * Start all pending IO requests. + */ +static void +bfa_itnim_iotov_online(struct bfa_itnim_s *itnim) +{ +	struct bfa_ioim_s *ioim; + +	bfa_itnim_iotov_stop(itnim); + +	/** +	 * Abort all inflight IO requests in the queue +	 */ +	bfa_itnim_delayed_comp(itnim, BFA_FALSE); + +	/** +	 * Start all pending IO requests. +	 */ +	while (!list_empty(&itnim->pending_q)) { +		bfa_q_deq(&itnim->pending_q, &ioim); +		list_add_tail(&ioim->qe, &itnim->io_q); +		bfa_ioim_start(ioim); +	} +} + +/** + * Fail all pending IO requests + */ +static void +bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim) +{ +	struct bfa_ioim_s *ioim; + +	/** +	 * Fail all inflight IO requests in the queue +	 */ +	bfa_itnim_delayed_comp(itnim, BFA_TRUE); + +	/** +	 * Fail any pending IO requests. +	 */ +	while (!list_empty(&itnim->pending_q)) { +		bfa_q_deq(&itnim->pending_q, &ioim); +		list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); +		bfa_ioim_tov(ioim); +	} +} + +/** + * IO TOV timer callback. Fail any pending IO requests. + */ +static void +bfa_itnim_iotov(void *itnim_arg) +{ +	struct bfa_itnim_s *itnim = itnim_arg; + +	itnim->iotov_active = BFA_FALSE; + +	bfa_cb_itnim_tov_begin(itnim->ditn); +	bfa_itnim_iotov_cleanup(itnim); +	bfa_cb_itnim_tov(itnim->ditn); +} + +/** + * Start IO TOV timer for failing back pending IO requests in offline state. + */ +static void +bfa_itnim_iotov_start(struct bfa_itnim_s *itnim) +{ +	if (itnim->fcpim->path_tov > 0) { + +		itnim->iotov_active = BFA_TRUE; +		bfa_assert(bfa_itnim_hold_io(itnim)); +		bfa_timer_start(itnim->bfa, &itnim->timer, +			bfa_itnim_iotov, itnim, itnim->fcpim->path_tov); +	} +} + +/** + * Stop IO TOV timer. + */ +static void +bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim) +{ +	if (itnim->iotov_active) { +		itnim->iotov_active = BFA_FALSE; +		bfa_timer_stop(&itnim->timer); +	} +} + +/** + * Stop IO TOV timer. + */ +static void +bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) +{ +    bfa_boolean_t pathtov_active = BFA_FALSE; + +    if (itnim->iotov_active) +		pathtov_active = BFA_TRUE; + +	bfa_itnim_iotov_stop(itnim); +	if (pathtov_active) +		bfa_cb_itnim_tov_begin(itnim->ditn); +	bfa_itnim_iotov_cleanup(itnim); +	if (pathtov_active) +		bfa_cb_itnim_tov(itnim->ditn); +} + + + +/** + *  bfa_itnim_public + */ + +/** + * 		Itnim interrupt processing. + */ +void +bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	union bfi_itnim_i2h_msg_u msg; +	struct bfa_itnim_s *itnim; + +	bfa_trc(bfa, m->mhdr.msg_id); + +	msg.msg = m; + +	switch (m->mhdr.msg_id) { +	case BFI_ITNIM_I2H_CREATE_RSP: +		itnim = BFA_ITNIM_FROM_TAG(fcpim, +					       msg.create_rsp->bfa_handle); +		bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); +		bfa_stats(itnim, create_comps); +		bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); +		break; + +	case BFI_ITNIM_I2H_DELETE_RSP: +		itnim = BFA_ITNIM_FROM_TAG(fcpim, +					       msg.delete_rsp->bfa_handle); +		bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); +		bfa_stats(itnim, delete_comps); +		bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); +		break; + +	case BFI_ITNIM_I2H_SLER_EVENT: +		itnim = BFA_ITNIM_FROM_TAG(fcpim, +					       msg.sler_event->bfa_handle); +		bfa_stats(itnim, sler_events); +		bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER); +		break; + +	default: +		bfa_trc(bfa, m->mhdr.msg_id); +		bfa_assert(0); +	} +} + + + +/** + *  bfa_itnim_api + */ + +struct bfa_itnim_s * +bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfa_itnim_s *itnim; + +	itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); +	bfa_assert(itnim->rport == rport); + +	itnim->ditn = ditn; + +	bfa_stats(itnim, creates); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE); + +	return (itnim); +} + +void +bfa_itnim_delete(struct bfa_itnim_s *itnim) +{ +	bfa_stats(itnim, deletes); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE); +} + +void +bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec) +{ +	itnim->seq_rec = seq_rec; +	bfa_stats(itnim, onlines); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE); +} + +void +bfa_itnim_offline(struct bfa_itnim_s *itnim) +{ +	bfa_stats(itnim, offlines); +	bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE); +} + +/** + * Return true if itnim is considered offline for holding off IO request. + * IO is not held if itnim is being deleted. + */ +bfa_boolean_t +bfa_itnim_hold_io(struct bfa_itnim_s *itnim) +{ +	return ( +		itnim->fcpim->path_tov && itnim->iotov_active && +		(bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) || +		 bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) || +		 bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) || +		 bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) || +		 bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) || +		 bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable)) +); +} + +void +bfa_itnim_get_stats(struct bfa_itnim_s *itnim, +	struct bfa_itnim_hal_stats_s *stats) +{ +	*stats = itnim->stats; +} + +void +bfa_itnim_clear_stats(struct bfa_itnim_s *itnim) +{ +	bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats)); +} + + diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c new file mode 100644 index 00000000000..c2735e55cf0 --- /dev/null +++ b/drivers/scsi/bfa/bfa_log.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_log.c BFA log library + */ + +#include <bfa_os_inc.h> +#include <cs/bfa_log.h> + +/* + * global log info structure + */ +struct bfa_log_info_s { +	u32        start_idx;	/*  start index for a module */ +	u32        total_count;	/*  total count for a module */ +	enum bfa_log_severity level;	/*  global log level */ +	bfa_log_cb_t	cbfn;		/*  callback function */ +}; + +static struct bfa_log_info_s bfa_log_info[BFA_LOG_MODULE_ID_MAX + 1]; +static u32 bfa_log_msg_total_count; +static int      bfa_log_initialized; + +static char    *bfa_log_severity[] = +	{ "[none]", "[critical]", "[error]", "[warn]", "[info]", "" }; + +/** + * BFA log library initialization + * + * The log library initialization includes the following, + *    - set log instance name and callback function + *    - read the message array generated from xml files + *    - calculate start index for each module + *    - calculate message count for each module + *    - perform error checking + * + * @param[in] log_mod - log module info + * @param[in] instance_name - instance name + * @param[in] cbfn - callback function + * + * It return 0 on success, or -1 on failure + */ +int +bfa_log_init(struct bfa_log_mod_s *log_mod, char *instance_name, +			bfa_log_cb_t cbfn) +{ +	struct bfa_log_msgdef_s *msg; +	u32        pre_mod_id = 0; +	u32        cur_mod_id = 0; +	u32        i, pre_idx, idx, msg_id; + +	/* +	 * set instance name +	 */ +	if (log_mod) { +		strncpy(log_mod->instance_info, instance_name, +			sizeof(log_mod->instance_info)); +		log_mod->cbfn = cbfn; +		for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) +			log_mod->log_level[i] = BFA_LOG_WARNING; +	} + +	if (bfa_log_initialized) +		return 0; + +	for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) { +		bfa_log_info[i].start_idx = 0; +		bfa_log_info[i].total_count = 0; +		bfa_log_info[i].level = BFA_LOG_WARNING; +		bfa_log_info[i].cbfn = cbfn; +	} + +	pre_idx = 0; +	idx = 0; +	msg = bfa_log_msg_array; +	msg_id = BFA_LOG_GET_MSG_ID(msg); +	pre_mod_id = BFA_LOG_GET_MOD_ID(msg_id); +	while (msg_id != 0) { +		cur_mod_id = BFA_LOG_GET_MOD_ID(msg_id); + +		if (cur_mod_id > BFA_LOG_MODULE_ID_MAX) { +			cbfn(log_mod, msg_id, +				"%s%s log: module id %u out of range\n", +				BFA_LOG_CAT_NAME, +				bfa_log_severity[BFA_LOG_ERROR], +				cur_mod_id); +			return -1; +		} + +		if (pre_mod_id > BFA_LOG_MODULE_ID_MAX) { +			cbfn(log_mod, msg_id, +				"%s%s log: module id %u out of range\n", +				BFA_LOG_CAT_NAME, +				bfa_log_severity[BFA_LOG_ERROR], +				pre_mod_id); +			return -1; +		} + +		if (cur_mod_id != pre_mod_id) { +			bfa_log_info[pre_mod_id].start_idx = pre_idx; +			bfa_log_info[pre_mod_id].total_count = idx - pre_idx; +			pre_mod_id = cur_mod_id; +			pre_idx = idx; +		} + +		idx++; +		msg++; +		msg_id = BFA_LOG_GET_MSG_ID(msg); +	} + +	bfa_log_info[cur_mod_id].start_idx = pre_idx; +	bfa_log_info[cur_mod_id].total_count = idx - pre_idx; +	bfa_log_msg_total_count = idx; + +	cbfn(log_mod, msg_id, "%s%s log: init OK, msg total count %u\n", +		BFA_LOG_CAT_NAME, +		bfa_log_severity[BFA_LOG_INFO], bfa_log_msg_total_count); + +	bfa_log_initialized = 1; + +	return 0; +} + +/** + * BFA log set log level for a module + * + * @param[in] log_mod - log module info + * @param[in] mod_id - module id + * @param[in] log_level - log severity level + * + * It return BFA_STATUS_OK on success, or > 0 on failure + */ +bfa_status_t +bfa_log_set_level(struct bfa_log_mod_s *log_mod, int mod_id, +		  enum bfa_log_severity log_level) +{ +	if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX) +		return BFA_STATUS_EINVAL; + +	if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX) +		return BFA_STATUS_EINVAL; + +	if (log_mod) +		log_mod->log_level[mod_id] = log_level; +	else +		bfa_log_info[mod_id].level = log_level; + +	return BFA_STATUS_OK; +} + +/** + * BFA log set log level for all modules + * + * @param[in] log_mod - log module info + * @param[in] log_level - log severity level + * + * It return BFA_STATUS_OK on success, or > 0 on failure + */ +bfa_status_t +bfa_log_set_level_all(struct bfa_log_mod_s *log_mod, +		  enum bfa_log_severity log_level) +{ +	int mod_id = BFA_LOG_UNUSED_ID + 1; + +	if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX) +		return BFA_STATUS_EINVAL; + +	if (log_mod) { +		for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++) +			log_mod->log_level[mod_id] = log_level; +	} else { +		for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++) +			bfa_log_info[mod_id].level = log_level; +	} + +	return BFA_STATUS_OK; +} + +/** + * BFA log set log level for all aen sub-modules + * + * @param[in] log_mod - log module info + * @param[in] log_level - log severity level + * + * It return BFA_STATUS_OK on success, or > 0 on failure + */ +bfa_status_t +bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod, +		  enum bfa_log_severity log_level) +{ +	int mod_id = BFA_LOG_AEN_MIN + 1; + +	if (log_mod) { +		for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++) +			log_mod->log_level[mod_id] = log_level; +	} else { +		for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++) +			bfa_log_info[mod_id].level = log_level; +	} + +	return BFA_STATUS_OK; +} + +/** + * BFA log get log level for a module + * + * @param[in] log_mod - log module info + * @param[in] mod_id - module id + * + * It returns log level or -1 on error + */ +enum bfa_log_severity +bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id) +{ +	if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX) +		return BFA_LOG_INVALID; + +	if (log_mod) +		return (log_mod->log_level[mod_id]); +	else +		return (bfa_log_info[mod_id].level); +} + +enum bfa_log_severity +bfa_log_get_msg_level(struct bfa_log_mod_s *log_mod, u32 msg_id) +{ +	struct bfa_log_msgdef_s *msg; +	u32        mod = BFA_LOG_GET_MOD_ID(msg_id); +	u32        idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1; + +	if (!bfa_log_initialized) +		return BFA_LOG_INVALID; + +	if (mod > BFA_LOG_MODULE_ID_MAX) +		return BFA_LOG_INVALID; + +	if (idx >= bfa_log_info[mod].total_count) { +		bfa_log_info[mod].cbfn(log_mod, msg_id, +			"%s%s log: inconsistent idx %u vs. total count %u\n", +			BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx, +			bfa_log_info[mod].total_count); +		return BFA_LOG_INVALID; +	} + +	msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx; +	if (msg_id != BFA_LOG_GET_MSG_ID(msg)) { +		bfa_log_info[mod].cbfn(log_mod, msg_id, +			"%s%s log: inconsistent msg id %u array msg id %u\n", +			BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], +			msg_id, BFA_LOG_GET_MSG_ID(msg)); +		return BFA_LOG_INVALID; +	} + +	return BFA_LOG_GET_SEVERITY(msg); +} + +/** + * BFA log message handling + * + * BFA log message handling finds the message based on message id and prints + * out the message based on its format and arguments. It also does prefix + * the severity etc. + * + * @param[in] log_mod - log module info + * @param[in] msg_id - message id + * @param[in] ... - message arguments + * + * It return 0 on success, or -1 on errors + */ +int +bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...) +{ +	va_list         ap; +	char            buf[256]; +	struct bfa_log_msgdef_s *msg; +	int             log_level; +	u32        mod = BFA_LOG_GET_MOD_ID(msg_id); +	u32        idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1; + +	if (!bfa_log_initialized) +		return -1; + +	if (mod > BFA_LOG_MODULE_ID_MAX) +		return -1; + +	if (idx >= bfa_log_info[mod].total_count) { +		bfa_log_info[mod]. +			cbfn +			(log_mod, msg_id, +			"%s%s log: inconsistent idx %u vs. total count %u\n", +			BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx, +			bfa_log_info[mod].total_count); +		return -1; +	} + +	msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx; +	if (msg_id != BFA_LOG_GET_MSG_ID(msg)) { +		bfa_log_info[mod]. +			cbfn +			(log_mod, msg_id, +			"%s%s log: inconsistent msg id %u array msg id %u\n", +			BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], +			msg_id, BFA_LOG_GET_MSG_ID(msg)); +		return -1; +	} + +	log_level = log_mod ? log_mod->log_level[mod] : bfa_log_info[mod].level; +	if ((BFA_LOG_GET_SEVERITY(msg) > log_level) && +			(msg->attributes != BFA_LOG_ATTR_NONE)) +		return 0; + +	va_start(ap, msg_id); +	bfa_os_vsprintf(buf, BFA_LOG_GET_MSG_FMT_STRING(msg), ap); +	va_end(ap); + +	if (log_mod) +		log_mod->cbfn(log_mod, msg_id, "%s[%s]%s%s %s: %s\n", +				BFA_LOG_CAT_NAME, log_mod->instance_info, +				bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)], +				(msg->attributes & BFA_LOG_ATTR_AUDIT) +				? " (audit) " : "", msg->msg_value, buf); +	else +		bfa_log_info[mod].cbfn(log_mod, msg_id, "%s%s%s %s: %s\n", +				BFA_LOG_CAT_NAME, +				bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)], +				(msg->attributes & BFA_LOG_ATTR_AUDIT) ? +				" (audit) " : "", msg->msg_value, buf); + +	return 0; +} + diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c new file mode 100644 index 00000000000..5c154d341d6 --- /dev/null +++ b/drivers/scsi/bfa/bfa_log_module.c @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <cs/bfa_log.h> +#include <aen/bfa_aen_adapter.h> +#include <aen/bfa_aen_audit.h> +#include <aen/bfa_aen_ethport.h> +#include <aen/bfa_aen_ioc.h> +#include <aen/bfa_aen_itnim.h> +#include <aen/bfa_aen_lport.h> +#include <aen/bfa_aen_port.h> +#include <aen/bfa_aen_rport.h> +#include <log/bfa_log_fcs.h> +#include <log/bfa_log_hal.h> +#include <log/bfa_log_linux.h> +#include <log/bfa_log_wdrv.h> + +struct bfa_log_msgdef_s bfa_log_msg_array[] = { + + +/* messages define for BFA_AEN_CAT_ADAPTER Module */ +{BFA_AEN_ADAPTER_ADD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ADAPTER_ADD", + "New adapter found: SN = %s, base port WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_ADAPTER_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_ADAPTER_REMOVE", + "Adapter removed: SN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + + + + +/* messages define for BFA_AEN_CAT_AUDIT Module */ +{BFA_AEN_AUDIT_AUTH_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_ENABLE", + "Authentication enabled for base port: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_AUDIT_AUTH_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_DISABLE", + "Authentication disabled for base port: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + + + + +/* messages define for BFA_AEN_CAT_ETHPORT Module */ +{BFA_AEN_ETHPORT_LINKUP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ETHPORT_LINKUP", + "Base port ethernet linkup: mac = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_ETHPORT_LINKDOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ETHPORT_LINKDOWN", + "Base port ethernet linkdown: mac = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_ETHPORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ETHPORT_ENABLE", + "Base port ethernet interface enabled: mac = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_ETHPORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ETHPORT_DISABLE", + "Base port ethernet interface disabled: mac = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + + + + +/* messages define for BFA_AEN_CAT_IOC Module */ +{BFA_AEN_IOC_HBGOOD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_IOC_HBGOOD", + "Heart Beat of IOC %d is good.", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_HBFAIL, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_CRITICAL, + "BFA_AEN_IOC_HBFAIL", + "Heart Beat of IOC %d has failed.", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_IOC_ENABLE", + "IOC %d is enabled.", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_IOC_DISABLE", + "IOC %d is disabled.", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_FWMISMATCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWMISMATCH", + "Running firmware version is incompatible with the driver version.", + (0), 0}, + + + + +/* messages define for BFA_AEN_CAT_ITNIM Module */ +{BFA_AEN_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ITNIM_ONLINE", + "Target (WWN = %s) is online for initiator (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_ITNIM_OFFLINE", + "Target (WWN = %s) offlined by initiator (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_ITNIM_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_ITNIM_DISCONNECT", + "Target (WWN = %s) connectivity lost for initiator (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + + + + +/* messages define for BFA_AEN_CAT_LPORT Module */ +{BFA_AEN_LPORT_NEW, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_LPORT_NEW", + "New logical port created: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_DELETE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_LPORT_DELETE", + "Logical port deleted: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_LPORT_ONLINE", + "Logical port online: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_LPORT_OFFLINE", + "Logical port taken offline: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_LPORT_DISCONNECT", + "Logical port lost fabric connectivity: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_NEW_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_LPORT_NEW_PROP", + "New virtual port created using proprietary interface: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_DELETE_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_PROP", + "Virtual port deleted using proprietary interface: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_NEW_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "BFA_AEN_LPORT_NEW_STANDARD", + "New virtual port created using standard interface: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_DELETE_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_STANDARD", + "Virtual port deleted using standard interface: WWN = %s, Role = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_LPORT_NPIV_DUP_WWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_DUP_WWN", + "Virtual port login failed. Duplicate WWN = %s reported by fabric.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_LPORT_NPIV_FABRIC_MAX, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_FABRIC_MAX", + "Virtual port (WWN = %s) login failed. Max NPIV ports already exist in" + " fabric/fport.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_LPORT_NPIV_UNKNOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_UNKNOWN", + "Virtual port (WWN = %s) login failed.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + + + + +/* messages define for BFA_AEN_CAT_PORT Module */ +{BFA_AEN_PORT_ONLINE, BFA_LOG_ATTR_NONE, BFA_LOG_INFO, "BFA_AEN_PORT_ONLINE", + "Base port online: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, + "BFA_AEN_PORT_OFFLINE", + "Base port offline: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_RLIR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_PORT_RLIR", + "RLIR event not supported.", + (0), 0}, + +{BFA_AEN_PORT_SFP_INSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_PORT_SFP_INSERT", + "New SFP found: WWN/MAC = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_SFP_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_REMOVE", + "SFP removed: WWN/MAC = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_SFP_POM, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, + "BFA_AEN_PORT_SFP_POM", + "SFP POM level to %s: WWN/MAC = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_PORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_PORT_ENABLE", + "Base port enabled: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_PORT_DISABLE", + "Base port disabled: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_AUTH_ON, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_PORT_AUTH_ON", + "Authentication successful for base port: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_AUTH_OFF, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, + "BFA_AEN_PORT_AUTH_OFF", + "Authentication unsuccessful for base port: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, + "BFA_AEN_PORT_DISCONNECT", + "Base port (WWN = %s) lost fabric connectivity.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_QOS_NEG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING, + "BFA_AEN_PORT_QOS_NEG", + "QOS negotiation failed for base port: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_FABRIC_NAME_CHANGE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_PORT_FABRIC_NAME_CHANGE", + "Base port WWN = %s, Fabric WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_PORT_SFP_ACCESS_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_ACCESS_ERROR", + "SFP access error: WWN/MAC = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_PORT_SFP_UNSUPPORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_UNSUPPORT", + "Unsupported SFP found: WWN/MAC = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + + + + +/* messages define for BFA_AEN_CAT_RPORT Module */ +{BFA_AEN_RPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_RPORT_ONLINE", + "Remote port (WWN = %s) online for logical port (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_RPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_RPORT_OFFLINE", + "Remote port (WWN = %s) offlined by logical port (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_RPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_RPORT_DISCONNECT", + "Remote port (WWN = %s) connectivity lost for logical port (WWN = %s).", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2}, + +{BFA_AEN_RPORT_QOS_PRIO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_RPORT_QOS_PRIO", + "QOS priority changed to %s: RPWWN = %s and LPWWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, + +{BFA_AEN_RPORT_QOS_FLOWID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "BFA_AEN_RPORT_QOS_FLOWID", + "QOS flow ID changed to %d: RPWWN = %s and LPWWN = %s.", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, + + + + +/* messages define for FCS Module */ +{BFA_LOG_FCS_FABRIC_NOSWITCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "FCS_FABRIC_NOSWITCH", + "No switched fabric presence is detected.", + (0), 0}, + +{BFA_LOG_FCS_FABRIC_ISOLATED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "FCS_FABRIC_ISOLATED", + "Port is isolated due to VF_ID mismatch. PWWN: %s, Port VF_ID: %04x and" + " switch port VF_ID: %04x.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_X << BFA_LOG_ARG1) | +  (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, + + + + +/* messages define for HAL Module */ +{BFA_LOG_HAL_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, + "HAL_ASSERT", + "Assertion failure: %s:%d: %s", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, + +{BFA_LOG_HAL_HEARTBEAT_FAILURE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_CRITICAL, "HAL_HEARTBEAT_FAILURE", + "Firmware heartbeat failure at %d", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_HAL_FCPIM_PARM_INVALID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "HAL_FCPIM_PARM_INVALID", + "Driver configuration %s value %d is invalid. Value should be within" + " %d and %d.", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | +  (BFA_LOG_D << BFA_LOG_ARG2) | (BFA_LOG_D << BFA_LOG_ARG3) | 0), 4}, + +{BFA_LOG_HAL_SM_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR, + "HAL_SM_ASSERT", + "SM Assertion failure: %s:%d: event = %d", + ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | +  (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3}, + + + + +/* messages define for LINUX Module */ +{BFA_LOG_LINUX_DEVICE_CLAIMED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_DEVICE_CLAIMED", + "bfa device at %s claimed.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_HASH_INIT_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_HASH_INIT_FAILED", + "Hash table initialization failure for the port %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_SYSFS_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_SYSFS_FAILED", + "sysfs file creation failure for the port %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_MEM_ALLOC_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_MEM_ALLOC_FAILED", + "Memory allocation failed: %s.  ", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_DRIVER_REGISTRATION_FAILED", + "%s.  ", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_ITNIM_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_ITNIM_FREE", + "scsi%d: FCID: %s WWPN: %s", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3}, + +{BFA_LOG_LINUX_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_ITNIM_ONLINE", + "Target: %d:0:%d FCID: %s WWPN: %s", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4}, + +{BFA_LOG_LINUX_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_ITNIM_OFFLINE", + "Target: %d:0:%d FCID: %s WWPN: %s", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | +  (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4}, + +{BFA_LOG_LINUX_SCSI_HOST_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_SCSI_HOST_FREE", + "Free scsi%d", + ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_SCSI_ABORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_SCSI_ABORT", + "scsi%d: abort cmnd %p, iotag %x", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) | +  (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, + +{BFA_LOG_LINUX_SCSI_ABORT_COMP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_SCSI_ABORT_COMP", + "scsi%d: complete abort 0x%p, iotag 0x%x", + ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) | +  (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, + + + + +/* messages define for WDRV Module */ +{BFA_LOG_WDRV_IOC_INIT_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_IOC_INIT_ERROR", + "IOC initialization has failed.", + (0), 0}, + +{BFA_LOG_WDRV_IOC_INTERNAL_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_IOC_INTERNAL_ERROR", + "IOC internal error.  ", + (0), 0}, + +{BFA_LOG_WDRV_IOC_START_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_IOC_START_ERROR", + "IOC could not be started.  ", + (0), 0}, + +{BFA_LOG_WDRV_IOC_STOP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_IOC_STOP_ERROR", + "IOC could not be stopped.  ", + (0), 0}, + +{BFA_LOG_WDRV_INSUFFICIENT_RESOURCES, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_INSUFFICIENT_RESOURCES", + "Insufficient memory.  ", + (0), 0}, + +{BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "WDRV_BASE_ADDRESS_MAP_ERROR", + "Unable to map the IOC onto the system address space.  ", + (0), 0}, + + +{0, 0, 0, "", "", 0, 0}, +}; diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c new file mode 100644 index 00000000000..9844b45412b --- /dev/null +++ b/drivers/scsi/bfa/bfa_lps.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfi/bfi_lps.h> +#include <cs/bfa_debug.h> + +BFA_TRC_FILE(HAL, LPS); +BFA_MODULE(lps); + +#define BFA_LPS_MIN_LPORTS	(1) +#define BFA_LPS_MAX_LPORTS	(256) + +/** + * forward declarations + */ +static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, +			    u32 *dm_len); +static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, +			   struct bfa_iocfc_cfg_s *cfg, +			   struct bfa_meminfo_s *meminfo, +			   struct bfa_pcidev_s *pcidev); +static void bfa_lps_initdone(struct bfa_s *bfa); +static void bfa_lps_detach(struct bfa_s *bfa); +static void bfa_lps_start(struct bfa_s *bfa); +static void bfa_lps_stop(struct bfa_s *bfa); +static void bfa_lps_iocdisable(struct bfa_s *bfa); +static void bfa_lps_login_rsp(struct bfa_s *bfa, +			      struct bfi_lps_login_rsp_s *rsp); +static void bfa_lps_logout_rsp(struct bfa_s *bfa, +			       struct bfi_lps_logout_rsp_s *rsp); +static void bfa_lps_reqq_resume(void *lps_arg); +static void bfa_lps_free(struct bfa_lps_s *lps); +static void bfa_lps_send_login(struct bfa_lps_s *lps); +static void bfa_lps_send_logout(struct bfa_lps_s *lps); +static void bfa_lps_login_comp(struct bfa_lps_s *lps); +static void bfa_lps_logout_comp(struct bfa_lps_s *lps); + + +/** + *  lps_pvt BFA LPS private functions + */ + +enum bfa_lps_event { +	BFA_LPS_SM_LOGIN	= 1,	/* login request from user	*/ +	BFA_LPS_SM_LOGOUT	= 2,	/* logout request from user	*/ +	BFA_LPS_SM_FWRSP	= 3,	/* f/w response to login/logout	*/ +	BFA_LPS_SM_RESUME	= 4,	/* space present in reqq queue	*/ +	BFA_LPS_SM_DELETE	= 5,	/* lps delete from user		*/ +	BFA_LPS_SM_OFFLINE	= 6,	/* Link is offline		*/ +}; + +static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, +			enum bfa_lps_event event); +static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); +static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, +			enum bfa_lps_event event); + +/** + * Init state -- no login + */ +static void +bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_LOGIN: +		if (bfa_reqq_full(lps->bfa, lps->reqq)) { +			bfa_sm_set_state(lps, bfa_lps_sm_loginwait); +			bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); +		} else { +			bfa_sm_set_state(lps, bfa_lps_sm_login); +			bfa_lps_send_login(lps); +		} +		break; + +	case BFA_LPS_SM_LOGOUT: +		bfa_lps_logout_comp(lps); +		break; + +	case BFA_LPS_SM_DELETE: +		bfa_lps_free(lps); +		break; + +	case BFA_LPS_SM_OFFLINE: +		break; + +	case BFA_LPS_SM_FWRSP: +		/* Could happen when fabric detects loopback and discards +		 * the lps request. Fw will eventually sent out the timeout +		 * Just ignore +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * login is in progress -- awaiting response from firmware + */ +static void +bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_FWRSP: +		if (lps->status == BFA_STATUS_OK) +			bfa_sm_set_state(lps, bfa_lps_sm_online); +		else +			bfa_sm_set_state(lps, bfa_lps_sm_init); +		bfa_lps_login_comp(lps); +		break; + +	case BFA_LPS_SM_OFFLINE: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * login pending - awaiting space in request queue + */ +static void +bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_RESUME: +		bfa_sm_set_state(lps, bfa_lps_sm_login); +		break; + +	case BFA_LPS_SM_OFFLINE: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		bfa_reqq_wcancel(&lps->wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * login complete + */ +static void +bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_LOGOUT: +		if (bfa_reqq_full(lps->bfa, lps->reqq)) { +			bfa_sm_set_state(lps, bfa_lps_sm_logowait); +			bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); +		} else { +			bfa_sm_set_state(lps, bfa_lps_sm_logout); +			bfa_lps_send_logout(lps); +		} +		break; + +	case BFA_LPS_SM_OFFLINE: +	case BFA_LPS_SM_DELETE: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * logout in progress - awaiting firmware response + */ +static void +bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_FWRSP: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		bfa_lps_logout_comp(lps); +		break; + +	case BFA_LPS_SM_OFFLINE: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * logout pending -- awaiting space in request queue + */ +static void +bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) +{ +	bfa_trc(lps->bfa, lps->lp_tag); +	bfa_trc(lps->bfa, event); + +	switch (event) { +	case BFA_LPS_SM_RESUME: +		bfa_sm_set_state(lps, bfa_lps_sm_logout); +		bfa_lps_send_logout(lps); +		break; + +	case BFA_LPS_SM_OFFLINE: +		bfa_sm_set_state(lps, bfa_lps_sm_init); +		bfa_reqq_wcancel(&lps->wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  lps_pvt BFA LPS private functions + */ + +/** + * return memory requirement + */ +static void +bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) +{ +	if (cfg->drvcfg.min_cfg) +		*ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS; +	else +		*ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS; +} + +/** + * bfa module attach at initialization time + */ +static void +bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps; +	int			i; + +	bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s)); +	mod->num_lps = BFA_LPS_MAX_LPORTS; +	if (cfg->drvcfg.min_cfg) +		mod->num_lps = BFA_LPS_MIN_LPORTS; +	else +		mod->num_lps = BFA_LPS_MAX_LPORTS; +	mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo); + +	bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s); + +	INIT_LIST_HEAD(&mod->lps_free_q); +	INIT_LIST_HEAD(&mod->lps_active_q); + +	for (i = 0; i < mod->num_lps; i++, lps++) { +		lps->bfa	= bfa; +		lps->lp_tag	= (u8) i; +		lps->reqq	= BFA_REQQ_LPS; +		bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); +		list_add_tail(&lps->qe, &mod->lps_free_q); +	} +} + +static void +bfa_lps_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_lps_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_lps_start(struct bfa_s *bfa) +{ +} + +static void +bfa_lps_stop(struct bfa_s *bfa) +{ +} + +/** + * IOC in disabled state -- consider all lps offline + */ +static void +bfa_lps_iocdisable(struct bfa_s *bfa) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps; +	struct list_head		*qe, *qen; + +	list_for_each_safe(qe, qen, &mod->lps_active_q) { +		lps = (struct bfa_lps_s *) qe; +		bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); +	} +} + +/** + * Firmware login response + */ +static void +bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps; + +	bfa_assert(rsp->lp_tag < mod->num_lps); +	lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); + +	lps->status = rsp->status; +	switch (rsp->status) { +	case BFA_STATUS_OK: +		lps->fport	= rsp->f_port; +		lps->npiv_en	= rsp->npiv_en; +		lps->lp_pid	= rsp->lp_pid; +		lps->pr_bbcred	= bfa_os_ntohs(rsp->bb_credit); +		lps->pr_pwwn	= rsp->port_name; +		lps->pr_nwwn	= rsp->node_name; +		lps->auth_req	= rsp->auth_req; +		lps->lp_mac	= rsp->lp_mac; +		lps->brcd_switch = rsp->brcd_switch; +		lps->fcf_mac	= rsp->fcf_mac; + +		break; + +	case BFA_STATUS_FABRIC_RJT: +		lps->lsrjt_rsn = rsp->lsrjt_rsn; +		lps->lsrjt_expl = rsp->lsrjt_expl; + +		break; + +	case BFA_STATUS_EPROTOCOL: +		lps->ext_status = rsp->ext_status; + +		break; + +	default: +		/* Nothing to do with other status */ +		break; +	} + +	bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); +} + +/** + * Firmware logout response + */ +static void +bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps; + +	bfa_assert(rsp->lp_tag < mod->num_lps); +	lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag); + +	bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); +} + +/** + * Space is available in request queue, resume queueing request to firmware. + */ +static void +bfa_lps_reqq_resume(void *lps_arg) +{ +	struct bfa_lps_s	*lps = lps_arg; + +	bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); +} + +/** + * lps is freed -- triggered by vport delete + */ +static void +bfa_lps_free(struct bfa_lps_s *lps) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(lps->bfa); + +	list_del(&lps->qe); +	list_add_tail(&lps->qe, &mod->lps_free_q); +} + +/** + * send login request to firmware + */ +static void +bfa_lps_send_login(struct bfa_lps_s *lps) +{ +	struct bfi_lps_login_req_s	*m; + +	m = bfa_reqq_next(lps->bfa, lps->reqq); +	bfa_assert(m); + +	bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, +			bfa_lpuid(lps->bfa)); + +	m->lp_tag	= lps->lp_tag; +	m->alpa		= lps->alpa; +	m->pdu_size	= bfa_os_htons(lps->pdusz); +	m->pwwn		= lps->pwwn; +	m->nwwn		= lps->nwwn; +	m->fdisc	= lps->fdisc; +	m->auth_en	= lps->auth_en; + +	bfa_reqq_produce(lps->bfa, lps->reqq); +} + +/** + * send logout request to firmware + */ +static void +bfa_lps_send_logout(struct bfa_lps_s *lps) +{ +	struct bfi_lps_logout_req_s *m; + +	m = bfa_reqq_next(lps->bfa, lps->reqq); +	bfa_assert(m); + +	bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, +			bfa_lpuid(lps->bfa)); + +	m->lp_tag    = lps->lp_tag; +	m->port_name = lps->pwwn; +	bfa_reqq_produce(lps->bfa, lps->reqq); +} + +/** + * Indirect login completion handler for non-fcs + */ +static void +bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) +{ +	struct bfa_lps_s *lps	= arg; + +	if (!complete) +		return; + +	if (lps->fdisc) +		bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); +	else +		bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); +} + +/** + * Login completion handler -- direct call for fcs, queue for others + */ +static void +bfa_lps_login_comp(struct bfa_lps_s *lps) +{ +	if (!lps->bfa->fcs) { +		bfa_cb_queue(lps->bfa, &lps->hcb_qe, +				bfa_lps_login_comp_cb, lps); +		return; +	} + +	if (lps->fdisc) +		bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); +	else +		bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); +} + +/** + * Indirect logout completion handler for non-fcs + */ +static void +bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) +{ +	struct bfa_lps_s *lps	= arg; + +	if (!complete) +		return; + +	if (lps->fdisc) +		bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); +	else +		bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); +} + +/** + * Logout completion handler -- direct call for fcs, queue for others + */ +static void +bfa_lps_logout_comp(struct bfa_lps_s *lps) +{ +	if (!lps->bfa->fcs) { +		bfa_cb_queue(lps->bfa, &lps->hcb_qe, +				bfa_lps_logout_comp_cb, lps); +		return; +	} +	if (lps->fdisc) +		bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); +	else +		bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg); +} + + + +/** + *  lps_public BFA LPS public functions + */ + +/** + * Allocate a lport srvice tag. + */ +struct bfa_lps_s  * +bfa_lps_alloc(struct bfa_s *bfa) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps = NULL; + +	bfa_q_deq(&mod->lps_free_q, &lps); + +	if (lps == NULL) +		return NULL; + +	list_add_tail(&lps->qe, &mod->lps_active_q); + +	bfa_sm_set_state(lps, bfa_lps_sm_init); +	return lps; +} + +/** + * Free lport service tag. This can be called anytime after an alloc. + * No need to wait for any pending login/logout completions. + */ +void +bfa_lps_delete(struct bfa_lps_s *lps) +{ +	bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); +} + +/** + * Initiate a lport login. + */ +void +bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, +	wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en) +{ +	lps->uarg	= uarg; +	lps->alpa	= alpa; +	lps->pdusz	= pdusz; +	lps->pwwn	= pwwn; +	lps->nwwn	= nwwn; +	lps->fdisc	= BFA_FALSE; +	lps->auth_en	= auth_en; +	bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); +} + +/** + * Initiate a lport fdisc login. + */ +void +bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, +	wwn_t nwwn) +{ +	lps->uarg	= uarg; +	lps->alpa	= 0; +	lps->pdusz	= pdusz; +	lps->pwwn	= pwwn; +	lps->nwwn	= nwwn; +	lps->fdisc	= BFA_TRUE; +	lps->auth_en	= BFA_FALSE; +	bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); +} + +/** + * Initiate a lport logout (flogi). + */ +void +bfa_lps_flogo(struct bfa_lps_s *lps) +{ +	bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); +} + +/** + * Initiate a lport FDSIC logout. + */ +void +bfa_lps_fdisclogo(struct bfa_lps_s *lps) +{ +	bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); +} + +/** + * Discard a pending login request -- should be called only for + * link down handling. + */ +void +bfa_lps_discard(struct bfa_lps_s *lps) +{ +	bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); +} + +/** + * Return lport services tag + */ +u8 +bfa_lps_get_tag(struct bfa_lps_s *lps) +{ +	return lps->lp_tag; +} + +/** + * Return lport services tag given the pid + */ +u8 +bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) +{ +	struct bfa_lps_mod_s	*mod = BFA_LPS_MOD(bfa); +	struct bfa_lps_s	*lps; +	int			i; + +	for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { +		if (lps->lp_pid == pid) +			return lps->lp_tag; +	} + +	/* Return base port tag anyway */ +	return 0; +} + +/** + * return if fabric login indicates support for NPIV + */ +bfa_boolean_t +bfa_lps_is_npiv_en(struct bfa_lps_s *lps) +{ +	return lps->npiv_en; +} + +/** + * Return TRUE if attached to F-Port, else return FALSE + */ +bfa_boolean_t +bfa_lps_is_fport(struct bfa_lps_s *lps) +{ +	return lps->fport; +} + +/** + * Return TRUE if attached to a Brocade Fabric + */ +bfa_boolean_t +bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps) +{ +	return lps->brcd_switch; +} +/** + * return TRUE if authentication is required + */ +bfa_boolean_t +bfa_lps_is_authreq(struct bfa_lps_s *lps) +{ +	return lps->auth_req; +} + +bfa_eproto_status_t +bfa_lps_get_extstatus(struct bfa_lps_s *lps) +{ +	return lps->ext_status; +} + +/** + * return port id assigned to the lport + */ +u32 +bfa_lps_get_pid(struct bfa_lps_s *lps) +{ +	return lps->lp_pid; +} + +/** + * Return bb_credit assigned in FLOGI response + */ +u16 +bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps) +{ +	return lps->pr_bbcred; +} + +/** + * Return peer port name + */ +wwn_t +bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps) +{ +	return lps->pr_pwwn; +} + +/** + * Return peer node name + */ +wwn_t +bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps) +{ +	return lps->pr_nwwn; +} + +/** + * return reason code if login request is rejected + */ +u8 +bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps) +{ +	return lps->lsrjt_rsn; +} + +/** + * return explanation code if login request is rejected + */ +u8 +bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps) +{ +	return lps->lsrjt_expl; +} + + +/** + * LPS firmware message class handler. + */ +void +bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	union bfi_lps_i2h_msg_u	msg; + +	bfa_trc(bfa, m->mhdr.msg_id); +	msg.msg = m; + +	switch (m->mhdr.msg_id) { +	case BFI_LPS_H2I_LOGIN_RSP: +		bfa_lps_login_rsp(bfa, msg.login_rsp); +		break; + +	case BFI_LPS_H2I_LOGOUT_RSP: +		bfa_lps_logout_rsp(bfa, msg.logout_rsp); +		break; + +	default: +		bfa_trc(bfa, m->mhdr.msg_id); +		bfa_assert(0); +	} +} + + diff --git a/drivers/scsi/bfa/bfa_lps_priv.h b/drivers/scsi/bfa/bfa_lps_priv.h new file mode 100644 index 00000000000..d16c6ce995d --- /dev/null +++ b/drivers/scsi/bfa/bfa_lps_priv.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_LPS_PRIV_H__ +#define __BFA_LPS_PRIV_H__ + +#include <bfa_svc.h> + +struct bfa_lps_mod_s { +	struct list_head		lps_free_q; +	struct list_head		lps_active_q; +	struct bfa_lps_s	*lps_arr; +	int			num_lps; +}; + +#define BFA_LPS_MOD(__bfa)		(&(__bfa)->modules.lps_mod) +#define BFA_LPS_FROM_TAG(__mod, __tag)	(&(__mod)->lps_arr[__tag]) + +/* + * external functions + */ +void	bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + +#endif /* __BFA_LPS_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_module.c b/drivers/scsi/bfa/bfa_module.c new file mode 100644 index 00000000000..32eda8e1ec6 --- /dev/null +++ b/drivers/scsi/bfa/bfa_module.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <bfa.h> +#include <defs/bfa_defs_pci.h> +#include <cs/bfa_debug.h> +#include <bfa_iocfc.h> + +/** + * BFA module list terminated by NULL + */ +struct bfa_module_s *hal_mods[] = { +	&hal_mod_sgpg, +	&hal_mod_pport, +	&hal_mod_fcxp, +	&hal_mod_lps, +	&hal_mod_uf, +	&hal_mod_rport, +	&hal_mod_fcpim, +#ifdef BFA_CFG_PBIND +	&hal_mod_pbind, +#endif +	NULL +}; + +/** + * Message handlers for various modules. + */ +bfa_isr_func_t  bfa_isrs[BFI_MC_MAX] = { +	bfa_isr_unhandled,	/* NONE */ +	bfa_isr_unhandled,	/* BFI_MC_IOC */ +	bfa_isr_unhandled,	/* BFI_MC_DIAG */ +	bfa_isr_unhandled,	/* BFI_MC_FLASH */ +	bfa_isr_unhandled,	/* BFI_MC_CEE */ +	bfa_pport_isr,		/* BFI_MC_PORT */ +	bfa_isr_unhandled,	/* BFI_MC_IOCFC */ +	bfa_isr_unhandled,	/* BFI_MC_LL */ +	bfa_uf_isr,		/* BFI_MC_UF */ +	bfa_fcxp_isr,		/* BFI_MC_FCXP */ +	bfa_lps_isr,		/* BFI_MC_LPS */ +	bfa_rport_isr,		/* BFI_MC_RPORT */ +	bfa_itnim_isr,		/* BFI_MC_ITNIM */ +	bfa_isr_unhandled,	/* BFI_MC_IOIM_READ */ +	bfa_isr_unhandled,	/* BFI_MC_IOIM_WRITE */ +	bfa_isr_unhandled,	/* BFI_MC_IOIM_IO */ +	bfa_ioim_isr,		/* BFI_MC_IOIM */ +	bfa_ioim_good_comp_isr,	/* BFI_MC_IOIM_IOCOM */ +	bfa_tskim_isr,		/* BFI_MC_TSKIM */ +	bfa_isr_unhandled,	/* BFI_MC_SBOOT */ +	bfa_isr_unhandled,	/* BFI_MC_IPFC */ +	bfa_isr_unhandled,	/* BFI_MC_PORT */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +	bfa_isr_unhandled,	/* --------- */ +}; + +/** + * Message handlers for mailbox command classes + */ +bfa_ioc_mbox_mcfunc_t  bfa_mbox_isrs[BFI_MC_MAX] = { +	NULL, +	NULL,			/* BFI_MC_IOC	*/ +	NULL,			/* BFI_MC_DIAG	*/ +	NULL,		/* BFI_MC_FLASH */ +	NULL,			/* BFI_MC_CEE	*/ +	NULL,			/* BFI_MC_PORT	*/ +	bfa_iocfc_isr,		/* BFI_MC_IOCFC */ +	NULL, +}; + diff --git a/drivers/scsi/bfa/bfa_modules_priv.h b/drivers/scsi/bfa/bfa_modules_priv.h new file mode 100644 index 00000000000..96f70534593 --- /dev/null +++ b/drivers/scsi/bfa/bfa_modules_priv.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_MODULES_PRIV_H__ +#define __BFA_MODULES_PRIV_H__ + +#include "bfa_uf_priv.h" +#include "bfa_port_priv.h" +#include "bfa_rport_priv.h" +#include "bfa_fcxp_priv.h" +#include "bfa_lps_priv.h" +#include "bfa_fcpim_priv.h" +#include <cee/bfa_cee.h> +#include <port/bfa_port.h> + + +struct bfa_modules_s { +	struct bfa_pport_s	pport;	/*  physical port module	*/ +	struct bfa_fcxp_mod_s fcxp_mod; /*  fcxp module		*/ +	struct bfa_lps_mod_s lps_mod;   /*  fcxp module		*/ +	struct bfa_uf_mod_s uf_mod;	/*  unsolicited frame module	*/ +	struct bfa_rport_mod_s rport_mod; /*  remote port module	*/ +	struct bfa_fcpim_mod_s fcpim_mod; /*  FCP initiator module	*/ +	struct bfa_sgpg_mod_s sgpg_mod; /*  SG page module		*/ +	struct bfa_cee_s cee;   	/*  CEE Module                 */ +	struct bfa_port_s port;		/*  Physical port module	*/ +}; + +#endif /* __BFA_MODULES_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h new file mode 100644 index 00000000000..10a89f75fa9 --- /dev/null +++ b/drivers/scsi/bfa/bfa_os_inc.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + * Contains declarations all OS Specific files needed for BFA layer + */ + +#ifndef __BFA_OS_INC_H__ +#define __BFA_OS_INC_H__ + +#ifndef __KERNEL__ +#include <stdint.h> +#else +#include <linux/types.h> + +#include <linux/version.h> +#include <linux/pci.h> + +#include <linux/dma-mapping.h> +#define SET_MODULE_VERSION(VER) + +#include <linux/idr.h> + +#include <linux/interrupt.h> +#include <linux/cdev.h> +#include <linux/fs.h> +#include <linux/delay.h> +#include <linux/vmalloc.h> + +#include <linux/workqueue.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_host.h> + +#include <scsi/scsi_tcq.h> +#include <scsi/scsi_transport_fc.h> +#include <scsi/scsi_transport.h> + +#define BFA_ERR			KERN_ERR +#define BFA_WARNING		KERN_WARNING +#define BFA_NOTICE		KERN_NOTICE +#define BFA_INFO		KERN_INFO +#define BFA_DEBUG		KERN_DEBUG + +#define LOG_BFAD_INIT		0x00000001 +#define LOG_FCP_IO		0x00000002 + +#ifdef DEBUG +#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...)			\ +		BFA_LOG(bfad, level, mask, fmt, ## arg) +#define BFA_DEV_TRACE(bfad, level, fmt, arg...)				\ +		BFA_DEV_PRINTF(bfad, level, fmt, ## arg) +#define BFA_TRACE(level, fmt, arg...)					\ +		BFA_PRINTF(level, fmt, ## arg) +#else +#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) +#define BFA_DEV_TRACE(bfad, level, fmt, arg...) +#define BFA_TRACE(level, fmt, arg...) +#endif + +#define BFA_ASSERT(p) do {						\ +	if (!(p)) {      \ +		printk(KERN_ERR "assert(%s) failed at %s:%d\n",		\ +		#p, __FILE__, __LINE__);      \ +		BUG();      \ +	}								\ +} while (0) + + +#define BFA_LOG(bfad, level, mask, fmt, arg...)				\ +do { 									\ +	if (((mask) & (((struct bfad_s *)(bfad))->			\ +		cfg_data[cfg_log_mask])) || (level[1] <= '3'))		\ +		dev_printk(level, &(((struct bfad_s *)			\ +			(bfad))->pcidev->dev), fmt, ##arg);      \ +} while (0) + +#ifndef BFA_DEV_PRINTF +#define BFA_DEV_PRINTF(bfad, level, fmt, arg...)			\ +		dev_printk(level, &(((struct bfad_s *)			\ +			(bfad))->pcidev->dev), fmt, ##arg); +#endif + +#define BFA_PRINTF(level, fmt, arg...)					\ +		printk(level fmt, ##arg); + +int bfa_os_MWB(void *); + +#define bfa_os_mmiowb()		mmiowb() + +#define bfa_swap_3b(_x)				\ +	((((_x) & 0xff) << 16) |		\ +	((_x) & 0x00ff00) |			\ +	(((_x) & 0xff0000) >> 16)) + +#define bfa_swap_8b(_x) 				\ +     ((((_x) & 0xff00000000000000ull) >> 56)		\ +      | (((_x) & 0x00ff000000000000ull) >> 40)		\ +      | (((_x) & 0x0000ff0000000000ull) >> 24)		\ +      | (((_x) & 0x000000ff00000000ull) >> 8)		\ +      | (((_x) & 0x00000000ff000000ull) << 8)		\ +      | (((_x) & 0x0000000000ff0000ull) << 24)		\ +      | (((_x) & 0x000000000000ff00ull) << 40)		\ +      | (((_x) & 0x00000000000000ffull) << 56)) + +#define bfa_os_swap32(_x) 			\ +	((((_x) & 0xff) << 24) 		|	\ +	(((_x) & 0x0000ff00) << 8)	|	\ +	(((_x) & 0x00ff0000) >> 8)	|	\ +	(((_x) & 0xff000000) >> 24)) + + +#ifndef __BIGENDIAN +#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \ +				 (((_x) & 0x00ff) << 8))) + +#define bfa_os_htonl(_x)	bfa_os_swap32(_x) +#define bfa_os_htonll(_x)	bfa_swap_8b(_x) +#define bfa_os_hton3b(_x)	bfa_swap_3b(_x) + +#define bfa_os_wtole(_x)   (_x) + +#else + +#define bfa_os_htons(_x)   (_x) +#define bfa_os_htonl(_x)   (_x) +#define bfa_os_hton3b(_x)  (_x) +#define bfa_os_htonll(_x)  (_x) +#define bfa_os_wtole(_x)   bfa_os_swap32(_x) + +#endif + +#define bfa_os_ntohs(_x)   bfa_os_htons(_x) +#define bfa_os_ntohl(_x)   bfa_os_htonl(_x) +#define bfa_os_ntohll(_x)  bfa_os_htonll(_x) +#define bfa_os_ntoh3b(_x)  bfa_os_hton3b(_x) + +#define bfa_os_u32(__pa64) ((__pa64) >> 32) + +#define bfa_os_memset	memset +#define bfa_os_memcpy	memcpy +#define bfa_os_udelay	udelay +#define bfa_os_vsprintf vsprintf + +#define bfa_os_assign(__t, __s) __t = __s + +#define bfa_os_addr_t char __iomem * +#define bfa_os_panic() + +#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr)) +#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr)) +#define bfa_os_mem_read(_raddr, _off)                                   \ +	bfa_os_ntohl(readl(((_raddr) + (_off)))) +#define bfa_os_mem_write(_raddr, _off, _val)                            \ +	writel(bfa_os_htonl((_val)), ((_raddr) + (_off))) + +#define BFA_TRC_TS(_trcm)						\ +			({						\ +				struct timeval tv;			\ +									\ +				do_gettimeofday(&tv);      \ +				(tv.tv_sec*1000000+tv.tv_usec);      \ +			 }) + +struct bfa_log_mod_s; +void bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id, +			const char *fmt, ...); +#endif + +#define boolean_t int + +/** + * For current time stamp, OS API will fill-in + */ +struct bfa_timeval_s { +	u32	tv_sec;		/*  seconds        */ +	u32	tv_usec;	/*  microseconds   */ +}; + +void bfa_os_gettimeofday(struct bfa_timeval_s *tv); + +static inline void +wwn2str(char *wwn_str, u64 wwn) +{ +	union { +		u64 wwn; +		u8 byte[8]; +	} w; + +	w.wwn = wwn; +	sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0], +		w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5], +		w.byte[6], w.byte[7]); +} + +static inline void +fcid2str(char *fcid_str, u32 fcid) +{ +	union { +		u32 fcid; +		u8 byte[4]; +	} f; + +	f.fcid = fcid; +	sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]); +} + +#endif /* __BFA_OS_INC_H__ */ diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c new file mode 100644 index 00000000000..cab19028361 --- /dev/null +++ b/drivers/scsi/bfa/bfa_port.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <defs/bfa_defs_port.h> +#include <cs/bfa_trc.h> +#include <cs/bfa_log.h> +#include <cs/bfa_debug.h> +#include <port/bfa_port.h> +#include <bfi/bfi.h> +#include <bfi/bfi_port.h> +#include <bfa_ioc.h> +#include <cna/bfa_cna_trcmod.h> + +BFA_TRC_FILE(CNA, PORT); + +#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) +#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc) + +static void +bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats) +{ +	u32       *dip = (u32 *) stats; +	u32        t0, t1; +	int             i; + +	for (i = 0; i < sizeof(union bfa_pport_stats_u) / sizeof(u32); +	     i += 2) { +		t0 = dip[i]; +		t1 = dip[i + 1]; +#ifdef __BIGENDIAN +		dip[i] = bfa_os_ntohl(t0); +		dip[i + 1] = bfa_os_ntohl(t1); +#else +		dip[i] = bfa_os_ntohl(t1); +		dip[i + 1] = bfa_os_ntohl(t0); +#endif +	} + +    /** todo +     * QoS stats r also swapped as 64bit; that structure also +     * has to use 64 bit counters +     */ +} + +/** + * bfa_port_enable_isr() + * + * + * @param[in] port - Pointer to the port module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) +{ +	bfa_assert(0); +} + +/** + * bfa_port_disable_isr() + * + * + * @param[in] port - Pointer to the port module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status) +{ +	bfa_assert(0); +} + +/** + * bfa_port_get_stats_isr() + * + * + * @param[in] port - Pointer to the Port module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) +{ +	port->stats_status = status; +	port->stats_busy = BFA_FALSE; + +	if (status == BFA_STATUS_OK) { +		memcpy(port->stats, port->stats_dma.kva, +		       sizeof(union bfa_pport_stats_u)); +		bfa_port_stats_swap(port, port->stats); +	} + +	if (port->stats_cbfn) { +		port->stats_cbfn(port->stats_cbarg, status); +		port->stats_cbfn = NULL; +	} +} + +/** + * bfa_port_clear_stats_isr() + * + * + * @param[in] port - Pointer to the Port module + *            status - Return status from the f/w + * + * @return void + */ +static void +bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) +{ +	port->stats_status = status; +	port->stats_busy = BFA_FALSE; + +	if (port->stats_cbfn) { +		port->stats_cbfn(port->stats_cbarg, status); +		port->stats_cbfn = NULL; +	} +} + +/** + * bfa_port_isr() + * + * + * @param[in] Pointer to the Port module data structure. + * + * @return void + */ +static void +bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) +{ +	struct bfa_port_s *port = (struct bfa_port_s *)cbarg; +	union bfi_port_i2h_msg_u *i2hmsg; + +	i2hmsg = (union bfi_port_i2h_msg_u *)m; +	bfa_trc(port, m->mh.msg_id); + +	switch (m->mh.msg_id) { +	case BFI_PORT_I2H_ENABLE_RSP: +		if (port->endis_pending == BFA_FALSE) +			break; +		bfa_port_enable_isr(port, i2hmsg->enable_rsp.status); +		break; + +	case BFI_PORT_I2H_DISABLE_RSP: +		if (port->endis_pending == BFA_FALSE) +			break; +		bfa_port_disable_isr(port, i2hmsg->disable_rsp.status); +		break; + +	case BFI_PORT_I2H_GET_STATS_RSP: +		/* +		 * Stats busy flag is still set? (may be cmd timed out) +		 */ +		if (port->stats_busy == BFA_FALSE) +			break; +		bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status); +		break; + +	case BFI_PORT_I2H_CLEAR_STATS_RSP: +		if (port->stats_busy == BFA_FALSE) +			break; +		bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * bfa_port_meminfo() + * + * + * @param[in] void + * + * @return Size of DMA region + */ +u32 +bfa_port_meminfo(void) +{ +	return BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), BFA_DMA_ALIGN_SZ); +} + +/** + * bfa_port_mem_claim() + * + * + * @param[in] port Port module pointer + * 	      dma_kva Kernel Virtual Address of Port DMA Memory + * 	      dma_pa  Physical Address of Port DMA Memory + * + * @return void + */ +void +bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) +{ +	port->stats_dma.kva = dma_kva; +	port->stats_dma.pa = dma_pa; +} + +/** + * bfa_port_enable() + * + *   Send the Port enable request to the f/w + * + * @param[in] Pointer to the Port module data structure. + * + * @return Status + */ +bfa_status_t +bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, +		void *cbarg) +{ +	struct bfi_port_generic_req_s *m; + +	/** todo Not implemented */ +	bfa_assert(0); + +	if (!bfa_ioc_is_operational(port->ioc)) { +		bfa_trc(port, BFA_STATUS_IOC_FAILURE); +		return BFA_STATUS_IOC_FAILURE; +	} + +	if (port->endis_pending) { +		bfa_trc(port, BFA_STATUS_DEVBUSY); +		return BFA_STATUS_DEVBUSY; +	} + +	m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; + +	port->msgtag++; +	port->endis_cbfn = cbfn; +	port->endis_cbarg = cbarg; +	port->endis_pending = BFA_TRUE; + +	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ, +		    bfa_ioc_portid(port->ioc)); +	bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); + +	return BFA_STATUS_OK; +} + +/** + * bfa_port_disable() + * + *   Send the Port disable request to the f/w + * + * @param[in] Pointer to the Port module data structure. + * + * @return Status + */ +bfa_status_t +bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, +		 void *cbarg) +{ +	struct bfi_port_generic_req_s *m; + +	/** todo Not implemented */ +	bfa_assert(0); + +	if (!bfa_ioc_is_operational(port->ioc)) { +		bfa_trc(port, BFA_STATUS_IOC_FAILURE); +		return BFA_STATUS_IOC_FAILURE; +	} + +	if (port->endis_pending) { +		bfa_trc(port, BFA_STATUS_DEVBUSY); +		return BFA_STATUS_DEVBUSY; +	} + +	m = (struct bfi_port_generic_req_s *)port->endis_mb.msg; + +	port->msgtag++; +	port->endis_cbfn = cbfn; +	port->endis_cbarg = cbarg; +	port->endis_pending = BFA_TRUE; + +	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ, +		    bfa_ioc_portid(port->ioc)); +	bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); + +	return BFA_STATUS_OK; +} + +/** + * bfa_port_get_stats() + * + *   Send the request to the f/w to fetch Port statistics. + * + * @param[in] Pointer to the Port module data structure. + * + * @return Status + */ +bfa_status_t +bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats, +		   bfa_port_stats_cbfn_t cbfn, void *cbarg) +{ +	struct bfi_port_get_stats_req_s *m; + +	if (!bfa_ioc_is_operational(port->ioc)) { +		bfa_trc(port, BFA_STATUS_IOC_FAILURE); +		return BFA_STATUS_IOC_FAILURE; +	} + +	if (port->stats_busy) { +		bfa_trc(port, BFA_STATUS_DEVBUSY); +		return BFA_STATUS_DEVBUSY; +	} + +	m = (struct bfi_port_get_stats_req_s *)port->stats_mb.msg; + +	port->stats = stats; +	port->stats_cbfn = cbfn; +	port->stats_cbarg = cbarg; +	port->stats_busy = BFA_TRUE; +	bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa); + +	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ, +		    bfa_ioc_portid(port->ioc)); +	bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); + +	return BFA_STATUS_OK; +} + +/** + * bfa_port_clear_stats() + * + * + * @param[in] Pointer to the Port module data structure. + * + * @return Status + */ +bfa_status_t +bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, +		     void *cbarg) +{ +	struct bfi_port_generic_req_s *m; + +	if (!bfa_ioc_is_operational(port->ioc)) { +		bfa_trc(port, BFA_STATUS_IOC_FAILURE); +		return BFA_STATUS_IOC_FAILURE; +	} + +	if (port->stats_busy) { +		bfa_trc(port, BFA_STATUS_DEVBUSY); +		return BFA_STATUS_DEVBUSY; +	} + +	m = (struct bfi_port_generic_req_s *)port->stats_mb.msg; + +	port->stats_cbfn = cbfn; +	port->stats_cbarg = cbarg; +	port->stats_busy = BFA_TRUE; + +	bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ, +		    bfa_ioc_portid(port->ioc)); +	bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); + +	return BFA_STATUS_OK; +} + +/** + * bfa_port_hbfail() + * + * + * @param[in] Pointer to the Port module data structure. + * + * @return void + */ +void +bfa_port_hbfail(void *arg) +{ +	struct bfa_port_s *port = (struct bfa_port_s *)arg; + +	/* +	 * Fail any pending get_stats/clear_stats requests +	 */ +	if (port->stats_busy) { +		if (port->stats_cbfn) +			port->stats_cbfn(port->dev, BFA_STATUS_FAILED); +		port->stats_cbfn = NULL; +		port->stats_busy = BFA_FALSE; +	} + +	/* +	 * Clear any enable/disable is pending +	 */ +	if (port->endis_pending) { +		if (port->endis_cbfn) +			port->endis_cbfn(port->dev, BFA_STATUS_FAILED); +		port->endis_cbfn = NULL; +		port->endis_pending = BFA_FALSE; +	} +} + +/** + * bfa_port_attach() + * + * + * @param[in] port - Pointer to the Port module data structure + *            ioc  - Pointer to the ioc module data structure + *            dev  - Pointer to the device driver module data structure + *                   The device driver specific mbox ISR functions have + *                   this pointer as one of the parameters. + *            trcmod - + *            logmod - + * + * @return void + */ +void +bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, +		struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) +{ +	bfa_assert(port); + +	port->dev = dev; +	port->ioc = ioc; +	port->trcmod = trcmod; +	port->logmod = logmod; + +	port->stats_busy = port->endis_pending = BFA_FALSE; +	port->stats_cbfn = port->endis_cbfn = NULL; + +	bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); +	bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); +	bfa_ioc_hbfail_register(port->ioc, &port->hbfail); + +	bfa_trc(port, 0); +} + +/** + * bfa_port_detach() + * + * + * @param[in] port - Pointer to the Port module data structure + * + * @return void + */ +void +bfa_port_detach(struct bfa_port_s *port) +{ +	bfa_trc(port, 0); +} diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h new file mode 100644 index 00000000000..4b97e275990 --- /dev/null +++ b/drivers/scsi/bfa/bfa_port_priv.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_PORT_PRIV_H__ +#define __BFA_PORT_PRIV_H__ + +#include <defs/bfa_defs_pport.h> +#include <bfi/bfi_pport.h> +#include "bfa_intr_priv.h" + +/** + * BFA physical port data structure + */ +struct bfa_pport_s { +	struct bfa_s 		*bfa;	/*  parent BFA instance */ +	bfa_sm_t		sm;	/*  port state machine */ +	wwn_t			nwwn;	/*  node wwn of physical port */ +	wwn_t			pwwn;	/*  port wwn of physical oprt */ +	enum bfa_pport_speed speed_sup; +					/*  supported speeds */ +	enum bfa_pport_speed speed;	/*  current speed */ +	enum bfa_pport_topology topology;	/*  current topology */ +	u8			myalpa;	/*  my ALPA in LOOP topology */ +	u8			rsvd[3]; +	struct bfa_pport_cfg_s	cfg;	/*  current port configuration */ +	struct bfa_qos_attr_s  qos_attr;   /* QoS Attributes */ +	struct bfa_qos_vc_attr_s qos_vc_attr;  /*  VC info from ELP */ +	struct bfa_reqq_wait_s	reqq_wait; +					/*  to wait for room in reqq */ +	struct bfa_reqq_wait_s	svcreq_wait; +					/*  to wait for room in reqq */ +	struct bfa_reqq_wait_s	stats_reqq_wait; +					/*  to wait for room in reqq (stats) */ +	void			*event_cbarg; +	void			(*event_cbfn) (void *cbarg, +						bfa_pport_event_t event); +	union { +		union bfi_pport_i2h_msg_u i2hmsg; +	} event_arg; +	void			*bfad;	/*  BFA driver handle */ +	struct bfa_cb_qe_s		hcb_qe;	/*  BFA callback queue elem */ +	enum bfa_pport_linkstate	hcb_event; +					/*  link event for callback */ +	u32		msgtag;	/*  fimrware msg tag for reply */ +	u8			*stats_kva; +	u64		stats_pa; +	union bfa_pport_stats_u *stats;	/*  pport stats */ +	u32		mypid : 24; +	u32		rsvd_b : 8; +	struct bfa_timer_s 	timer;	/*  timer */ +	union bfa_pport_stats_u 	*stats_ret; +					/*  driver stats location */ +	bfa_status_t		stats_status; +					/*  stats/statsclr status */ +	bfa_boolean_t   	stats_busy; +					/*  outstanding stats/statsclr */ +	bfa_boolean_t   	stats_qfull; +	bfa_boolean_t   	diag_busy; +					/*  diag busy status */ +	bfa_boolean_t   	beacon; +					/*  port beacon status */ +	bfa_boolean_t   	link_e2e_beacon; +					/*  link beacon status */ +	bfa_cb_pport_t		stats_cbfn; +					/*  driver callback function */ +	void			*stats_cbarg; +					/* *!< user callback arg */ +}; + +#define BFA_PORT_MOD(__bfa)	(&(__bfa)->modules.pport) + +/* + * public functions + */ +void	bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +#endif /* __BFA_PORT_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h new file mode 100644 index 00000000000..0747a6b26f7 --- /dev/null +++ b/drivers/scsi/bfa/bfa_priv.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_PRIV_H__ +#define __BFA_PRIV_H__ + +#include "bfa_iocfc.h" +#include "bfa_intr_priv.h" +#include "bfa_trcmod_priv.h" +#include "bfa_modules_priv.h" +#include "bfa_fwimg_priv.h" +#include <cs/bfa_log.h> +#include <bfa_timer.h> + +/** + * Macro to define a new BFA module + */ +#define BFA_MODULE(__mod) 						\ +	static void bfa_ ## __mod ## _meminfo(				\ +			struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,	\ +			u32 *dm_len);      \ +	static void bfa_ ## __mod ## _attach(struct bfa_s *bfa,		\ +			void *bfad, struct bfa_iocfc_cfg_s *cfg, 	\ +			struct bfa_meminfo_s *meminfo,			\ +			struct bfa_pcidev_s *pcidev);      \ +	static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa);      \ +	static void bfa_ ## __mod ## _detach(struct bfa_s *bfa);      \ +	static void bfa_ ## __mod ## _start(struct bfa_s *bfa);      \ +	static void bfa_ ## __mod ## _stop(struct bfa_s *bfa);      \ +	static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa);      \ +									\ +	extern struct bfa_module_s hal_mod_ ## __mod;			\ +	struct bfa_module_s hal_mod_ ## __mod = {			\ +		bfa_ ## __mod ## _meminfo,				\ +		bfa_ ## __mod ## _attach,				\ +		bfa_ ## __mod ## _initdone,				\ +		bfa_ ## __mod ## _detach,				\ +		bfa_ ## __mod ## _start,				\ +		bfa_ ## __mod ## _stop,					\ +		bfa_ ## __mod ## _iocdisable,				\ +	} + +#define BFA_CACHELINE_SZ	(256) + +/** + * Structure used to interact between different BFA sub modules + * + * Each sub module needs to implement only the entry points relevant to it (and + * can leave entry points as NULL) + */ +struct bfa_module_s { +	void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +			u32 *dm_len); +	void (*attach) (struct bfa_s *bfa, void *bfad, +			struct bfa_iocfc_cfg_s *cfg, +			struct bfa_meminfo_s *meminfo, +			struct bfa_pcidev_s *pcidev); +	void (*initdone) (struct bfa_s *bfa); +	void (*detach) (struct bfa_s *bfa); +	void (*start) (struct bfa_s *bfa); +	void (*stop) (struct bfa_s *bfa); +	void (*iocdisable) (struct bfa_s *bfa); +}; + +extern struct bfa_module_s *hal_mods[]; + +struct bfa_s { +	void			*bfad;		/*  BFA driver instance    */ +	struct bfa_aen_s	*aen;		/*  AEN module		    */ +	struct bfa_plog_s	*plog;		/*  portlog buffer	    */ +	struct bfa_log_mod_s	*logm;		/*  driver logging modulen */ +	struct bfa_trc_mod_s	*trcmod;	/*  driver tracing	    */ +	struct bfa_ioc_s	ioc;		/*  IOC module		    */ +	struct bfa_iocfc_s	iocfc;		/*  IOCFC module	    */ +	struct bfa_timer_mod_s	timer_mod;	/*  timer module	    */ +	struct bfa_modules_s	modules;	/*  BFA modules	    */ +	struct list_head	comp_q;		/*  pending completions    */ +	bfa_boolean_t		rme_process;	/*  RME processing enabled */ +	struct list_head		reqq_waitq[BFI_IOC_MAX_CQS]; +	bfa_boolean_t		fcs;		/*  FCS is attached to BFA */ +	struct bfa_msix_s	msix; +}; + +extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX]; +extern bfa_ioc_mbox_mcfunc_t  bfa_mbox_isrs[]; +extern bfa_boolean_t bfa_auto_recover; +extern struct bfa_module_s hal_mod_flash; +extern struct bfa_module_s hal_mod_fcdiag; +extern struct bfa_module_s hal_mod_sgpg; +extern struct bfa_module_s hal_mod_pport; +extern struct bfa_module_s hal_mod_fcxp; +extern struct bfa_module_s hal_mod_lps; +extern struct bfa_module_s hal_mod_uf; +extern struct bfa_module_s hal_mod_rport; +extern struct bfa_module_s hal_mod_fcpim; +extern struct bfa_module_s hal_mod_pbind; + +#endif /* __BFA_PRIV_H__ */ + diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c new file mode 100644 index 00000000000..16da77a8db2 --- /dev/null +++ b/drivers/scsi/bfa/bfa_rport.c @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include <cs/bfa_debug.h> +#include <bfi/bfi_rport.h> +#include "bfa_intr_priv.h" + +BFA_TRC_FILE(HAL, RPORT); +BFA_MODULE(rport); + +#define bfa_rport_offline_cb(__rp) do {				\ +	if ((__rp)->bfa->fcs)						\ +		bfa_cb_rport_offline((__rp)->rport_drv);      \ +	else {								\ +		bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe,		\ +				__bfa_cb_rport_offline, (__rp));      \ +	}								\ +} while (0) + +#define bfa_rport_online_cb(__rp) do {				\ +	if ((__rp)->bfa->fcs)						\ +		bfa_cb_rport_online((__rp)->rport_drv);      \ +	else {								\ +		bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe,		\ +				  __bfa_cb_rport_online, (__rp));      \ +		}							\ +} while (0) + +/* + * forward declarations + */ +static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod); +static void bfa_rport_free(struct bfa_rport_s *rport); +static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp); +static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp); +static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp); +static void __bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete); +static void __bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete); + +/** + *  bfa_rport_sm BFA rport state machine + */ + + +enum bfa_rport_event { +	BFA_RPORT_SM_CREATE	= 1,	/*  rport create event		*/ +	BFA_RPORT_SM_DELETE	= 2,	/*  deleting an existing rport */ +	BFA_RPORT_SM_ONLINE	= 3,	/*  rport is online		*/ +	BFA_RPORT_SM_OFFLINE	= 4,	/*  rport is offline		*/ +	BFA_RPORT_SM_FWRSP	= 5,	/*  firmware response		*/ +	BFA_RPORT_SM_HWFAIL	= 6,	/*  IOC h/w failure		*/ +	BFA_RPORT_SM_QOS_SCN	= 7,	/*  QoS SCN from firmware	*/ +	BFA_RPORT_SM_SET_SPEED	= 8,	/*  Set Rport Speed 		*/ +	BFA_RPORT_SM_QRESUME	= 9,	/*  space in requeue queue	*/ +}; + +static void	bfa_rport_sm_uninit(struct bfa_rport_s *rp, +					enum bfa_rport_event event); +static void	bfa_rport_sm_created(struct bfa_rport_s *rp, +					 enum bfa_rport_event event); +static void	bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_online(struct bfa_rport_s *rp, +					enum bfa_rport_event event); +static void	bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_offline(struct bfa_rport_s *rp, +					 enum bfa_rport_event event); +static void	bfa_rport_sm_deleting(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, +					    enum bfa_rport_event event); +static void	bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); +static void	bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, +					  enum bfa_rport_event event); + +/** + * Beginning state, only online event expected. + */ +static void +bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_CREATE: +		bfa_stats(rp, sm_un_cr); +		bfa_sm_set_state(rp, bfa_rport_sm_created); +		break; + +	default: +		bfa_stats(rp, sm_un_unexp); +		bfa_assert(0); +	} +} + +static void +bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_ONLINE: +		bfa_stats(rp, sm_cr_on); +		if (bfa_rport_send_fwcreate(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_cr_del); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_cr_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		break; + +	default: +		bfa_stats(rp, sm_cr_unexp); +		bfa_assert(0); +	} +} + +/** + * Waiting for rport create response from firmware. + */ +static void +bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_FWRSP: +		bfa_stats(rp, sm_fwc_rsp); +		bfa_sm_set_state(rp, bfa_rport_sm_online); +		bfa_rport_online_cb(rp); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_fwc_del); +		bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); +		break; + +	case BFA_RPORT_SM_OFFLINE: +		bfa_stats(rp, sm_fwc_off); +		bfa_sm_set_state(rp, bfa_rport_sm_offline_pending); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_fwc_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		break; + +	default: +		bfa_stats(rp, sm_fwc_unexp); +		bfa_assert(0); +	} +} + +/** + * Request queue is full, awaiting queue resume to send create request. + */ +static void +bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_QRESUME: +		bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); +		bfa_rport_send_fwcreate(rp); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_fwc_del); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_reqq_wcancel(&rp->reqq_wait); +		bfa_rport_free(rp); +		break; + +	case BFA_RPORT_SM_OFFLINE: +		bfa_stats(rp, sm_fwc_off); +		bfa_sm_set_state(rp, bfa_rport_sm_offline); +		bfa_reqq_wcancel(&rp->reqq_wait); +		bfa_rport_offline_cb(rp); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_fwc_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		bfa_reqq_wcancel(&rp->reqq_wait); +		break; + +	default: +		bfa_stats(rp, sm_fwc_unexp); +		bfa_assert(0); +	} +} + +/** + * Online state - normal parking state. + */ +static void +bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	struct bfi_rport_qos_scn_s *qos_scn; + +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_OFFLINE: +		bfa_stats(rp, sm_on_off); +		if (bfa_rport_send_fwdelete(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_on_del); +		if (bfa_rport_send_fwdelete(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_deleting); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_on_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		break; + +	case BFA_RPORT_SM_SET_SPEED: +		bfa_rport_send_fwspeed(rp); +		break; + +	case BFA_RPORT_SM_QOS_SCN: +		qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg; +		rp->qos_attr = qos_scn->new_qos_attr; +		bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id); +		bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id); +		bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority); +		bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority); + +		qos_scn->old_qos_attr.qos_flow_id  = +			bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id); +		qos_scn->new_qos_attr.qos_flow_id  = +			bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id); +		qos_scn->old_qos_attr.qos_priority = +			bfa_os_ntohl(qos_scn->old_qos_attr.qos_priority); +		qos_scn->new_qos_attr.qos_priority = +			bfa_os_ntohl(qos_scn->new_qos_attr.qos_priority); + +		if (qos_scn->old_qos_attr.qos_flow_id != +			qos_scn->new_qos_attr.qos_flow_id) +			bfa_cb_rport_qos_scn_flowid(rp->rport_drv, +						    qos_scn->old_qos_attr, +						    qos_scn->new_qos_attr); +		if (qos_scn->old_qos_attr.qos_priority != +			qos_scn->new_qos_attr.qos_priority) +			bfa_cb_rport_qos_scn_prio(rp->rport_drv, +						  qos_scn->old_qos_attr, +						  qos_scn->new_qos_attr); +		break; + +	default: +		bfa_stats(rp, sm_on_unexp); +		bfa_assert(0); +	} +} + +/** + * Firmware rport is being deleted - awaiting f/w response. + */ +static void +bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_FWRSP: +		bfa_stats(rp, sm_fwd_rsp); +		bfa_sm_set_state(rp, bfa_rport_sm_offline); +		bfa_rport_offline_cb(rp); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_fwd_del); +		bfa_sm_set_state(rp, bfa_rport_sm_deleting); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_fwd_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		bfa_rport_offline_cb(rp); +		break; + +	default: +		bfa_stats(rp, sm_fwd_unexp); +		bfa_assert(0); +	} +} + +static void +bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_QRESUME: +		bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); +		bfa_rport_send_fwdelete(rp); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_fwd_del); +		bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_fwd_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		bfa_reqq_wcancel(&rp->reqq_wait); +		bfa_rport_offline_cb(rp); +		break; + +	default: +		bfa_stats(rp, sm_fwd_unexp); +		bfa_assert(0); +	} +} + +/** + * Offline state. + */ +static void +bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_off_del); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	case BFA_RPORT_SM_ONLINE: +		bfa_stats(rp, sm_off_on); +		if (bfa_rport_send_fwcreate(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_off_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		break; + +	default: +		bfa_stats(rp, sm_off_unexp); +		bfa_assert(0); +	} +} + +/** + * Rport is deleted, waiting for firmware response to delete. + */ +static void +bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_FWRSP: +		bfa_stats(rp, sm_del_fwrsp); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_del_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_QRESUME: +		bfa_stats(rp, sm_del_fwrsp); +		bfa_sm_set_state(rp, bfa_rport_sm_deleting); +		bfa_rport_send_fwdelete(rp); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_del_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_reqq_wcancel(&rp->reqq_wait); +		bfa_rport_free(rp); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Waiting for rport create response from firmware. A delete is pending. + */ +static void +bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, +				enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_FWRSP: +		bfa_stats(rp, sm_delp_fwrsp); +		if (bfa_rport_send_fwdelete(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_deleting); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_delp_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	default: +		bfa_stats(rp, sm_delp_unexp); +		bfa_assert(0); +	} +} + +/** + * Waiting for rport create response from firmware. Rport offline is pending. + */ +static void +bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, +				 enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_FWRSP: +		bfa_stats(rp, sm_offp_fwrsp); +		if (bfa_rport_send_fwdelete(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_offp_del); +		bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		bfa_stats(rp, sm_offp_hwf); +		bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); +		break; + +	default: +		bfa_stats(rp, sm_offp_unexp); +		bfa_assert(0); +	} +} + +/** + * IOC h/w failed. + */ +static void +bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event) +{ +	bfa_trc(rp->bfa, rp->rport_tag); +	bfa_trc(rp->bfa, event); + +	switch (event) { +	case BFA_RPORT_SM_OFFLINE: +		bfa_stats(rp, sm_iocd_off); +		bfa_rport_offline_cb(rp); +		break; + +	case BFA_RPORT_SM_DELETE: +		bfa_stats(rp, sm_iocd_del); +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); +		bfa_rport_free(rp); +		break; + +	case BFA_RPORT_SM_ONLINE: +		bfa_stats(rp, sm_iocd_on); +		if (bfa_rport_send_fwcreate(rp)) +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); +		else +			bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); +		break; + +	case BFA_RPORT_SM_HWFAIL: +		break; + +	default: +		bfa_stats(rp, sm_iocd_unexp); +		bfa_assert(0); +	} +} + + + +/** + *  bfa_rport_private BFA rport private functions + */ + +static void +__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_rport_s *rp = cbarg; + +	if (complete) +		bfa_cb_rport_online(rp->rport_drv); +} + +static void +__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_rport_s *rp = cbarg; + +	if (complete) +		bfa_cb_rport_offline(rp->rport_drv); +} + +static void +bfa_rport_qresume(void *cbarg) +{ +	struct bfa_rport_s	*rp = cbarg; + +	bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME); +} + +static void +bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len) +{ +	if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) +		cfg->fwcfg.num_rports = BFA_RPORT_MIN; + +	*km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s); +} + +static void +bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		     struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); +	struct bfa_rport_s *rp; +	u16        i; + +	INIT_LIST_HEAD(&mod->rp_free_q); +	INIT_LIST_HEAD(&mod->rp_active_q); + +	rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo); +	mod->rps_list = rp; +	mod->num_rports = cfg->fwcfg.num_rports; + +	bfa_assert(mod->num_rports +		   && !(mod->num_rports & (mod->num_rports - 1))); + +	for (i = 0; i < mod->num_rports; i++, rp++) { +		bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s)); +		rp->bfa = bfa; +		rp->rport_tag = i; +		bfa_sm_set_state(rp, bfa_rport_sm_uninit); + +		/** +		 *  - is unused +		 */ +		if (i) +			list_add_tail(&rp->qe, &mod->rp_free_q); + +		bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp); +	} + +	/** +	 * consume memory +	 */ +	bfa_meminfo_kva(meminfo) = (u8 *) rp; +} + +static void +bfa_rport_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_start(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_rport_iocdisable(struct bfa_s *bfa) +{ +	struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); +	struct bfa_rport_s *rport; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &mod->rp_active_q) { +		rport = (struct bfa_rport_s *) qe; +		bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); +	} +} + +static struct bfa_rport_s * +bfa_rport_alloc(struct bfa_rport_mod_s *mod) +{ +	struct bfa_rport_s *rport; + +	bfa_q_deq(&mod->rp_free_q, &rport); +	if (rport) +		list_add_tail(&rport->qe, &mod->rp_active_q); + +	return (rport); +} + +static void +bfa_rport_free(struct bfa_rport_s *rport) +{ +	struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa); + +	bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport)); +	list_del(&rport->qe); +	list_add_tail(&rport->qe, &mod->rp_free_q); +} + +static bfa_boolean_t +bfa_rport_send_fwcreate(struct bfa_rport_s *rp) +{ +	struct bfi_rport_create_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); +	if (!m) { +		bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, +			bfa_lpuid(rp->bfa)); +	m->bfa_handle = rp->rport_tag; +	m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz); +	m->pid = rp->rport_info.pid; +	m->lp_tag = rp->rport_info.lp_tag; +	m->local_pid = rp->rport_info.local_pid; +	m->fc_class = rp->rport_info.fc_class; +	m->vf_en = rp->rport_info.vf_en; +	m->vf_id = rp->rport_info.vf_id; +	m->cisc = rp->rport_info.cisc; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); +	return BFA_TRUE; +} + +static bfa_boolean_t +bfa_rport_send_fwdelete(struct bfa_rport_s *rp) +{ +	struct bfi_rport_delete_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); +	if (!m) { +		bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, +			bfa_lpuid(rp->bfa)); +	m->fw_handle = rp->fw_handle; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); +	return BFA_TRUE; +} + +static bfa_boolean_t +bfa_rport_send_fwspeed(struct bfa_rport_s *rp) +{ +	struct bfa_rport_speed_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); +	if (!m) { +		bfa_trc(rp->bfa, rp->rport_info.speed); +		return BFA_FALSE; +	} + +	bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, +			bfa_lpuid(rp->bfa)); +	m->fw_handle = rp->fw_handle; +	m->speed = (u8)rp->rport_info.speed; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT); +	return BFA_TRUE; +} + + + +/** + *  bfa_rport_public + */ + +/** + * 		Rport interrupt processing. + */ +void +bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	union bfi_rport_i2h_msg_u msg; +	struct bfa_rport_s *rp; + +	bfa_trc(bfa, m->mhdr.msg_id); + +	msg.msg = m; + +	switch (m->mhdr.msg_id) { +	case BFI_RPORT_I2H_CREATE_RSP: +		rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle); +		rp->fw_handle = msg.create_rsp->fw_handle; +		rp->qos_attr = msg.create_rsp->qos_attr; +		bfa_assert(msg.create_rsp->status == BFA_STATUS_OK); +		bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); +		break; + +	case BFI_RPORT_I2H_DELETE_RSP: +		rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle); +		bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK); +		bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); +		break; + +	case BFI_RPORT_I2H_QOS_SCN: +		rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle); +		rp->event_arg.fw_msg = msg.qos_scn_evt; +		bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN); +		break; + +	default: +		bfa_trc(bfa, m->mhdr.msg_id); +		bfa_assert(0); +	} +} + + + +/** + *  bfa_rport_api + */ + +struct bfa_rport_s * +bfa_rport_create(struct bfa_s *bfa, void *rport_drv) +{ +	struct bfa_rport_s *rp; + +	rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa)); + +	if (rp == NULL) +		return (NULL); + +	rp->bfa = bfa; +	rp->rport_drv = rport_drv; +	bfa_rport_clear_stats(rp); + +	bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit)); +	bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE); + +	return (rp); +} + +void +bfa_rport_delete(struct bfa_rport_s *rport) +{ +	bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE); +} + +void +bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info) +{ +	bfa_assert(rport_info->max_frmsz != 0); + +	/** +	 * Some JBODs are seen to be not setting PDU size correctly in PLOGI +	 * responses. Default to minimum size. +	 */ +	if (rport_info->max_frmsz == 0) { +		bfa_trc(rport->bfa, rport->rport_tag); +		rport_info->max_frmsz = FC_MIN_PDUSZ; +	} + +	bfa_os_assign(rport->rport_info, *rport_info); +	bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE); +} + +void +bfa_rport_offline(struct bfa_rport_s *rport) +{ +	bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE); +} + +void +bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed) +{ +	bfa_assert(speed != 0); +	bfa_assert(speed != BFA_PPORT_SPEED_AUTO); + +	rport->rport_info.speed = speed; +	bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED); +} + +void +bfa_rport_get_stats(struct bfa_rport_s *rport, +	struct bfa_rport_hal_stats_s *stats) +{ +	*stats = rport->stats; +} + +void +bfa_rport_get_qos_attr(struct bfa_rport_s *rport, +					struct bfa_rport_qos_attr_s *qos_attr) +{ +	qos_attr->qos_priority  = bfa_os_ntohl(rport->qos_attr.qos_priority); +	qos_attr->qos_flow_id  = bfa_os_ntohl(rport->qos_attr.qos_flow_id); + +} + +void +bfa_rport_clear_stats(struct bfa_rport_s *rport) +{ +	bfa_os_memset(&rport->stats, 0, sizeof(rport->stats)); +} + + diff --git a/drivers/scsi/bfa/bfa_rport_priv.h b/drivers/scsi/bfa/bfa_rport_priv.h new file mode 100644 index 00000000000..6490ce2e990 --- /dev/null +++ b/drivers/scsi/bfa/bfa_rport_priv.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_RPORT_PRIV_H__ +#define __BFA_RPORT_PRIV_H__ + +#include <bfa_svc.h> + +#define BFA_RPORT_MIN	4 + +struct bfa_rport_mod_s { +	struct bfa_rport_s *rps_list;	/*  list of rports	*/ +	struct list_head 	rp_free_q;	/*  free bfa_rports	*/ +	struct list_head 	rp_active_q;	/*  free bfa_rports 	*/ +	u16	num_rports;	/*  number of rports	*/ +}; + +#define BFA_RPORT_MOD(__bfa)	(&(__bfa)->modules.rport_mod) + +/** + * Convert rport tag to RPORT + */ +#define BFA_RPORT_FROM_TAG(__bfa, _tag)				\ +	(BFA_RPORT_MOD(__bfa)->rps_list +				\ +	 ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1))) + +/* + * external functions + */ +void	bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +#endif /* __BFA_RPORT_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c new file mode 100644 index 00000000000..279d8f9b890 --- /dev/null +++ b/drivers/scsi/bfa/bfa_sgpg.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> + +BFA_TRC_FILE(HAL, SGPG); +BFA_MODULE(sgpg); + +/** + *  bfa_sgpg_mod BFA SGPG Mode module + */ + +/** + * Compute and return memory needed by FCP(im) module. + */ +static void +bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len, +		u32 *dm_len) +{ +	if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) +		cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; + +	*km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s); +	*dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s); +} + + +static void +bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		    struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_sgpg_mod_s	*mod = BFA_SGPG_MOD(bfa); +	int				i; +	struct bfa_sgpg_s		*hsgpg; +	struct bfi_sgpg_s 	*sgpg; +	u64		align_len; + +	union { +		u64        pa; +		union bfi_addr_u      addr; +	} sgpg_pa; + +	INIT_LIST_HEAD(&mod->sgpg_q); +	INIT_LIST_HEAD(&mod->sgpg_wait_q); + +	bfa_trc(bfa, cfg->drvcfg.num_sgpgs); + +	mod->num_sgpgs = cfg->drvcfg.num_sgpgs; +	mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo); +	align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa); +	mod->sgpg_arr_pa += align_len; +	mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) + +						align_len); +	mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) + +						align_len); + +	hsgpg = mod->hsgpg_arr; +	sgpg = mod->sgpg_arr; +	sgpg_pa.pa = mod->sgpg_arr_pa; +	mod->free_sgpgs = mod->num_sgpgs; + +	bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1))); + +	for (i = 0; i < mod->num_sgpgs; i++) { +		bfa_os_memset(hsgpg, 0, sizeof(*hsgpg)); +		bfa_os_memset(sgpg, 0, sizeof(*sgpg)); + +		hsgpg->sgpg = sgpg; +		hsgpg->sgpg_pa = sgpg_pa.addr; +		list_add_tail(&hsgpg->qe, &mod->sgpg_q); + +		hsgpg++; +		sgpg++; +		sgpg_pa.pa += sizeof(struct bfi_sgpg_s); +	} + +	bfa_meminfo_kva(minfo) = (u8 *) hsgpg; +	bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg; +	bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; +} + +static void +bfa_sgpg_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_detach(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_start(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_sgpg_iocdisable(struct bfa_s *bfa) +{ +} + + + +/** + *  bfa_sgpg_public BFA SGPG public functions + */ + +bfa_status_t +bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs) +{ +	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); +	struct bfa_sgpg_s *hsgpg; +	int             i; + +	bfa_trc_fp(bfa, nsgpgs); + +	if (mod->free_sgpgs < nsgpgs) +		return BFA_STATUS_ENOMEM; + +	for (i = 0; i < nsgpgs; i++) { +		bfa_q_deq(&mod->sgpg_q, &hsgpg); +		bfa_assert(hsgpg); +		list_add_tail(&hsgpg->qe, sgpg_q); +	} + +	mod->free_sgpgs -= nsgpgs; +	return BFA_STATUS_OK; +} + +void +bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg) +{ +	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); +	struct bfa_sgpg_wqe_s *wqe; + +	bfa_trc_fp(bfa, nsgpg); + +	mod->free_sgpgs += nsgpg; +	bfa_assert(mod->free_sgpgs <= mod->num_sgpgs); + +	list_splice_tail_init(sgpg_q, &mod->sgpg_q); + +	if (list_empty(&mod->sgpg_wait_q)) +		return; + +	/** +	 * satisfy as many waiting requests as possible +	 */ +	do { +		wqe = bfa_q_first(&mod->sgpg_wait_q); +		if (mod->free_sgpgs < wqe->nsgpg) +			nsgpg = mod->free_sgpgs; +		else +			nsgpg = wqe->nsgpg; +		bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg); +		wqe->nsgpg -= nsgpg; +		if (wqe->nsgpg == 0) { +			list_del(&wqe->qe); +			wqe->cbfn(wqe->cbarg); +		} +	} while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q)); +} + +void +bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg) +{ +	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + +	bfa_assert(nsgpg > 0); +	bfa_assert(nsgpg > mod->free_sgpgs); + +	wqe->nsgpg_total = wqe->nsgpg = nsgpg; + +	/** +	 * allocate any left to this one first +	 */ +	if (mod->free_sgpgs) { +		/** +		 * no one else is waiting for SGPG +		 */ +		bfa_assert(list_empty(&mod->sgpg_wait_q)); +		list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q); +		wqe->nsgpg -= mod->free_sgpgs; +		mod->free_sgpgs = 0; +	} + +	list_add_tail(&wqe->qe, &mod->sgpg_wait_q); +} + +void +bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe) +{ +	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); + +	bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe)); +	list_del(&wqe->qe); + +	if (wqe->nsgpg_total != wqe->nsgpg) +		bfa_sgpg_mfree(bfa, &wqe->sgpg_q, +				   wqe->nsgpg_total - wqe->nsgpg); +} + +void +bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg), +		   void *cbarg) +{ +	INIT_LIST_HEAD(&wqe->sgpg_q); +	wqe->cbfn = cbfn; +	wqe->cbarg = cbarg; +} + + diff --git a/drivers/scsi/bfa/bfa_sgpg_priv.h b/drivers/scsi/bfa/bfa_sgpg_priv.h new file mode 100644 index 00000000000..9c2a8cbe752 --- /dev/null +++ b/drivers/scsi/bfa/bfa_sgpg_priv.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  hal_sgpg.h BFA SG page module + */ + +#ifndef __BFA_SGPG_PRIV_H__ +#define __BFA_SGPG_PRIV_H__ + +#include <cs/bfa_q.h> + +#define BFA_SGPG_MIN	(16) + +/** + * Alignment macro for SG page allocation + */ +#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \ +			& ~(sizeof(struct bfi_sgpg_s) - 1)) + +struct bfa_sgpg_wqe_s { +	struct list_head qe;	/*  queue sg page element	*/ +	int	nsgpg;		/*  pages to be allocated	*/ +	int	nsgpg_total;	/*  total pages required	*/ +	void	(*cbfn) (void *cbarg); +				/*  callback function		*/ +	void	*cbarg;		/*  callback arg		*/ +	struct list_head sgpg_q;	/*  queue of alloced sgpgs	*/ +}; + +struct bfa_sgpg_s { +	struct list_head 	qe;	/*  queue sg page element	*/ +	struct bfi_sgpg_s *sgpg; /*  va of SG page		*/ +	union bfi_addr_u sgpg_pa;/*  pa of SG page		*/ +}; + +/** + * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of + * SG pages required. + */ +#define BFA_SGPG_NPAGE(_nsges)  (((_nsges) / BFI_SGPG_DATA_SGES) + 1) + +struct bfa_sgpg_mod_s { +	struct bfa_s *bfa; +	int		num_sgpgs;	/*  number of SG pages		*/ +	int		free_sgpgs;	/*  number of free SG pages	*/ +	struct bfa_sgpg_s *hsgpg_arr;	/*  BFA SG page array	*/ +	struct bfi_sgpg_s *sgpg_arr;	/*  actual SG page array	*/ +	u64	sgpg_arr_pa;	/*  SG page array DMA addr	*/ +	struct list_head sgpg_q;	/*  queue of free SG pages	*/ +	struct list_head sgpg_wait_q; /*  wait queue for SG pages	*/ +}; +#define BFA_SGPG_MOD(__bfa)	(&(__bfa)->modules.sgpg_mod) + +bfa_status_t	bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, +								int nsgpgs); +void		bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, +								int nsgpgs); +void		bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, +				   void (*cbfn) (void *cbarg), void *cbarg); +void		bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, +								int nsgpgs); +void		bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); + +#endif /* __BFA_SGPG_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_sm.c b/drivers/scsi/bfa/bfa_sm.c new file mode 100644 index 00000000000..5420f4f45e5 --- /dev/null +++ b/drivers/scsi/bfa/bfa_sm.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfasm.c BFA State machine utility functions + */ + +#include <cs/bfa_sm.h> + +/** + *  cs_sm_api + */ + +int +bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm) +{ +	int             i = 0; + +	while (smt[i].sm && smt[i].sm != sm) +		i++; +	return smt[i].state; +} + + diff --git a/drivers/scsi/bfa/bfa_timer.c b/drivers/scsi/bfa/bfa_timer.c new file mode 100644 index 00000000000..cb76481f5cb --- /dev/null +++ b/drivers/scsi/bfa/bfa_timer.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa_timer.h> +#include <cs/bfa_debug.h> + +void +bfa_timer_init(struct bfa_timer_mod_s *mod) +{ +	INIT_LIST_HEAD(&mod->timer_q); +} + +void +bfa_timer_beat(struct bfa_timer_mod_s *mod) +{ +	struct list_head        *qh = &mod->timer_q; +	struct list_head        *qe, *qe_next; +	struct bfa_timer_s *elem; +	struct list_head         timedout_q; + +	INIT_LIST_HEAD(&timedout_q); + +	qe = bfa_q_next(qh); + +	while (qe != qh) { +		qe_next = bfa_q_next(qe); + +		elem = (struct bfa_timer_s *) qe; +		if (elem->timeout <= BFA_TIMER_FREQ) { +			elem->timeout = 0; +			list_del(&elem->qe); +			list_add_tail(&elem->qe, &timedout_q); +		} else { +			elem->timeout -= BFA_TIMER_FREQ; +		} + +		qe = qe_next;	/* go to next elem */ +	} + +	/* +	 * Pop all the timeout entries +	 */ +	while (!list_empty(&timedout_q)) { +		bfa_q_deq(&timedout_q, &elem); +		elem->timercb(elem->arg); +	} +} + +/** + * Should be called with lock protection + */ +void +bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, +		    void (*timercb) (void *), void *arg, unsigned int timeout) +{ + +	bfa_assert(timercb != NULL); +	bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer)); + +	timer->timeout = timeout; +	timer->timercb = timercb; +	timer->arg = arg; + +	list_add_tail(&timer->qe, &mod->timer_q); +} + +/** + * Should be called with lock protection + */ +void +bfa_timer_stop(struct bfa_timer_s *timer) +{ +	bfa_assert(!list_empty(&timer->qe)); + +	list_del(&timer->qe); +} diff --git a/drivers/scsi/bfa/bfa_trcmod_priv.h b/drivers/scsi/bfa/bfa_trcmod_priv.h new file mode 100644 index 00000000000..b3562dce7e9 --- /dev/null +++ b/drivers/scsi/bfa/bfa_trcmod_priv.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  hal_trcmod.h BFA trace modules + */ + +#ifndef __BFA_TRCMOD_PRIV_H__ +#define __BFA_TRCMOD_PRIV_H__ + +#include <cs/bfa_trc.h> + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { +	BFA_TRC_HAL_IOC		= 1, +	BFA_TRC_HAL_INTR	= 2, +	BFA_TRC_HAL_FCXP	= 3, +	BFA_TRC_HAL_UF		= 4, +	BFA_TRC_HAL_DIAG	= 5, +	BFA_TRC_HAL_RPORT	= 6, +	BFA_TRC_HAL_FCPIM	= 7, +	BFA_TRC_HAL_IOIM	= 8, +	BFA_TRC_HAL_TSKIM	= 9, +	BFA_TRC_HAL_ITNIM	= 10, +	BFA_TRC_HAL_PPORT	= 11, +	BFA_TRC_HAL_SGPG	= 12, +	BFA_TRC_HAL_FLASH	= 13, +	BFA_TRC_HAL_DEBUG	= 14, +	BFA_TRC_HAL_WWN		= 15, +	BFA_TRC_HAL_FLASH_RAW	= 16, +	BFA_TRC_HAL_SBOOT	= 17, +	BFA_TRC_HAL_SBOOT_IO	= 18, +	BFA_TRC_HAL_SBOOT_INTR	= 19, +	BFA_TRC_HAL_SBTEST	= 20, +	BFA_TRC_HAL_IPFC	= 21, +	BFA_TRC_HAL_IOCFC	= 22, +	BFA_TRC_HAL_FCPTM	= 23, +	BFA_TRC_HAL_IOTM	= 24, +	BFA_TRC_HAL_TSKTM	= 25, +	BFA_TRC_HAL_TIN		= 26, +	BFA_TRC_HAL_LPS		= 27, +	BFA_TRC_HAL_FCDIAG	= 28, +	BFA_TRC_HAL_PBIND	= 29, +	BFA_TRC_HAL_IOCFC_CT	= 30, +	BFA_TRC_HAL_IOCFC_CB	= 31, +	BFA_TRC_HAL_IOCFC_Q	= 32, +}; + +#endif /* __BFA_TRCMOD_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c new file mode 100644 index 00000000000..010d40d1e5d --- /dev/null +++ b/drivers/scsi/bfa/bfa_tskim.c @@ -0,0 +1,689 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_cb_ioim_macros.h> + +BFA_TRC_FILE(HAL, TSKIM); + +/** + * task management completion handling + */ +#define bfa_tskim_qcomp(__tskim, __cbfn) do {			     \ +	bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim)); \ +	bfa_tskim_notify_comp(__tskim);      \ +} while (0) + +#define bfa_tskim_notify_comp(__tskim) do {				     \ +	if ((__tskim)->notify)					     	     \ +		bfa_itnim_tskdone((__tskim)->itnim);      \ +} while (0) + +/* + * forward declarations + */ +static void     __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete); +static void     __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete); +static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim, +					       lun_t lun); +static void     bfa_tskim_gather_ios(struct bfa_tskim_s *tskim); +static void     bfa_tskim_cleanp_comp(void *tskim_cbarg); +static void     bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim); +static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim); +static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim); +static void     bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim); + +/** + *  bfa_tskim_sm + */ + +enum bfa_tskim_event { +	BFA_TSKIM_SM_START        = 1,  /*  TM command start            */ +	BFA_TSKIM_SM_DONE         = 2,  /*  TM completion               */ +	BFA_TSKIM_SM_QRESUME      = 3,  /*  resume after qfull          */ +	BFA_TSKIM_SM_HWFAIL       = 5,  /*  IOC h/w failure event       */ +	BFA_TSKIM_SM_HCB          = 6,  /*  BFA callback completion     */ +	BFA_TSKIM_SM_IOS_DONE     = 7,  /*  IO and sub TM completions   */ +	BFA_TSKIM_SM_CLEANUP      = 8,  /*  TM cleanup on ITN offline   */ +	BFA_TSKIM_SM_CLEANUP_DONE = 9,  /*  TM abort completion         */ +}; + +static void     bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, +					enum bfa_tskim_event event); +static void     bfa_tskim_sm_active(struct bfa_tskim_s *tskim, +					enum bfa_tskim_event event); +static void     bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, +					 enum bfa_tskim_event event); +static void     bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, +					 enum bfa_tskim_event event); +static void     bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, +				       enum bfa_tskim_event event); +static void     bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, +				       enum bfa_tskim_event event); +static void     bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, +				     enum bfa_tskim_event event); + +/** + *      Task management command beginning state. + */ +static void +bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_START: +		bfa_sm_set_state(tskim, bfa_tskim_sm_active); +		bfa_tskim_gather_ios(tskim); + +		/** +		 * If device is offline, do not send TM on wire. Just cleanup +		 * any pending IO requests and complete TM request. +		 */ +		if (!bfa_itnim_is_online(tskim->itnim)) { +			bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); +			tskim->tsk_status = BFI_TSKIM_STS_OK; +			bfa_tskim_cleanup_ios(tskim); +			return; +		} + +		if (!bfa_tskim_send(tskim)) { +			bfa_sm_set_state(tskim, bfa_tskim_sm_qfull); +			bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, +					  &tskim->reqq_wait); +		} +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * brief + *	TM command is active, awaiting completion from firmware to + *	cleanup IO requests in TM scope. + */ +static void +bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_DONE: +		bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); +		bfa_tskim_cleanup_ios(tskim); +		break; + +	case BFA_TSKIM_SM_CLEANUP: +		bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); +		if (!bfa_tskim_send_abort(tskim)) { +			bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull); +			bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, +				&tskim->reqq_wait); +		} +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_tskim_iocdisable_ios(tskim); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *	An active TM is being cleaned up since ITN is offline. Awaiting cleanup + *	completion event from firmware. + */ +static void +bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_DONE: +		/** +		 * Ignore and wait for ABORT completion from firmware. +		 */ +		break; + +	case BFA_TSKIM_SM_CLEANUP_DONE: +		bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); +		bfa_tskim_cleanup_ios(tskim); +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_tskim_iocdisable_ios(tskim); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_IOS_DONE: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done); +		break; + +	case BFA_TSKIM_SM_CLEANUP: +		/** +		 * Ignore, TM command completed on wire. +		 * Notify TM conmpletion on IO cleanup completion. +		 */ +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_tskim_iocdisable_ios(tskim); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *      Task management command is waiting for room in request CQ + */ +static void +bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_QRESUME: +		bfa_sm_set_state(tskim, bfa_tskim_sm_active); +		bfa_tskim_send(tskim); +		break; + +	case BFA_TSKIM_SM_CLEANUP: +		/** +		 * No need to send TM on wire since ITN is offline. +		 */ +		bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); +		bfa_reqq_wcancel(&tskim->reqq_wait); +		bfa_tskim_cleanup_ios(tskim); +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_reqq_wcancel(&tskim->reqq_wait); +		bfa_tskim_iocdisable_ios(tskim); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *      Task management command is active, awaiting for room in request CQ + *	to send clean up request. + */ +static void +bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, +		enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_DONE: +		bfa_reqq_wcancel(&tskim->reqq_wait); +		/** +		 * +		 * Fall through !!! +		 */ + +	case BFA_TSKIM_SM_QRESUME: +		bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); +		bfa_tskim_send_abort(tskim); +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); +		bfa_reqq_wcancel(&tskim->reqq_wait); +		bfa_tskim_iocdisable_ios(tskim); +		bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *      BFA callback is pending + */ +static void +bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) +{ +	bfa_trc(tskim->bfa, event); + +	switch (event) { +	case BFA_TSKIM_SM_HCB: +		bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); +		bfa_tskim_free(tskim); +		break; + +	case BFA_TSKIM_SM_CLEANUP: +		bfa_tskim_notify_comp(tskim); +		break; + +	case BFA_TSKIM_SM_HWFAIL: +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  bfa_tskim_private + */ + +static void +__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_tskim_s *tskim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); +		return; +	} + +	bfa_stats(tskim->itnim, tm_success); +	bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status); +} + +static void +__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_tskim_s *tskim = cbarg; + +	if (!complete) { +		bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); +		return; +	} + +	bfa_stats(tskim->itnim, tm_failures); +	bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, +			   BFI_TSKIM_STS_FAILED); +} + +static          bfa_boolean_t +bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun) +{ +	switch (tskim->tm_cmnd) { +	case FCP_TM_TARGET_RESET: +		return BFA_TRUE; + +	case FCP_TM_ABORT_TASK_SET: +	case FCP_TM_CLEAR_TASK_SET: +	case FCP_TM_LUN_RESET: +	case FCP_TM_CLEAR_ACA: +		return (tskim->lun == lun); + +	default: +		bfa_assert(0); +	} + +	return BFA_FALSE; +} + +/** + *      Gather affected IO requests and task management commands. + */ +static void +bfa_tskim_gather_ios(struct bfa_tskim_s *tskim) +{ +	struct bfa_itnim_s *itnim = tskim->itnim; +	struct bfa_ioim_s *ioim; +	struct list_head        *qe, *qen; + +	INIT_LIST_HEAD(&tskim->io_q); + +	/** +	 * Gather any active IO requests first. +	 */ +	list_for_each_safe(qe, qen, &itnim->io_q) { +		ioim = (struct bfa_ioim_s *) qe; +		if (bfa_tskim_match_scope +		    (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { +			list_del(&ioim->qe); +			list_add_tail(&ioim->qe, &tskim->io_q); +		} +	} + +	/** +	 * Failback any pending IO requests immediately. +	 */ +	list_for_each_safe(qe, qen, &itnim->pending_q) { +		ioim = (struct bfa_ioim_s *) qe; +		if (bfa_tskim_match_scope +		    (tskim, bfa_cb_ioim_get_lun(ioim->dio))) { +			list_del(&ioim->qe); +			list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); +			bfa_ioim_tov(ioim); +		} +	} +} + +/** + * 		IO cleanup completion + */ +static void +bfa_tskim_cleanp_comp(void *tskim_cbarg) +{ +	struct bfa_tskim_s *tskim = tskim_cbarg; + +	bfa_stats(tskim->itnim, tm_io_comps); +	bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE); +} + +/** + *      Gather affected IO requests and task management commands. + */ +static void +bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim) +{ +	struct bfa_ioim_s *ioim; +	struct list_head        *qe, *qen; + +	bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim); + +	list_for_each_safe(qe, qen, &tskim->io_q) { +		ioim = (struct bfa_ioim_s *) qe; +		bfa_wc_up(&tskim->wc); +		bfa_ioim_cleanup_tm(ioim, tskim); +	} + +	bfa_wc_wait(&tskim->wc); +} + +/** + *      Send task management request to firmware. + */ +static bfa_boolean_t +bfa_tskim_send(struct bfa_tskim_s *tskim) +{ +	struct bfa_itnim_s *itnim = tskim->itnim; +	struct bfi_tskim_req_s *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(tskim->bfa, itnim->reqq); +	if (!m) +		return BFA_FALSE; + +	/** +	 * build i/o request message next +	 */ +	bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, +			bfa_lpuid(tskim->bfa)); + +	m->tsk_tag = bfa_os_htons(tskim->tsk_tag); +	m->itn_fhdl = tskim->itnim->rport->fw_handle; +	m->t_secs = tskim->tsecs; +	m->lun = tskim->lun; +	m->tm_flags = tskim->tm_cmnd; + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(tskim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +/** + *      Send abort request to cleanup an active TM to firmware. + */ +static bfa_boolean_t +bfa_tskim_send_abort(struct bfa_tskim_s *tskim) +{ +	struct bfa_itnim_s             *itnim = tskim->itnim; +	struct bfi_tskim_abortreq_s    *m; + +	/** +	 * check for room in queue to send request now +	 */ +	m = bfa_reqq_next(tskim->bfa, itnim->reqq); +	if (!m) +		return BFA_FALSE; + +	/** +	 * build i/o request message next +	 */ +	bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, +			bfa_lpuid(tskim->bfa)); + +	m->tsk_tag  = bfa_os_htons(tskim->tsk_tag); + +	/** +	 * queue I/O message to firmware +	 */ +	bfa_reqq_produce(tskim->bfa, itnim->reqq); +	return BFA_TRUE; +} + +/** + *      Call to resume task management cmnd waiting for room in request queue. + */ +static void +bfa_tskim_qresume(void *cbarg) +{ +	struct bfa_tskim_s *tskim = cbarg; + +	bfa_fcpim_stats(tskim->fcpim, qresumes); +	bfa_stats(tskim->itnim, tm_qresumes); +	bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME); +} + +/** + * Cleanup IOs associated with a task mangement command on IOC failures. + */ +static void +bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim) +{ +	struct bfa_ioim_s *ioim; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &tskim->io_q) { +		ioim = (struct bfa_ioim_s *) qe; +		bfa_ioim_iocdisable(ioim); +	} +} + + + +/** + *  bfa_tskim_friend + */ + +/** + * Notification on completions from related ioim. + */ +void +bfa_tskim_iodone(struct bfa_tskim_s *tskim) +{ +	bfa_wc_down(&tskim->wc); +} + +/** + * Handle IOC h/w failure notification from itnim. + */ +void +bfa_tskim_iocdisable(struct bfa_tskim_s *tskim) +{ +	tskim->notify = BFA_FALSE; +	bfa_stats(tskim->itnim, tm_iocdowns); +	bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL); +} + +/** + * Cleanup TM command and associated IOs as part of ITNIM offline. + */ +void +bfa_tskim_cleanup(struct bfa_tskim_s *tskim) +{ +	tskim->notify = BFA_TRUE; +	bfa_stats(tskim->itnim, tm_cleanups); +	bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP); +} + +/** + *      Memory allocation and initialization. + */ +void +bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo) +{ +	struct bfa_tskim_s *tskim; +	u16        i; + +	INIT_LIST_HEAD(&fcpim->tskim_free_q); + +	tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo); +	fcpim->tskim_arr = tskim; + +	for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { +		/* +		 * initialize TSKIM +		 */ +		bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s)); +		tskim->tsk_tag = i; +		tskim->bfa     = fcpim->bfa; +		tskim->fcpim   = fcpim; +		tskim->notify  = BFA_FALSE; +		bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume, +				   tskim); +		bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); + +		list_add_tail(&tskim->qe, &fcpim->tskim_free_q); +	} + +	bfa_meminfo_kva(minfo) = (u8 *) tskim; +} + +void +bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim) +{ +    /** +     * @todo +     */ +} + +void +bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; +	struct bfa_tskim_s *tskim; +	u16        tsk_tag = bfa_os_ntohs(rsp->tsk_tag); + +	tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag); +	bfa_assert(tskim->tsk_tag == tsk_tag); + +	tskim->tsk_status = rsp->tsk_status; + +	/** +	 * Firmware sends BFI_TSKIM_STS_ABORTED status for abort +	 * requests. All other statuses are for normal completions. +	 */ +	if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) { +		bfa_stats(tskim->itnim, tm_cleanup_comps); +		bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE); +	} else { +		bfa_stats(tskim->itnim, tm_fw_rsps); +		bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE); +	} +} + + + +/** + *  bfa_tskim_api + */ + + +struct bfa_tskim_s * +bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) +{ +	struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); +	struct bfa_tskim_s *tskim; + +	bfa_q_deq(&fcpim->tskim_free_q, &tskim); + +	if (!tskim) +		bfa_fcpim_stats(fcpim, no_tskims); +	else +		tskim->dtsk = dtsk; + +	return tskim; +} + +void +bfa_tskim_free(struct bfa_tskim_s *tskim) +{ +	bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe)); +	list_del(&tskim->qe); +	list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q); +} + +/** + *      Start a task management command. + * + * @param[in]       tskim       BFA task management command instance + * @param[in]       itnim       i-t nexus for the task management command + * @param[in]       lun         lun, if applicable + * @param[in]       tm_cmnd     Task management command code. + * @param[in]       t_secs      Timeout in seconds + * + * @return None. + */ +void +bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun, +		    enum fcp_tm_cmnd tm_cmnd, u8 tsecs) +{ +	tskim->itnim   = itnim; +	tskim->lun     = lun; +	tskim->tm_cmnd = tm_cmnd; +	tskim->tsecs   = tsecs; +	tskim->notify  = BFA_FALSE; +	bfa_stats(itnim, tm_cmnds); + +	list_add_tail(&tskim->qe, &itnim->tsk_q); +	bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); +} + + diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c new file mode 100644 index 00000000000..ff5f9deb1b2 --- /dev/null +++ b/drivers/scsi/bfa/bfa_uf.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_uf.c BFA unsolicited frame receive implementation + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include <bfi/bfi_uf.h> +#include <cs/bfa_debug.h> + +BFA_TRC_FILE(HAL, UF); +BFA_MODULE(uf); + +/* + ***************************************************************************** + * Internal functions + ***************************************************************************** + */ +static void +__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) +{ +	struct bfa_uf_s   *uf = cbarg; +	struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); + +	if (complete) +		ufm->ufrecv(ufm->cbarg, uf); +} + +static void +claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ +	u32        uf_pb_tot_sz; + +	ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi); +	ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi); +	uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs), +							BFA_DMA_ALIGN_SZ); + +	bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz; +	bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz; + +	bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz); +} + +static void +claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ +	struct bfi_uf_buf_post_s *uf_bp_msg; +	struct bfi_sge_s      *sge; +	union bfi_addr_u      sga_zero = { {0} }; +	u16        i; +	u16        buf_len; + +	ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi); +	uf_bp_msg = ufm->uf_buf_posts; + +	for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; +	     i++, uf_bp_msg++) { +		bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); + +		uf_bp_msg->buf_tag = i; +		buf_len = sizeof(struct bfa_uf_buf_s); +		uf_bp_msg->buf_len = bfa_os_htons(buf_len); +		bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, +			    bfa_lpuid(ufm->bfa)); + +		sge = uf_bp_msg->sge; +		sge[0].sg_len = buf_len; +		sge[0].flags = BFI_SGE_DATA_LAST; +		bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i)); +		bfa_sge_to_be(sge); + +		sge[1].sg_len = buf_len; +		sge[1].flags = BFI_SGE_PGDLEN; +		sge[1].sga = sga_zero; +		bfa_sge_to_be(&sge[1]); +	} + +	/** +	 * advance pointer beyond consumed memory +	 */ +	bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg; +} + +static void +claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ +	u16        i; +	struct bfa_uf_s   *uf; + +	/* +	 * Claim block of memory for UF list +	 */ +	ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi); + +	/* +	 * Initialize UFs and queue it in UF free queue +	 */ +	for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { +		bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s)); +		uf->bfa = ufm->bfa; +		uf->uf_tag = i; +		uf->pb_len = sizeof(struct bfa_uf_buf_s); +		uf->buf_kva = (void *)&ufm->uf_pbs_kva[i]; +		uf->buf_pa = ufm_pbs_pa(ufm, i); +		list_add_tail(&uf->qe, &ufm->uf_free_q); +	} + +	/** +	 * advance memory pointer +	 */ +	bfa_meminfo_kva(mi) = (u8 *) uf; +} + +static void +uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi) +{ +	claim_uf_pbs(ufm, mi); +	claim_ufs(ufm, mi); +	claim_uf_post_msgs(ufm, mi); +} + +static void +bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len) +{ +	u32        num_ufs = cfg->fwcfg.num_uf_bufs; + +	/* +	 * dma-able memory for UF posted bufs +	 */ +	*dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs), +							BFA_DMA_ALIGN_SZ); + +	/* +	 * kernel Virtual memory for UFs and UF buf post msg copies +	 */ +	*ndm_len += sizeof(struct bfa_uf_s) * num_ufs; +	*ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs; +} + +static void +bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +		  struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) +{ +	struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + +	bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s)); +	ufm->bfa = bfa; +	ufm->num_ufs = cfg->fwcfg.num_uf_bufs; +	INIT_LIST_HEAD(&ufm->uf_free_q); +	INIT_LIST_HEAD(&ufm->uf_posted_q); + +	uf_mem_claim(ufm, meminfo); +} + +static void +bfa_uf_initdone(struct bfa_s *bfa) +{ +} + +static void +bfa_uf_detach(struct bfa_s *bfa) +{ +} + +static struct bfa_uf_s * +bfa_uf_get(struct bfa_uf_mod_s *uf_mod) +{ +	struct bfa_uf_s   *uf; + +	bfa_q_deq(&uf_mod->uf_free_q, &uf); +	return (uf); +} + +static void +bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) +{ +	list_add_tail(&uf->qe, &uf_mod->uf_free_q); +} + +static bfa_status_t +bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) +{ +	struct bfi_uf_buf_post_s *uf_post_msg; + +	uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); +	if (!uf_post_msg) +		return BFA_STATUS_FAILED; + +	bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], +		      sizeof(struct bfi_uf_buf_post_s)); +	bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP); + +	bfa_trc(ufm->bfa, uf->uf_tag); + +	list_add_tail(&uf->qe, &ufm->uf_posted_q); +	return BFA_STATUS_OK; +} + +static void +bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) +{ +	struct bfa_uf_s   *uf; + +	while ((uf = bfa_uf_get(uf_mod)) != NULL) { +		if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) +			break; +	} +} + +static void +uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) +{ +	struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); +	u16        uf_tag = m->buf_tag; +	struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag]; +	struct bfa_uf_s   *uf = &ufm->uf_list[uf_tag]; +	u8        *buf = &uf_buf->d[0]; +	struct fchs_s         *fchs; + +	m->frm_len = bfa_os_ntohs(m->frm_len); +	m->xfr_len = bfa_os_ntohs(m->xfr_len); + +	fchs = (struct fchs_s *) uf_buf; + +	list_del(&uf->qe);	/* dequeue from posted queue */ + +	uf->data_ptr = buf; +	uf->data_len = m->xfr_len; + +	bfa_assert(uf->data_len >= sizeof(struct fchs_s)); + +	if (uf->data_len == sizeof(struct fchs_s)) { +		bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, +			       uf->data_len, (struct fchs_s *) buf); +	} else { +		u32        pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); +		bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, +				      BFA_PL_EID_RX, uf->data_len, +				      (struct fchs_s *) buf, pld_w0); +	} + +	bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); +} + +static void +bfa_uf_stop(struct bfa_s *bfa) +{ +} + +static void +bfa_uf_iocdisable(struct bfa_s *bfa) +{ +	struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); +	struct bfa_uf_s   *uf; +	struct list_head        *qe, *qen; + +	list_for_each_safe(qe, qen, &ufm->uf_posted_q) { +		uf = (struct bfa_uf_s *) qe; +		list_del(&uf->qe); +		bfa_uf_put(ufm, uf); +	} +} + +static void +bfa_uf_start(struct bfa_s *bfa) +{ +	bfa_uf_post_all(BFA_UF_MOD(bfa)); +} + + + +/** + *  bfa_uf_api + */ + +/** + * 		Register handler for all unsolicted recieve frames. + * + * @param[in]	bfa		BFA instance + * @param[in]	ufrecv	receive handler function + * @param[in]	cbarg	receive handler arg + */ +void +bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) +{ +	struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); + +	ufm->ufrecv = ufrecv; +	ufm->cbarg = cbarg; +} + +/** + * 		Free an unsolicited frame back to BFA. + * + * @param[in]		uf		unsolicited frame to be freed + * + * @return None + */ +void +bfa_uf_free(struct bfa_uf_s *uf) +{ +	bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); +	bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); +} + + + +/** + *  uf_pub BFA uf module public functions + */ + +void +bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) +{ +	bfa_trc(bfa, msg->mhdr.msg_id); + +	switch (msg->mhdr.msg_id) { +	case BFI_UF_I2H_FRM_RCVD: +		uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); +		break; + +	default: +		bfa_trc(bfa, msg->mhdr.msg_id); +		bfa_assert(0); +	} +} + + diff --git a/drivers/scsi/bfa/bfa_uf_priv.h b/drivers/scsi/bfa/bfa_uf_priv.h new file mode 100644 index 00000000000..bcb490f834f --- /dev/null +++ b/drivers/scsi/bfa/bfa_uf_priv.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_UF_PRIV_H__ +#define __BFA_UF_PRIV_H__ + +#include <cs/bfa_sm.h> +#include <bfa_svc.h> +#include <bfi/bfi_uf.h> + +#define BFA_UF_MIN	(4) + +struct bfa_uf_mod_s { +	struct bfa_s *bfa;		/*  back pointer to BFA */ +	struct bfa_uf_s *uf_list;	/*  array of UFs */ +	u16	num_ufs;	/*  num unsolicited rx frames */ +	struct list_head 	uf_free_q;	/*  free UFs */ +	struct list_head 	uf_posted_q;	/*  UFs posted to IOC */ +	struct bfa_uf_buf_s *uf_pbs_kva;	/*  list UF bufs request pld */ +	u64	uf_pbs_pa;	/*  phy addr for UF bufs */ +	struct bfi_uf_buf_post_s *uf_buf_posts; +					/*  pre-built UF post msgs */ +	bfa_cb_uf_recv_t ufrecv;	/*  uf recv handler function */ +	void		*cbarg;		/*  uf receive handler arg */ +}; + +#define BFA_UF_MOD(__bfa)	(&(__bfa)->modules.uf_mod) + +#define ufm_pbs_pa(_ufmod, _uftag)	\ +	((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag)) + +void	bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + +#endif /* __BFA_UF_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c new file mode 100644 index 00000000000..6f2be5abf56 --- /dev/null +++ b/drivers/scsi/bfa/bfad.c @@ -0,0 +1,1182 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfad.c Linux driver PCI interface module. + */ + +#include <linux/module.h> +#include "bfad_drv.h" +#include "bfad_im.h" +#include "bfad_tm.h" +#include "bfad_ipfc.h" +#include "bfad_trcmod.h" +#include <fcb/bfa_fcb_vf.h> +#include <fcb/bfa_fcb_rport.h> +#include <fcb/bfa_fcb_port.h> +#include <fcb/bfa_fcb.h> + +BFA_TRC_FILE(LDRV, BFAD); +static DEFINE_MUTEX(bfad_mutex); +LIST_HEAD(bfad_list); +static int      bfad_inst; +int bfad_supported_fc4s; + +static char     *host_name; +static char     *os_name; +static char     *os_patch; +static int      num_rports; +static int      num_ios; +static int      num_tms; +static int      num_fcxps; +static int      num_ufbufs; +static int      reqq_size; +static int      rspq_size; +static int      num_sgpgs; +static int      rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; +static int      bfa_io_max_sge = BFAD_IO_MAX_SGE; +static int      log_level = BFA_LOG_WARNING; +static int      ioc_auto_recover = BFA_TRUE; +static int      ipfc_enable = BFA_FALSE; +static int      ipfc_mtu = -1; +int 		bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; +int      	bfa_linkup_delay = -1; + +module_param(os_name, charp, S_IRUGO | S_IWUSR); +module_param(os_patch, charp, S_IRUGO | S_IWUSR); +module_param(host_name, charp, S_IRUGO | S_IWUSR); +module_param(num_rports, int, S_IRUGO | S_IWUSR); +module_param(num_ios, int, S_IRUGO | S_IWUSR); +module_param(num_tms, int, S_IRUGO | S_IWUSR); +module_param(num_fcxps, int, S_IRUGO | S_IWUSR); +module_param(num_ufbufs, int, S_IRUGO | S_IWUSR); +module_param(reqq_size, int, S_IRUGO | S_IWUSR); +module_param(rspq_size, int, S_IRUGO | S_IWUSR); +module_param(num_sgpgs, int, S_IRUGO | S_IWUSR); +module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR); +module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR); +module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR); +module_param(log_level, int, S_IRUGO | S_IWUSR); +module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR); +module_param(ipfc_enable, int, S_IRUGO | S_IWUSR); +module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR); +module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR); + +/* + * Stores the module parm num_sgpgs value; + * used to reset for bfad next instance. + */ +static int num_sgpgs_parm; + +static bfa_status_t +bfad_fc4_probe(struct bfad_s *bfad) +{ +	int             rc; + +	rc = bfad_im_probe(bfad); +	if (rc != BFA_STATUS_OK) +		goto ext; + +	bfad_tm_probe(bfad); + +	if (ipfc_enable) +		bfad_ipfc_probe(bfad); +ext: +	return rc; +} + +static void +bfad_fc4_probe_undo(struct bfad_s *bfad) +{ +	bfad_im_probe_undo(bfad); +	bfad_tm_probe_undo(bfad); +	if (ipfc_enable) +		bfad_ipfc_probe_undo(bfad); +} + +static void +bfad_fc4_probe_post(struct bfad_s *bfad) +{ +	if (bfad->im) +		bfad_im_probe_post(bfad->im); + +	bfad_tm_probe_post(bfad); +	if (ipfc_enable) +		bfad_ipfc_probe_post(bfad); +} + +static bfa_status_t +bfad_fc4_port_new(struct bfad_s *bfad, struct bfad_port_s *port, int roles) +{ +	int             rc = BFA_STATUS_FAILED; + +	if (roles & BFA_PORT_ROLE_FCP_IM) +		rc = bfad_im_port_new(bfad, port); +	if (rc != BFA_STATUS_OK) +		goto ext; + +	if (roles & BFA_PORT_ROLE_FCP_TM) +		rc = bfad_tm_port_new(bfad, port); +	if (rc != BFA_STATUS_OK) +		goto ext; + +	if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) +		rc = bfad_ipfc_port_new(bfad, port, port->pvb_type); +ext: +	return rc; +} + +static void +bfad_fc4_port_delete(struct bfad_s *bfad, struct bfad_port_s *port, int roles) +{ +	if (roles & BFA_PORT_ROLE_FCP_IM) +		bfad_im_port_delete(bfad, port); + +	if (roles & BFA_PORT_ROLE_FCP_TM) +		bfad_tm_port_delete(bfad, port); + +	if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) +		bfad_ipfc_port_delete(bfad, port); +} + +/** + *  BFA callbacks + */ +void +bfad_hcb_comp(void *arg, bfa_status_t status) +{ +	struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg; + +	fcomp->status = status; +	complete(&fcomp->comp); +} + +/** + * bfa_init callback + */ +void +bfa_cb_init(void *drv, bfa_status_t init_status) +{ +	struct bfad_s  *bfad = drv; + +	if (init_status == BFA_STATUS_OK) +		bfad->bfad_flags |= BFAD_HAL_INIT_DONE; + +	complete(&bfad->comp); +} + + + +/** + *  BFA_FCS callbacks + */ +static struct bfad_port_s * +bfad_get_drv_port(struct bfad_s *bfad, struct bfad_vf_s *vf_drv, +		  struct bfad_vport_s *vp_drv) +{ +	return ((vp_drv) ? (&(vp_drv)->drv_port) +		: ((vf_drv) ? (&(vf_drv)->base_port) : (&(bfad)->pport))); +} + +struct bfad_port_s * +bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port, +		 enum bfa_port_role roles, struct bfad_vf_s *vf_drv, +		 struct bfad_vport_s *vp_drv) +{ +	bfa_status_t    rc; +	struct bfad_port_s *port_drv; + +	if (!vp_drv && !vf_drv) { +		port_drv = &bfad->pport; +		port_drv->pvb_type = BFAD_PORT_PHYS_BASE; +	} else if (!vp_drv && vf_drv) { +		port_drv = &vf_drv->base_port; +		port_drv->pvb_type = BFAD_PORT_VF_BASE; +	} else if (vp_drv && !vf_drv) { +		port_drv = &vp_drv->drv_port; +		port_drv->pvb_type = BFAD_PORT_PHYS_VPORT; +	} else { +		port_drv = &vp_drv->drv_port; +		port_drv->pvb_type = BFAD_PORT_VF_VPORT; +	} + +	port_drv->fcs_port = port; +	port_drv->roles = roles; +	rc = bfad_fc4_port_new(bfad, port_drv, roles); +	if (rc != BFA_STATUS_OK) { +		bfad_fc4_port_delete(bfad, port_drv, roles); +		port_drv = NULL; +	} + +	return port_drv; +} + +void +bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles, +		    struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) +{ +	struct bfad_port_s *port_drv; + +	/* +	 * this will be only called from rmmod context +	 */ +	if (vp_drv && !vp_drv->comp_del) { +		port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); +		bfa_trc(bfad, roles); +		bfad_fc4_port_delete(bfad, port_drv, roles); +	} +} + +void +bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles, +		    struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) +{ +	struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); + +	if (roles & BFA_PORT_ROLE_FCP_IM) +		bfad_im_port_online(bfad, port_drv); + +	if (roles & BFA_PORT_ROLE_FCP_TM) +		bfad_tm_port_online(bfad, port_drv); + +	if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) +		bfad_ipfc_port_online(bfad, port_drv); + +	bfad->bfad_flags |= BFAD_PORT_ONLINE; +} + +void +bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles, +		     struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) +{ +	struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv); + +	if (roles & BFA_PORT_ROLE_FCP_IM) +		bfad_im_port_offline(bfad, port_drv); + +	if (roles & BFA_PORT_ROLE_FCP_TM) +		bfad_tm_port_offline(bfad, port_drv); + +	if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) +		bfad_ipfc_port_offline(bfad, port_drv); +} + +void +bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv) +{ +	if (vport_drv->comp_del) { +		complete(vport_drv->comp_del); +		return; +	} + +	kfree(vport_drv); +} + +/** + * FCS RPORT alloc callback, after successful PLOGI by FCS + */ +bfa_status_t +bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport, +		    struct bfad_rport_s **rport_drv) +{ +	bfa_status_t    rc = BFA_STATUS_OK; + +	*rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC); +	if (*rport_drv == NULL) { +		rc = BFA_STATUS_ENOMEM; +		goto ext; +	} + +	*rport = &(*rport_drv)->fcs_rport; + +ext: +	return rc; +} + + + +void +bfad_hal_mem_release(struct bfad_s *bfad) +{ +	int             i; +	struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; +	struct bfa_mem_elem_s *meminfo_elem; + +	for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { +		meminfo_elem = &hal_meminfo->meminfo[i]; +		if (meminfo_elem->kva != NULL) { +			switch (meminfo_elem->mem_type) { +			case BFA_MEM_TYPE_KVA: +				vfree(meminfo_elem->kva); +				break; +			case BFA_MEM_TYPE_DMA: +				dma_free_coherent(&bfad->pcidev->dev, +						meminfo_elem->mem_len, +						meminfo_elem->kva, +						(dma_addr_t) meminfo_elem->dma); +				break; +			default: +				bfa_assert(0); +				break; +			} +		} +	} + +	memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s)); +} + +void +bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) +{ +	if (num_rports > 0) +		bfa_cfg->fwcfg.num_rports = num_rports; +	if (num_ios > 0) +		bfa_cfg->fwcfg.num_ioim_reqs = num_ios; +	if (num_tms > 0) +		bfa_cfg->fwcfg.num_tskim_reqs = num_tms; +	if (num_fcxps > 0) +		bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps; +	if (num_ufbufs > 0) +		bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs; +	if (reqq_size > 0) +		bfa_cfg->drvcfg.num_reqq_elems = reqq_size; +	if (rspq_size > 0) +		bfa_cfg->drvcfg.num_rspq_elems = rspq_size; +	if (num_sgpgs > 0) +		bfa_cfg->drvcfg.num_sgpgs = num_sgpgs; + +	/* +	 * populate the hal values back to the driver for sysfs use. +	 * otherwise, the default values will be shown as 0 in sysfs +	 */ +	num_rports = bfa_cfg->fwcfg.num_rports; +	num_ios    = bfa_cfg->fwcfg.num_ioim_reqs; +	num_tms	   = bfa_cfg->fwcfg.num_tskim_reqs; +	num_fcxps  = bfa_cfg->fwcfg.num_fcxp_reqs; +	num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs; +	reqq_size  = bfa_cfg->drvcfg.num_reqq_elems; +	rspq_size  = bfa_cfg->drvcfg.num_rspq_elems; +	num_sgpgs  = bfa_cfg->drvcfg.num_sgpgs; +} + +bfa_status_t +bfad_hal_mem_alloc(struct bfad_s *bfad) +{ +	struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; +	struct bfa_mem_elem_s *meminfo_elem; +	bfa_status_t    rc = BFA_STATUS_OK; +	dma_addr_t      phys_addr; +	int             retry_count = 0; +	int             reset_value = 1; +	int             min_num_sgpgs = 512; +	void           *kva; +	int             i; + +	bfa_cfg_get_default(&bfad->ioc_cfg); + +retry: +	bfad_update_hal_cfg(&bfad->ioc_cfg); +	bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs; +	bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo); + +	for (i = 0; i < BFA_MEM_TYPE_MAX; i++) { +		meminfo_elem = &hal_meminfo->meminfo[i]; +		switch (meminfo_elem->mem_type) { +		case BFA_MEM_TYPE_KVA: +			kva = vmalloc(meminfo_elem->mem_len); +			if (kva == NULL) { +				bfad_hal_mem_release(bfad); +				rc = BFA_STATUS_ENOMEM; +				goto ext; +			} +			memset(kva, 0, meminfo_elem->mem_len); +			meminfo_elem->kva = kva; +			break; +		case BFA_MEM_TYPE_DMA: +			kva = dma_alloc_coherent(&bfad->pcidev->dev, +					meminfo_elem->mem_len, +					&phys_addr, GFP_KERNEL); +			if (kva == NULL) { +				bfad_hal_mem_release(bfad); +				/* +				 * If we cannot allocate with default +				 * num_sgpages try with half the value. +				 */ +				if (num_sgpgs > min_num_sgpgs) { +					printk(KERN_INFO "bfad[%d]: memory" +						" allocation failed with" +						" num_sgpgs: %d\n", +						bfad->inst_no, num_sgpgs); +					nextLowerInt(&num_sgpgs); +					printk(KERN_INFO "bfad[%d]: trying to" +						" allocate memory with" +						" num_sgpgs: %d\n", +						bfad->inst_no, num_sgpgs); +					retry_count++; +					goto retry; +				} else { +					if (num_sgpgs_parm > 0) +						num_sgpgs = num_sgpgs_parm; +					else { +						reset_value = +							(1 << retry_count); +						num_sgpgs *= reset_value; +					} +					rc = BFA_STATUS_ENOMEM; +					goto ext; +				} +			} + +			if (num_sgpgs_parm > 0) +				num_sgpgs = num_sgpgs_parm; +			else { +				reset_value = (1 << retry_count); +				num_sgpgs *= reset_value; +			} + +			memset(kva, 0, meminfo_elem->mem_len); +			meminfo_elem->kva = kva; +			meminfo_elem->dma = phys_addr; +			break; +		default: +			break; + +		} +	} +ext: +	return rc; +} + +/** + * Create a vport under a vf. + */ +bfa_status_t +bfad_vport_create(struct bfad_s *bfad, u16 vf_id, +		  struct bfa_port_cfg_s *port_cfg) +{ +	struct bfad_vport_s *vport; +	int             rc = BFA_STATUS_OK; +	unsigned long   flags; +	struct completion fcomp; + +	vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); +	if (!vport) { +		rc = BFA_STATUS_ENOMEM; +		goto ext; +	} + +	vport->drv_port.bfad = bfad; +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id, +				  port_cfg, vport); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (rc != BFA_STATUS_OK) +		goto ext_free_vport; + +	if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) { +		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port); +		if (rc != BFA_STATUS_OK) +			goto ext_free_fcs_vport; +	} + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_fcs_vport_start(&vport->fcs_vport); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	return BFA_STATUS_OK; + +ext_free_fcs_vport: +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	vport->comp_del = &fcomp; +	init_completion(vport->comp_del); +	bfa_fcs_vport_delete(&vport->fcs_vport); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	wait_for_completion(vport->comp_del); +ext_free_vport: +	kfree(vport); +ext: +	return rc; +} + +/** + * Create a vf and its base vport implicitely. + */ +bfa_status_t +bfad_vf_create(struct bfad_s *bfad, u16 vf_id, +	       struct bfa_port_cfg_s *port_cfg) +{ +	struct bfad_vf_s *vf; +	int             rc = BFA_STATUS_OK; + +	vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL); +	if (!vf) { +		rc = BFA_STATUS_FAILED; +		goto ext; +	} + +	rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg, +			       vf); +	if (rc != BFA_STATUS_OK) +		kfree(vf); +ext: +	return rc; +} + +void +bfad_bfa_tmo(unsigned long data) +{ +	struct bfad_s  *bfad = (struct bfad_s *)data; +	unsigned long   flags; +	struct list_head  doneq; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); + +	bfa_timer_tick(&bfad->bfa); + +	bfa_comp_deq(&bfad->bfa, &doneq); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (!list_empty(&doneq)) { +		bfa_comp_process(&bfad->bfa, &doneq); +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		bfa_comp_free(&bfad->bfa, &doneq); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	} + +	mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); +} + +void +bfad_init_timer(struct bfad_s *bfad) +{ +	init_timer(&bfad->hal_tmo); +	bfad->hal_tmo.function = bfad_bfa_tmo; +	bfad->hal_tmo.data = (unsigned long)bfad; + +	mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); +} + +int +bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) +{ +	unsigned long   bar0_len; +	int             rc = -ENODEV; + +	if (pci_enable_device(pdev)) { +		BFA_PRINTF(BFA_ERR, "pci_enable_device fail %p\n", pdev); +		goto out; +	} + +	if (pci_request_regions(pdev, BFAD_DRIVER_NAME)) +		goto out_disable_device; + +	pci_set_master(pdev); + + +	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) +		if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { +			BFA_PRINTF(BFA_ERR, "pci_set_dma_mask fail %p\n", pdev); +			goto out_release_region; +		} + +	bfad->pci_bar0_map = pci_resource_start(pdev, 0); +	bar0_len = pci_resource_len(pdev, 0); +	bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len); + +	if (bfad->pci_bar0_kva == NULL) { +		BFA_PRINTF(BFA_ERR, "Fail to map bar0\n"); +		goto out_release_region; +	} + +	bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn); +	bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn); +	bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva; +	bfad->hal_pcidev.device_id = pdev->device; +	bfad->pci_name = pci_name(pdev); + +	bfad->pci_attr.vendor_id = pdev->vendor; +	bfad->pci_attr.device_id = pdev->device; +	bfad->pci_attr.ssid = pdev->subsystem_device; +	bfad->pci_attr.ssvid = pdev->subsystem_vendor; +	bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn); + +	bfad->pcidev = pdev; +	return 0; + +out_release_region: +	pci_release_regions(pdev); +out_disable_device: +	pci_disable_device(pdev); +out: +	return rc; +} + +void +bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) +{ +#if defined(__ia64__) +	pci_iounmap(pdev, bfad->pci_bar0_kva); +#else +	iounmap(bfad->pci_bar0_kva); +#endif +	pci_release_regions(pdev); +	pci_disable_device(pdev); +	pci_set_drvdata(pdev, NULL); +} + +void +bfad_fcs_port_cfg(struct bfad_s *bfad) +{ +	struct bfa_port_cfg_s port_cfg; +	struct bfa_pport_attr_s attr; +	char            symname[BFA_SYMNAME_MAXLEN]; + +	sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no); +	memcpy(port_cfg.sym_name.symname, symname, strlen(symname)); +	bfa_pport_get_attr(&bfad->bfa, &attr); +	port_cfg.nwwn = attr.nwwn; +	port_cfg.pwwn = attr.pwwn; + +	bfa_fcs_cfg_base_port(&bfad->bfa_fcs, &port_cfg); +} + +bfa_status_t +bfad_drv_init(struct bfad_s *bfad) +{ +	bfa_status_t    rc; +	unsigned long   flags; +	struct bfa_fcs_driver_info_s driver_info; +	int             i; + +	bfad->cfg_data.rport_del_timeout = rport_del_timeout; +	bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth; +	bfad->cfg_data.io_max_sge = bfa_io_max_sge; +	bfad->cfg_data.binding_method = FCP_PWWN_BINDING; + +	rc = bfad_hal_mem_alloc(bfad); +	if (rc != BFA_STATUS_OK) { +		printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n", +		       bfad->inst_no); +		printk(KERN_WARNING +			"Not enough memory to attach all Brocade HBA ports," +			" System may need more memory.\n"); +		goto out_hal_mem_alloc_failure; +	} + +	bfa_init_log(&bfad->bfa, bfad->logmod); +	bfa_init_trc(&bfad->bfa, bfad->trcmod); +	bfa_init_aen(&bfad->bfa, bfad->aen); +	INIT_LIST_HEAD(&bfad->file_q); +	INIT_LIST_HEAD(&bfad->file_free_q); +	for (i = 0; i < BFAD_AEN_MAX_APPS; i++) { +		bfa_q_qe_init(&bfad->file_buf[i].qe); +		list_add_tail(&bfad->file_buf[i].qe, &bfad->file_free_q); +	} +	bfa_init_plog(&bfad->bfa, &bfad->plog_buf); +	bfa_plog_init(&bfad->plog_buf); +	bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START, +		     0, "Driver Attach"); + +	bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo, +		   &bfad->hal_pcidev); + +	init_completion(&bfad->comp); + +	/* +	 * Enable Interrupt and wait bfa_init completion +	 */ +	if (bfad_setup_intr(bfad)) { +		printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n", +		       bfad->inst_no); +		goto out_setup_intr_failure; +	} + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_init(&bfad->bfa); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	/* +	 * Set up interrupt handler for each vectors +	 */ +	if ((bfad->bfad_flags & BFAD_MSIX_ON) +	    && bfad_install_msix_handler(bfad)) { +		printk(KERN_WARNING "%s: install_msix failed, bfad%d\n", +		       __FUNCTION__, bfad->inst_no); +	} + +	bfad_init_timer(bfad); + +	wait_for_completion(&bfad->comp); + +	memset(&driver_info, 0, sizeof(driver_info)); +	strncpy(driver_info.version, BFAD_DRIVER_VERSION, +		sizeof(driver_info.version) - 1); +	if (host_name) +		strncpy(driver_info.host_machine_name, host_name, +			sizeof(driver_info.host_machine_name) - 1); +	if (os_name) +		strncpy(driver_info.host_os_name, os_name, +			sizeof(driver_info.host_os_name) - 1); +	if (os_patch) +		strncpy(driver_info.host_os_patch, os_patch, +			sizeof(driver_info.host_os_patch) - 1); + +	strncpy(driver_info.os_device_name, bfad->pci_name, +		sizeof(driver_info.os_device_name - 1)); + +	/* +	 * FCS INIT +	 */ +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod); +	bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod); +	bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen); +	bfa_fcs_init(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); +	bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	bfad->bfad_flags |= BFAD_DRV_INIT_DONE; +	return BFA_STATUS_OK; + +out_setup_intr_failure: +	bfa_detach(&bfad->bfa); +	bfad_hal_mem_release(bfad); +out_hal_mem_alloc_failure: +	return BFA_STATUS_FAILED; +} + +void +bfad_drv_uninit(struct bfad_s *bfad) +{ +	del_timer_sync(&bfad->hal_tmo); +	bfa_isr_disable(&bfad->bfa); +	bfa_detach(&bfad->bfa); +	bfad_remove_intr(bfad); +	bfa_assert(list_empty(&bfad->file_q)); +	bfad_hal_mem_release(bfad); +} + +void +bfad_drv_start(struct bfad_s *bfad) +{ +	unsigned long   flags; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_start(&bfad->bfa); +	bfa_fcs_start(&bfad->bfa_fcs); +	bfad->bfad_flags |= BFAD_HAL_START_DONE; +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	bfad_fc4_probe_post(bfad); +} + +void +bfad_drv_stop(struct bfad_s *bfad) +{ +	unsigned long   flags; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	init_completion(&bfad->comp); +	bfad->pport.flags |= BFAD_PORT_DELETE; +	bfa_fcs_exit(&bfad->bfa_fcs); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	wait_for_completion(&bfad->comp); + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	init_completion(&bfad->comp); +	bfa_stop(&bfad->bfa); +	bfad->bfad_flags &= ~BFAD_HAL_START_DONE; +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	wait_for_completion(&bfad->comp); +} + +bfa_status_t +bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) +{ +	int             rc = BFA_STATUS_OK; + +	/* +	 * Allocate scsi_host for the physical port +	 */ +	if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) +	    && (role & BFA_PORT_ROLE_FCP_IM)) { +		if (bfad->pport.im_port == NULL) { +			rc = BFA_STATUS_FAILED; +			goto out; +		} + +		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port); +		if (rc != BFA_STATUS_OK) +			goto out; + +		bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; +	} + +	bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; + +out: +	return rc; +} + +void +bfad_uncfg_pport(struct bfad_s *bfad) +{ +	if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) { +		bfad_ipfc_port_delete(bfad, &bfad->pport); +		bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC; +	} + +	if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM) +	    && (bfad->pport.roles & BFA_PORT_ROLE_FCP_IM)) { +		bfad_im_scsi_host_free(bfad, bfad->pport.im_port); +		bfad_im_port_clean(bfad->pport.im_port); +		kfree(bfad->pport.im_port); +		bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IM; +	} + +	bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE; +} + +void +bfad_drv_log_level_set(struct bfad_s *bfad) +{ +	if (log_level > BFA_LOG_INVALID && log_level <= BFA_LOG_LEVEL_MAX) +		bfa_log_set_level_all(&bfad->log_data, log_level); +} + + /* +  *  PCI_entry PCI driver entries * { +  */ + +/** + * PCI probe entry. + */ +int +bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) +{ +	struct bfad_s  *bfad; +	int             error = -ENODEV, retval; +	char            buf[16]; + +	/* +	 * For single port cards - only claim function 0 +	 */ +	if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) +	    && (PCI_FUNC(pdev->devfn) != 0)) +		return -ENODEV; + +	BFA_TRACE(BFA_INFO, "bfad_pci_probe entry"); + +	bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL); +	if (!bfad) { +		error = -ENOMEM; +		goto out; +	} + +	bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL); +	if (!bfad->trcmod) { +		printk(KERN_WARNING "Error alloc trace buffer!\n"); +		error = -ENOMEM; +		goto out_alloc_trace_failure; +	} + +	/* +	 * LOG/TRACE INIT +	 */ +	bfa_trc_init(bfad->trcmod); +	bfa_trc(bfad, bfad_inst); + +	bfad->logmod = &bfad->log_data; +	sprintf(buf, "%d", bfad_inst); +	bfa_log_init(bfad->logmod, buf, bfa_os_printf); + +	bfad_drv_log_level_set(bfad); + +	bfad->aen = &bfad->aen_buf; + +	if (!(bfad_load_fwimg(pdev))) { +		printk(KERN_WARNING "bfad_load_fwimg failure!\n"); +		kfree(bfad->trcmod); +		goto out_alloc_trace_failure; +	} + +	retval = bfad_pci_init(pdev, bfad); +	if (retval) { +		printk(KERN_WARNING "bfad_pci_init failure!\n"); +		error = retval; +		goto out_pci_init_failure; +	} + +	mutex_lock(&bfad_mutex); +	bfad->inst_no = bfad_inst++; +	list_add_tail(&bfad->list_entry, &bfad_list); +	mutex_unlock(&bfad_mutex); + +	spin_lock_init(&bfad->bfad_lock); +	pci_set_drvdata(pdev, bfad); + +	bfad->ref_count = 0; +	bfad->pport.bfad = bfad; + +	retval = bfad_drv_init(bfad); +	if (retval != BFA_STATUS_OK) +		goto out_drv_init_failure; +	if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { +		printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no); +		goto ok; +	} + +	/* +	 * PPORT FCS config +	 */ +	bfad_fcs_port_cfg(bfad); + +	retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM); +	if (retval != BFA_STATUS_OK) +		goto out_cfg_pport_failure; + +	/* +	 * BFAD level FC4 (IM/TM/IPFC) specific resource allocation +	 */ +	retval = bfad_fc4_probe(bfad); +	if (retval != BFA_STATUS_OK) { +		printk(KERN_WARNING "bfad_fc4_probe failed\n"); +		goto out_fc4_probe_failure; +	} + +	bfad_drv_start(bfad); + +	/* +	 * If bfa_linkup_delay is set to -1 default; try to retrive the +	 * value using the bfad_os_get_linkup_delay(); else use the +	 * passed in module param value as the bfa_linkup_delay. +	 */ +	if (bfa_linkup_delay < 0) { +		bfa_linkup_delay = bfad_os_get_linkup_delay(bfad); +		bfad_os_rport_online_wait(bfad); +		bfa_linkup_delay = -1; +	} else { +		bfad_os_rport_online_wait(bfad); +	} + +	bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name); +ok: +	return 0; + +out_fc4_probe_failure: +	bfad_fc4_probe_undo(bfad); +	bfad_uncfg_pport(bfad); +out_cfg_pport_failure: +	bfad_drv_uninit(bfad); +out_drv_init_failure: +	mutex_lock(&bfad_mutex); +	bfad_inst--; +	list_del(&bfad->list_entry); +	mutex_unlock(&bfad_mutex); +	bfad_pci_uninit(pdev, bfad); +out_pci_init_failure: +	kfree(bfad->trcmod); +out_alloc_trace_failure: +	kfree(bfad); +out: +	return error; +} + +/** + * PCI remove entry. + */ +void +bfad_pci_remove(struct pci_dev *pdev) +{ +	struct bfad_s  *bfad = pci_get_drvdata(pdev); +	unsigned long   flags; + +	bfa_trc(bfad, bfad->inst_no); + +	if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE) +	    && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { + +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		init_completion(&bfad->comp); +		bfa_stop(&bfad->bfa); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +		wait_for_completion(&bfad->comp); + +		bfad_remove_intr(bfad); +		del_timer_sync(&bfad->hal_tmo); +		goto hal_detach; +	} else if (!(bfad->bfad_flags & BFAD_DRV_INIT_DONE)) { +		goto remove_sysfs; +	} + +	if (bfad->bfad_flags & BFAD_HAL_START_DONE) +		bfad_drv_stop(bfad); + +	bfad_remove_intr(bfad); + +	del_timer_sync(&bfad->hal_tmo); +	bfad_fc4_probe_undo(bfad); + +	if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE) +		bfad_uncfg_pport(bfad); + +hal_detach: +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_detach(&bfad->bfa); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	bfad_hal_mem_release(bfad); +remove_sysfs: + +	mutex_lock(&bfad_mutex); +	bfad_inst--; +	list_del(&bfad->list_entry); +	mutex_unlock(&bfad_mutex); +	bfad_pci_uninit(pdev, bfad); + +	kfree(bfad->trcmod); +	kfree(bfad); +} + + +static struct pci_device_id bfad_id_table[] = { +	{ +	 .vendor = BFA_PCI_VENDOR_ID_BROCADE, +	 .device = BFA_PCI_DEVICE_ID_FC_8G2P, +	 .subvendor = PCI_ANY_ID, +	 .subdevice = PCI_ANY_ID, +	 }, +	{ +	 .vendor = BFA_PCI_VENDOR_ID_BROCADE, +	 .device = BFA_PCI_DEVICE_ID_FC_8G1P, +	 .subvendor = PCI_ANY_ID, +	 .subdevice = PCI_ANY_ID, +	 }, +	{ +	 .vendor = BFA_PCI_VENDOR_ID_BROCADE, +	 .device = BFA_PCI_DEVICE_ID_CT, +	 .subvendor = PCI_ANY_ID, +	 .subdevice = PCI_ANY_ID, +	 .class = (PCI_CLASS_SERIAL_FIBER << 8), +	 .class_mask = ~0, +	 }, + +	{0, 0}, +}; + +MODULE_DEVICE_TABLE(pci, bfad_id_table); + +static struct pci_driver bfad_pci_driver = { +	.name = BFAD_DRIVER_NAME, +	.id_table = bfad_id_table, +	.probe = bfad_pci_probe, +	.remove = __devexit_p(bfad_pci_remove), +}; + +/** + *  Linux driver module functions + */ +bfa_status_t +bfad_fc4_module_init(void) +{ +	int             rc; + +	rc = bfad_im_module_init(); +	if (rc != BFA_STATUS_OK) +		goto ext; + +	bfad_tm_module_init(); +	if (ipfc_enable) +		bfad_ipfc_module_init(); +ext: +	return rc; +} + +void +bfad_fc4_module_exit(void) +{ +	if (ipfc_enable) +		bfad_ipfc_module_exit(); +	bfad_tm_module_exit(); +	bfad_im_module_exit(); +} + +/** + * Driver module init. + */ +static int      __init +bfad_init(void) +{ +	int             error = 0; + +	printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n", +	       BFAD_DRIVER_VERSION); + +	if (num_sgpgs > 0) +		num_sgpgs_parm = num_sgpgs; + +	error = bfad_fc4_module_init(); +	if (error) { +		error = -ENOMEM; +		printk(KERN_WARNING "bfad_fc4_module_init failure\n"); +		goto ext; +	} + +	if (!strcmp(FCPI_NAME, " fcpim")) +		bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IM; +	if (!strcmp(FCPT_NAME, " fcptm")) +		bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_TM; +	if (!strcmp(IPFC_NAME, " ipfc")) +		bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IPFC; + +	bfa_ioc_auto_recover(ioc_auto_recover); +	bfa_fcs_rport_set_del_timeout(rport_del_timeout); +	error = pci_register_driver(&bfad_pci_driver); + +	if (error) { +		printk(KERN_WARNING "bfad pci_register_driver failure\n"); +		goto ext; +	} + +	return 0; + +ext: +	bfad_fc4_module_exit(); +	return error; +} + +/** + * Driver module exit. + */ +static void     __exit +bfad_exit(void) +{ +	pci_unregister_driver(&bfad_pci_driver); +	bfad_fc4_module_exit(); +	bfad_free_fwimg(); +} + +#define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME + +module_init(bfad_init); +module_exit(bfad_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME); +MODULE_AUTHOR("Brocade Communications Systems, Inc."); +MODULE_VERSION(BFAD_DRIVER_VERSION); + + diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c new file mode 100644 index 00000000000..9129ae3040f --- /dev/null +++ b/drivers/scsi/bfa/bfad_attr.c @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_attr.c Linux driver configuration interface module. + */ + +#include "bfad_drv.h" +#include "bfad_im.h" +#include "bfad_trcmod.h" +#include "bfad_attr.h" + +/** + *  FC_transport_template FC transport template + */ + +/** + * FC transport template entry, get SCSI target port ID. + */ +void +bfad_im_get_starget_port_id(struct scsi_target *starget) +{ +	struct Scsi_Host *shost; +	struct bfad_im_port_s *im_port; +	struct bfad_s         *bfad; +	struct bfad_itnim_s   *itnim = NULL; +	u32        fc_id = -1; +	unsigned long   flags; + +	shost = bfad_os_starget_to_shost(starget); +	im_port = (struct bfad_im_port_s *) shost->hostdata[0]; +	bfad = im_port->bfad; +	spin_lock_irqsave(&bfad->bfad_lock, flags); + +	itnim = bfad_os_get_itnim(im_port, starget->id); +	if (itnim) +		fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); + +	fc_starget_port_id(starget) = fc_id; +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +} + +/** + * FC transport template entry, get SCSI target nwwn. + */ +void +bfad_im_get_starget_node_name(struct scsi_target *starget) +{ +	struct Scsi_Host *shost; +	struct bfad_im_port_s *im_port; +	struct bfad_s         *bfad; +	struct bfad_itnim_s   *itnim = NULL; +	u64             node_name = 0; +	unsigned long   flags; + +	shost = bfad_os_starget_to_shost(starget); +	im_port = (struct bfad_im_port_s *) shost->hostdata[0]; +	bfad = im_port->bfad; +	spin_lock_irqsave(&bfad->bfad_lock, flags); + +	itnim = bfad_os_get_itnim(im_port, starget->id); +	if (itnim) +		node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim); + +	fc_starget_node_name(starget) = bfa_os_htonll(node_name); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +} + +/** + * FC transport template entry, get SCSI target pwwn. + */ +void +bfad_im_get_starget_port_name(struct scsi_target *starget) +{ +	struct Scsi_Host *shost; +	struct bfad_im_port_s *im_port; +	struct bfad_s         *bfad; +	struct bfad_itnim_s   *itnim = NULL; +	u64             port_name = 0; +	unsigned long   flags; + +	shost = bfad_os_starget_to_shost(starget); +	im_port = (struct bfad_im_port_s *) shost->hostdata[0]; +	bfad = im_port->bfad; +	spin_lock_irqsave(&bfad->bfad_lock, flags); + +	itnim = bfad_os_get_itnim(im_port, starget->id); +	if (itnim) +		port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); + +	fc_starget_port_name(starget) = bfa_os_htonll(port_name); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +} + +/** + * FC transport template entry, get SCSI host port ID. + */ +void +bfad_im_get_host_port_id(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_port_s    *port = im_port->port; + +	fc_host_port_id(shost) = +			bfa_os_hton3b(bfa_fcs_port_get_fcid(port->fcs_port)); +} + + + + + +struct Scsi_Host * +bfad_os_starget_to_shost(struct scsi_target *starget) +{ +	return dev_to_shost(starget->dev.parent); +} + +/** + * FC transport template entry, get SCSI host port type. + */ +static void +bfad_im_get_host_port_type(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_pport_attr_s attr; + +	bfa_pport_get_attr(&bfad->bfa, &attr); + +	switch (attr.port_type) { +	case BFA_PPORT_TYPE_NPORT: +		fc_host_port_type(shost) = FC_PORTTYPE_NPORT; +		break; +	case BFA_PPORT_TYPE_NLPORT: +		fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; +		break; +	case BFA_PPORT_TYPE_P2P: +		fc_host_port_type(shost) = FC_PORTTYPE_PTP; +		break; +	case BFA_PPORT_TYPE_LPORT: +		fc_host_port_type(shost) = FC_PORTTYPE_LPORT; +		break; +	default: +		fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; +		break; +	} +} + +/** + * FC transport template entry, get SCSI host port state. + */ +static void +bfad_im_get_host_port_state(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_pport_attr_s attr; + +	bfa_pport_get_attr(&bfad->bfa, &attr); + +	switch (attr.port_state) { +	case BFA_PPORT_ST_LINKDOWN: +		fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; +		break; +	case BFA_PPORT_ST_LINKUP: +		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; +		break; +	case BFA_PPORT_ST_UNINIT: +	case BFA_PPORT_ST_ENABLING_QWAIT: +	case BFA_PPORT_ST_ENABLING: +	case BFA_PPORT_ST_DISABLING_QWAIT: +	case BFA_PPORT_ST_DISABLING: +	case BFA_PPORT_ST_DISABLED: +	case BFA_PPORT_ST_STOPPED: +	case BFA_PPORT_ST_IOCDOWN: +	default: +		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; +		break; +	} +} + +/** + * FC transport template entry, get SCSI host active fc4s. + */ +static void +bfad_im_get_host_active_fc4s(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_port_s    *port = im_port->port; + +	memset(fc_host_active_fc4s(shost), 0, +	       sizeof(fc_host_active_fc4s(shost))); + +	if (port->supported_fc4s & +		(BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM)) +		fc_host_active_fc4s(shost)[2] = 1; + +	if (port->supported_fc4s & BFA_PORT_ROLE_FCP_IPFC) +		fc_host_active_fc4s(shost)[3] = 0x20; + +	fc_host_active_fc4s(shost)[7] = 1; +} + +/** + * FC transport template entry, get SCSI host link speed. + */ +static void +bfad_im_get_host_speed(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_pport_attr_s attr; + +	bfa_pport_get_attr(&bfad->bfa, &attr); +	switch (attr.speed) { +	case BFA_PPORT_SPEED_8GBPS: +		fc_host_speed(shost) = FC_PORTSPEED_8GBIT; +		break; +	case BFA_PPORT_SPEED_4GBPS: +		fc_host_speed(shost) = FC_PORTSPEED_4GBIT; +		break; +	case BFA_PPORT_SPEED_2GBPS: +		fc_host_speed(shost) = FC_PORTSPEED_2GBIT; +		break; +	case BFA_PPORT_SPEED_1GBPS: +		fc_host_speed(shost) = FC_PORTSPEED_1GBIT; +		break; +	default: +		fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; +		break; +	} +} + +/** + * FC transport template entry, get SCSI host port type. + */ +static void +bfad_im_get_host_fabric_name(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_port_s    *port = im_port->port; +	wwn_t           fabric_nwwn = 0; + +	fabric_nwwn = bfa_fcs_port_get_fabric_name(port->fcs_port); + +	fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn); + +} + +/** + * FC transport template entry, get BFAD statistics. + */ +static struct fc_host_statistics * +bfad_im_get_stats(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfad_hal_comp fcomp; +	struct fc_host_statistics *hstats; +	bfa_status_t    rc; +	unsigned long   flags; + +	hstats = &bfad->link_stats; +	init_completion(&fcomp.comp); +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	memset(hstats, 0, sizeof(struct fc_host_statistics)); +	rc = bfa_pport_get_stats(&bfad->bfa, +				     (union bfa_pport_stats_u *) hstats, +				     bfad_hcb_comp, &fcomp); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	if (rc != BFA_STATUS_OK) +		return NULL; + +	wait_for_completion(&fcomp.comp); + +	return hstats; +} + +/** + * FC transport template entry, reset BFAD statistics. + */ +static void +bfad_im_reset_stats(struct Scsi_Host *shost) +{ +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfad_hal_comp fcomp; +	unsigned long   flags; +	bfa_status_t    rc; + +	init_completion(&fcomp.comp); +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	rc = bfa_pport_clear_stats(&bfad->bfa, bfad_hcb_comp, &fcomp); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (rc != BFA_STATUS_OK) +		return; + +	wait_for_completion(&fcomp.comp); + +	return; +} + +/** + * FC transport template entry, get rport loss timeout. + */ +static void +bfad_im_get_rport_loss_tmo(struct fc_rport *rport) +{ +	struct bfad_itnim_data_s *itnim_data = rport->dd_data; +	struct bfad_itnim_s   *itnim = itnim_data->itnim; +	struct bfad_s         *bfad = itnim->im->bfad; +	unsigned long   flags; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +} + +/** + * FC transport template entry, set rport loss timeout. + */ +static void +bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) +{ +	struct bfad_itnim_data_s *itnim_data = rport->dd_data; +	struct bfad_itnim_s   *itnim = itnim_data->itnim; +	struct bfad_s         *bfad = itnim->im->bfad; +	unsigned long   flags; + +	if (timeout > 0) { +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		bfa_fcpim_path_tov_set(&bfad->bfa, timeout); +		rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	} + +} + +struct fc_function_template bfad_im_fc_function_template = { + +	/* Target dynamic attributes */ +	.get_starget_port_id = bfad_im_get_starget_port_id, +	.show_starget_port_id = 1, +	.get_starget_node_name = bfad_im_get_starget_node_name, +	.show_starget_node_name = 1, +	.get_starget_port_name = bfad_im_get_starget_port_name, +	.show_starget_port_name = 1, + +	/* Host dynamic attribute */ +	.get_host_port_id = bfad_im_get_host_port_id, +	.show_host_port_id = 1, + +	/* Host fixed attributes */ +	.show_host_node_name = 1, +	.show_host_port_name = 1, +	.show_host_supported_classes = 1, +	.show_host_supported_fc4s = 1, +	.show_host_supported_speeds = 1, +	.show_host_maxframe_size = 1, + +	/* More host dynamic attributes */ +	.show_host_port_type = 1, +	.get_host_port_type = bfad_im_get_host_port_type, +	.show_host_port_state = 1, +	.get_host_port_state = bfad_im_get_host_port_state, +	.show_host_active_fc4s = 1, +	.get_host_active_fc4s = bfad_im_get_host_active_fc4s, +	.show_host_speed = 1, +	.get_host_speed = bfad_im_get_host_speed, +	.show_host_fabric_name = 1, +	.get_host_fabric_name = bfad_im_get_host_fabric_name, + +	.show_host_symbolic_name = 1, + +	/* Statistics */ +	.get_fc_host_stats = bfad_im_get_stats, +	.reset_fc_host_stats = bfad_im_reset_stats, + +	/* Allocation length for host specific data */ +	.dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), + +	/* Remote port fixed attributes */ +	.show_rport_maxframe_size = 1, +	.show_rport_supported_classes = 1, +	.show_rport_dev_loss_tmo = 1, +	.get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo, +	.set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, +}; + +/** + *  Scsi_Host_attrs SCSI host attributes + */ +static ssize_t +bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr, +			 char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", +			ioc_attr.adapter_attr.serial_num); +} + +static ssize_t +bfad_im_model_show(struct device *dev, struct device_attribute *attr, +			char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.model); +} + +static ssize_t +bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, +				 char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", +			ioc_attr.adapter_attr.model_descr); +} + +static ssize_t +bfad_im_node_name_show(struct device *dev, struct device_attribute *attr, +				 char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_port_s    *port = im_port->port; +	u64        nwwn; + +	nwwn = bfa_fcs_port_get_nwwn(port->fcs_port); +	return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn)); +} + +static ssize_t +bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr, +				 char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); + +	return snprintf(buf, PAGE_SIZE, "Brocade %s FV%s DV%s\n", +			ioc_attr.adapter_attr.model, +			ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION); +} + +static ssize_t +bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr, +				char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.hw_ver); +} + +static ssize_t +bfad_im_drv_version_show(struct device *dev, struct device_attribute *attr, +				char *buf) +{ +	return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_VERSION); +} + +static ssize_t +bfad_im_optionrom_version_show(struct device *dev, +			 struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", +			ioc_attr.adapter_attr.optrom_ver); +} + +static ssize_t +bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr, +				 char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.fw_ver); +} + +static ssize_t +bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr, +				char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioc_attr_s  ioc_attr; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); +	return snprintf(buf, PAGE_SIZE, "%d\n", ioc_attr.adapter_attr.nports); +} + +static ssize_t +bfad_im_drv_name_show(struct device *dev, struct device_attribute *attr, +				char *buf) +{ +	return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_NAME); +} + +static ssize_t +bfad_im_num_of_discovered_ports_show(struct device *dev, +			struct device_attribute *attr, char *buf) +{ +	struct Scsi_Host *shost = class_to_shost(dev); +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_port_s    *port = im_port->port; +	struct bfad_s         *bfad = im_port->bfad; +	int        nrports = 2048; +	wwn_t          *rports = NULL; +	unsigned long   flags; + +	rports = kzalloc(sizeof(wwn_t) * nrports , GFP_ATOMIC); +	if (rports == NULL) +		return -ENOMEM; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	bfa_fcs_port_get_rports(port->fcs_port, rports, &nrports); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	kfree(rports); + +	return snprintf(buf, PAGE_SIZE, "%d\n", nrports); +} + +static          DEVICE_ATTR(serial_number, S_IRUGO, +				bfad_im_serial_num_show, NULL); +static          DEVICE_ATTR(model, S_IRUGO, bfad_im_model_show, NULL); +static          DEVICE_ATTR(model_description, S_IRUGO, +				bfad_im_model_desc_show, NULL); +static          DEVICE_ATTR(node_name, S_IRUGO, bfad_im_node_name_show, NULL); +static          DEVICE_ATTR(symbolic_name, S_IRUGO, +				bfad_im_symbolic_name_show, NULL); +static          DEVICE_ATTR(hardware_version, S_IRUGO, +				bfad_im_hw_version_show, NULL); +static          DEVICE_ATTR(driver_version, S_IRUGO, +				bfad_im_drv_version_show, NULL); +static          DEVICE_ATTR(option_rom_version, S_IRUGO, +				bfad_im_optionrom_version_show, NULL); +static          DEVICE_ATTR(firmware_version, S_IRUGO, +				bfad_im_fw_version_show, NULL); +static          DEVICE_ATTR(number_of_ports, S_IRUGO, +				bfad_im_num_of_ports_show, NULL); +static          DEVICE_ATTR(driver_name, S_IRUGO, bfad_im_drv_name_show, NULL); +static          DEVICE_ATTR(number_of_discovered_ports, S_IRUGO, +				bfad_im_num_of_discovered_ports_show, NULL); + +struct device_attribute *bfad_im_host_attrs[] = { +	&dev_attr_serial_number, +	&dev_attr_model, +	&dev_attr_model_description, +	&dev_attr_node_name, +	&dev_attr_symbolic_name, +	&dev_attr_hardware_version, +	&dev_attr_driver_version, +	&dev_attr_option_rom_version, +	&dev_attr_firmware_version, +	&dev_attr_number_of_ports, +	&dev_attr_driver_name, +	&dev_attr_number_of_discovered_ports, +	NULL, +}; + +struct device_attribute *bfad_im_vport_attrs[] = { +    &dev_attr_serial_number, +    &dev_attr_model, +    &dev_attr_model_description, +    &dev_attr_node_name, +    &dev_attr_symbolic_name, +    &dev_attr_hardware_version, +    &dev_attr_driver_version, +    &dev_attr_option_rom_version, +    &dev_attr_firmware_version, +    &dev_attr_number_of_ports, +    &dev_attr_driver_name, +    &dev_attr_number_of_discovered_ports, +    NULL, +}; + + diff --git a/drivers/scsi/bfa/bfad_attr.h b/drivers/scsi/bfa/bfad_attr.h new file mode 100644 index 00000000000..4d3312da6a8 --- /dev/null +++ b/drivers/scsi/bfa/bfad_attr.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFAD_ATTR_H__ +#define __BFAD_ATTR_H__ +/** + *  bfad_attr.h VMware driver configuration interface module. + */ + +/** + *  FC_transport_template FC transport template + */ + +struct Scsi_Host* +bfad_os_dev_to_shost(struct scsi_target *starget); + +/** + * FC transport template entry, get SCSI target port ID. + */ +void +bfad_im_get_starget_port_id(struct scsi_target *starget); + +/** + * FC transport template entry, get SCSI target nwwn. + */ +void +bfad_im_get_starget_node_name(struct scsi_target *starget); + +/** + * FC transport template entry, get SCSI target pwwn. + */ +void +bfad_im_get_starget_port_name(struct scsi_target *starget); + +/** + * FC transport template entry, get SCSI host port ID. + */ +void +bfad_im_get_host_port_id(struct Scsi_Host *shost); + +/** + * FC transport template entry, issue a LIP. + */ +int +bfad_im_issue_fc_host_lip(struct Scsi_Host *shost); + +struct Scsi_Host* +bfad_os_starget_to_shost(struct scsi_target *starget); + + +#endif /*  __BFAD_ATTR_H__ */ diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h new file mode 100644 index 00000000000..172c81e25c1 --- /dev/null +++ b/drivers/scsi/bfa/bfad_drv.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + * Contains base driver definitions. + */ + +/** + *  bfa_drv.h Linux driver data structures. + */ + +#ifndef __BFAD_DRV_H__ +#define __BFAD_DRV_H__ + +#include "bfa_os_inc.h" + +#include <bfa.h> +#include <bfa_svc.h> +#include <fcs/bfa_fcs.h> +#include <defs/bfa_defs_pci.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_rport.h> +#include <fcs/bfa_fcs_rport.h> +#include <defs/bfa_defs_vport.h> +#include <fcs/bfa_fcs_vport.h> + +#include <cs/bfa_plog.h> +#include "aen/bfa_aen.h" +#include <log/bfa_log_linux.h> + +#define BFAD_DRIVER_NAME        "bfa" +#ifdef BFA_DRIVER_VERSION +#define BFAD_DRIVER_VERSION    BFA_DRIVER_VERSION +#else +#define BFAD_DRIVER_VERSION    "2.0.0.0" +#endif + + +#define BFAD_IRQ_FLAGS IRQF_SHARED + +/* + * BFAD flags + */ +#define BFAD_MSIX_ON				0x00000001 +#define BFAD_HAL_INIT_DONE			0x00000002 +#define BFAD_DRV_INIT_DONE			0x00000004 +#define BFAD_CFG_PPORT_DONE			0x00000008 +#define BFAD_HAL_START_DONE			0x00000010 +#define BFAD_PORT_ONLINE			0x00000020 +#define BFAD_RPORT_ONLINE			0x00000040 + +#define BFAD_PORT_DELETE			0x00000001 + +/* + * BFAD related definition + */ +#define SCSI_SCAN_DELAY		HZ +#define BFAD_STOP_TIMEOUT	30 +#define BFAD_SUSPEND_TIMEOUT	BFAD_STOP_TIMEOUT + +/* + * BFAD configuration parameter default values + */ +#define BFAD_LUN_QUEUE_DEPTH 		32 +#define BFAD_IO_MAX_SGE 		SG_ALL + +#define bfad_isr_t irq_handler_t + +#define MAX_MSIX_ENTRY 22 + +struct bfad_msix_s { +	struct bfad_s *bfad; +	struct msix_entry msix; +}; + +enum bfad_port_pvb_type { +	BFAD_PORT_PHYS_BASE = 0, +	BFAD_PORT_PHYS_VPORT = 1, +	BFAD_PORT_VF_BASE = 2, +	BFAD_PORT_VF_VPORT = 3, +}; + +/* + * PORT data structure + */ +struct bfad_port_s { +	struct list_head list_entry; +	struct bfad_s         *bfad; +	struct bfa_fcs_port_s *fcs_port; +	u32        roles; +	s32         flags; +	u32        supported_fc4s; +	u8		ipfc_flags; +	enum bfad_port_pvb_type pvb_type; +	struct bfad_im_port_s *im_port;	/* IM specific data */ +	struct bfad_tm_port_s *tm_port;	/* TM specific data */ +	struct bfad_ipfc_port_s *ipfc_port;	/* IPFC specific data */ +}; + +/* + * VPORT data structure + */ +struct bfad_vport_s { +	struct bfad_port_s     drv_port; +	struct bfa_fcs_vport_s fcs_vport; +	struct completion *comp_del; +}; + +/* + * VF data structure + */ +struct bfad_vf_s { +	bfa_fcs_vf_t    fcs_vf; +	struct bfad_port_s    base_port;	/* base port for vf */ +	struct bfad_s   *bfad; +}; + +struct bfad_cfg_param_s { +	u32        rport_del_timeout; +	u32        ioc_queue_depth; +	u32        lun_queue_depth; +	u32        io_max_sge; +	u32        binding_method; +}; + +#define BFAD_AEN_MAX_APPS 8 +struct bfad_aen_file_s { +	struct list_head  qe; +	struct bfad_s *bfad; +	s32 ri; +	s32 app_id; +}; + +/* + * BFAD (PCI function) data structure + */ +struct bfad_s { +	struct list_head list_entry; +	struct bfa_s       bfa; +	struct bfa_fcs_s       bfa_fcs; +	struct pci_dev *pcidev; +	const char *pci_name; +	struct bfa_pcidev_s hal_pcidev; +	struct bfa_ioc_pci_attr_s pci_attr; +	unsigned long   pci_bar0_map; +	void __iomem   *pci_bar0_kva; +	struct completion comp; +	struct completion suspend; +	struct completion disable_comp; +	bfa_boolean_t   disable_active; +	struct bfad_port_s     pport;	/* physical port of the BFAD */ +	struct bfa_meminfo_s meminfo; +	struct bfa_iocfc_cfg_s   ioc_cfg; +	u32        inst_no;	/* BFAD instance number */ +	u32        bfad_flags; +	spinlock_t      bfad_lock; +	struct bfad_cfg_param_s cfg_data; +	struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY]; +	int             nvec; +	char            adapter_name[BFA_ADAPTER_SYM_NAME_LEN]; +	char            port_name[BFA_ADAPTER_SYM_NAME_LEN]; +	struct timer_list hal_tmo; +	unsigned long   hs_start; +	struct bfad_im_s *im;		/* IM specific data */ +	struct bfad_tm_s *tm;		/* TM specific data */ +	struct bfad_ipfc_s *ipfc;	/* IPFC specific data */ +	struct bfa_log_mod_s   log_data; +	struct bfa_trc_mod_s  *trcmod; +	struct bfa_log_mod_s  *logmod; +	struct bfa_aen_s      *aen; +	struct bfa_aen_s       aen_buf; +	struct bfad_aen_file_s file_buf[BFAD_AEN_MAX_APPS]; +	struct list_head         file_q; +	struct list_head         file_free_q; +	struct bfa_plog_s      plog_buf; +	int             ref_count; +	bfa_boolean_t	ipfc_enabled; +	struct fc_host_statistics link_stats; + +	struct kobject *bfa_kobj; +	struct kobject *ioc_kobj; +	struct kobject *pport_kobj; +	struct kobject *lport_kobj; +}; + +/* + * RPORT data structure + */ +struct bfad_rport_s { +	struct bfa_fcs_rport_s fcs_rport; +}; + +struct bfad_buf_info { +	void           *virt; +	dma_addr_t      phys; +	u32        size; +}; + +struct bfad_fcxp { +	struct bfad_port_s    *port; +	struct bfa_rport_s *bfa_rport; +	bfa_status_t    req_status; +	u16        tag; +	u16        rsp_len; +	u16        rsp_maxlen; +	u8         use_ireqbuf; +	u8         use_irspbuf; +	u32        num_req_sgles; +	u32        num_rsp_sgles; +	struct fchs_s          fchs; +	void           *reqbuf_info; +	void           *rspbuf_info; +	struct bfa_sge_s  *req_sge; +	struct bfa_sge_s  *rsp_sge; +	fcxp_send_cb_t  send_cbfn; +	void           *send_cbarg; +	void           *bfa_fcxp; +	struct completion comp; +}; + +struct bfad_hal_comp { +	bfa_status_t    status; +	struct completion comp; +}; + +/* + * Macro to obtain the immediate lower power + * of two for the integer. + */ +#define nextLowerInt(x)                         	\ +do {                                            	\ +	int j;                                  	\ +	(*x)--;    		                	\ +	for (j = 1; j < (sizeof(int) * 8); j <<= 1)     \ +		(*x) = (*x) | (*x) >> j;        	\ +	(*x)++;                  	        	\ +	(*x) = (*x) >> 1;                       	\ +} while (0) + + +bfa_status_t    bfad_vport_create(struct bfad_s *bfad, u16 vf_id, +				  struct bfa_port_cfg_s *port_cfg); +bfa_status_t    bfad_vf_create(struct bfad_s *bfad, u16 vf_id, +			       struct bfa_port_cfg_s *port_cfg); +bfa_status_t    bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role); +bfa_status_t    bfad_drv_init(struct bfad_s *bfad); +void            bfad_drv_start(struct bfad_s *bfad); +void            bfad_uncfg_pport(struct bfad_s *bfad); +void            bfad_drv_stop(struct bfad_s *bfad); +void            bfad_remove_intr(struct bfad_s *bfad); +void            bfad_hal_mem_release(struct bfad_s *bfad); +void            bfad_hcb_comp(void *arg, bfa_status_t status); + +int             bfad_setup_intr(struct bfad_s *bfad); +void            bfad_remove_intr(struct bfad_s *bfad); + +void		bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg); +bfa_status_t	bfad_hal_mem_alloc(struct bfad_s *bfad); +void		bfad_bfa_tmo(unsigned long data); +void		bfad_init_timer(struct bfad_s *bfad); +int		bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad); +void		bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad); +void		bfad_fcs_port_cfg(struct bfad_s *bfad); +void		bfad_drv_uninit(struct bfad_s *bfad); +void		bfad_drv_log_level_set(struct bfad_s *bfad); +bfa_status_t	bfad_fc4_module_init(void); +void		bfad_fc4_module_exit(void); + +void bfad_pci_remove(struct pci_dev *pdev); +int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid); +void bfad_os_rport_online_wait(struct bfad_s *bfad); +int bfad_os_get_linkup_delay(struct bfad_s *bfad); +int bfad_install_msix_handler(struct bfad_s *bfad); + +extern struct idr bfad_im_port_index; +extern struct list_head bfad_list; +extern int bfa_lun_queue_depth; +extern int bfad_supported_fc4s; +extern int bfa_linkup_delay; + +#endif /* __BFAD_DRV_H__ */ diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c new file mode 100644 index 00000000000..b2f6949bc8d --- /dev/null +++ b/drivers/scsi/bfa/bfad_fwimg.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfad_fwimg.c Linux driver PCI interface module. + */ +#include <bfa_os_inc.h> +#include <bfad_drv.h> +#include <bfad_im_compat.h> +#include <defs/bfa_defs_version.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <asm/uaccess.h> +#include <asm/fcntl.h> +#include <linux/pci.h> +#include <linux/firmware.h> +#include <bfa_fwimg_priv.h> +#include <bfa.h> + +u32 bfi_image_ct_size; +u32 bfi_image_cb_size; +u32 *bfi_image_ct; +u32 *bfi_image_cb; + + +#define	BFAD_FW_FILE_CT	"ctfw.bin" +#define	BFAD_FW_FILE_CB	"cbfw.bin" + +u32 * +bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, +			u32 *bfi_image_size, char *fw_name) +{ +	const struct firmware *fw; + +	if (request_firmware(&fw, fw_name, &pdev->dev)) { +		printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); +		goto error; +	} + +	*bfi_image = vmalloc(fw->size); +	if (NULL == *bfi_image) { +		printk(KERN_ALERT "Fail to allocate buffer for fw image " +			"size=%x!\n", (u32) fw->size); +		goto error; +	} + +	memcpy(*bfi_image, fw->data, fw->size); +	*bfi_image_size = fw->size/sizeof(u32); + +	return(*bfi_image); + +error: +	return(NULL); +} + +u32 * +bfad_get_firmware_buf(struct pci_dev *pdev) +{ +	if (pdev->device == BFA_PCI_DEVICE_ID_CT) { +		if (bfi_image_ct_size == 0) +			bfad_read_firmware(pdev, &bfi_image_ct, +				&bfi_image_ct_size, BFAD_FW_FILE_CT); +		return(bfi_image_ct); +	} else { +		if (bfi_image_cb_size == 0) +			bfad_read_firmware(pdev, &bfi_image_cb, +				&bfi_image_cb_size, BFAD_FW_FILE_CB); +		return(bfi_image_cb); +	} +} + +u32 * +bfi_image_ct_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct + off); } + +u32 * +bfi_image_cb_get_chunk(u32 off) +{ return (u32 *)(bfi_image_cb + off); } + diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c new file mode 100644 index 00000000000..158c99243c0 --- /dev/null +++ b/drivers/scsi/bfa/bfad_im.c @@ -0,0 +1,1230 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfad_im.c Linux driver IM module. + */ + +#include "bfad_drv.h" +#include "bfad_im.h" +#include "bfad_trcmod.h" +#include "bfa_cb_ioim_macros.h" +#include <fcb/bfa_fcb_fcpim.h> + +BFA_TRC_FILE(LDRV, IM); + +DEFINE_IDR(bfad_im_port_index); +struct scsi_transport_template *bfad_im_scsi_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_slave_alloc(struct scsi_device *sdev); + +void +bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, +			enum bfi_ioim_status io_status, u8 scsi_status, +			int sns_len, u8 *sns_info, s32 residue) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	struct bfad_s         *bfad = drv; +	struct bfad_itnim_data_s *itnim_data; +	struct bfad_itnim_s *itnim; + +	switch (io_status) { +	case BFI_IOIM_STS_OK: +		bfa_trc(bfad, scsi_status); +		cmnd->result = ScsiResult(DID_OK, scsi_status); +		scsi_set_resid(cmnd, 0); + +		if (sns_len > 0) { +			bfa_trc(bfad, sns_len); +			if (sns_len > SCSI_SENSE_BUFFERSIZE) +				sns_len = SCSI_SENSE_BUFFERSIZE; +			memcpy(cmnd->sense_buffer, sns_info, sns_len); +		} +		if (residue > 0) +			scsi_set_resid(cmnd, residue); +		break; + +	case BFI_IOIM_STS_ABORTED: +	case BFI_IOIM_STS_TIMEDOUT: +	case BFI_IOIM_STS_PATHTOV: +	default: +		cmnd->result = ScsiResult(DID_ERROR, 0); +	} + +	/* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ +	if (cmnd->device->host != NULL) +		scsi_dma_unmap(cmnd); + +	cmnd->host_scribble = NULL; +	bfa_trc(bfad, cmnd->result); + +	itnim_data = cmnd->device->hostdata; +	if (itnim_data) { +		itnim = itnim_data->itnim; +		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); +		} else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) { +			/* qfull handling */ +			bfad_os_handle_qfull(itnim, cmnd->device); +		} +	} + +	cmnd->scsi_done(cmnd); +} + +void +bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	struct bfad_itnim_data_s *itnim_data; +	struct bfad_itnim_s *itnim; + +	cmnd->result = ScsiResult(DID_OK, SCSI_STATUS_GOOD); + +	/* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ +	if (cmnd->device->host != NULL) +		scsi_dma_unmap(cmnd); + +	cmnd->host_scribble = NULL; + +	/* Queue depth adjustment */ +	if (bfa_lun_queue_depth > cmnd->device->queue_depth) { +		itnim_data = cmnd->device->hostdata; +		if (itnim_data) { +			itnim = itnim_data->itnim; +			if (itnim) +				bfad_os_ramp_up_qdepth(itnim, cmnd->device); +		} +	} + +	cmnd->scsi_done(cmnd); +} + +void +bfa_cb_ioim_abort(void *drv, struct bfad_ioim_s *dio) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; +	struct bfad_s         *bfad = drv; + +	cmnd->result = ScsiResult(DID_ERROR, 0); + +	/* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ +	if (cmnd->device->host != NULL) +		scsi_dma_unmap(cmnd); + +	bfa_trc(bfad, cmnd->result); +	cmnd->host_scribble = NULL; +} + +void +bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, +		   enum bfi_tskim_status tsk_status) +{ +	struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dtsk; +	wait_queue_head_t *wq; + +	cmnd->SCp.Status |= tsk_status << 1; +	set_bit(IO_DONE_BIT, (unsigned long *)&cmnd->SCp.Status); +	wq = (wait_queue_head_t *) cmnd->SCp.ptr; +	cmnd->SCp.ptr = NULL; + +	if (wq) +		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 * +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 bfa_ioc_attr_s  ioc_attr; +	struct bfad_s         *bfad = im_port->bfad; + +	memset(&ioc_attr, 0, sizeof(ioc_attr)); +	bfa_get_attr(&bfad->bfa, &ioc_attr); + +	memset(bfa_buf, 0, sizeof(bfa_buf)); +	snprintf(bfa_buf, sizeof(bfa_buf), +		 "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s", +		 ioc_attr.adapter_attr.model, bfad->pci_name, +		 BFAD_DRIVER_VERSION); +	return bfa_buf; +} + +/** + * Scsi_Host template entry, aborts the specified SCSI command. + * + * Returns: SUCCESS or FAILED. + */ +static int +bfad_im_abort_handler(struct scsi_cmnd *cmnd) +{ +	struct Scsi_Host *shost = cmnd->device->host; +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_ioim_s *hal_io; +	unsigned long   flags; +	u32        timeout; +	int             rc = FAILED; + +	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 */ +		rc = SUCCESS; +		goto out; +	} +	if (hal_io->dio != (struct bfad_ioim_s *) cmnd) { +		rc = FAILED; +		goto out; +	} + +	bfa_trc(bfad, hal_io->iotag); +	bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT, +		im_port->shost->host_no, cmnd, hal_io->iotag); +	bfa_ioim_abort(hal_io); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	/* Need to wait until the command get aborted */ +	timeout = 10; +	while ((struct bfa_ioim_s *) cmnd->host_scribble == hal_io) { +		set_current_state(TASK_UNINTERRUPTIBLE); +		schedule_timeout(timeout); +		if (timeout < 4 * HZ) +			timeout *= 2; +	} + +	cmnd->scsi_done(cmnd); +	bfa_trc(bfad, hal_io->iotag); +	bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT_COMP, +		im_port->shost->host_no, cmnd, hal_io->iotag); +	return SUCCESS; +out: +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	return rc; +} + +static bfa_status_t +bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, +		     struct bfad_itnim_s *itnim) +{ +	struct bfa_tskim_s *tskim; +	struct bfa_itnim_s *bfa_itnim; +	bfa_status_t    rc = BFA_STATUS_OK; + +	bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim); +	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"); +		rc = BFA_STATUS_FAILED; +		goto out; +	} + +	/* +	 * Set host_scribble to NULL to avoid aborting a task command if +	 * happens. +	 */ +	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, +			    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. + * + */ +static int +bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) +{ +	struct Scsi_Host *shost = cmnd->device->host; +	struct bfad_im_port_s *im_port = +			(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfa_tskim_s *tskim; +	struct bfad_itnim_s   *itnim; +	struct bfa_itnim_s *bfa_itnim; +	DECLARE_WAIT_QUEUE_HEAD(wq); +	int             rc = SUCCESS; +	unsigned long   flags; +	enum bfi_tskim_status task_status; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	itnim = itnim_data->itnim; +	if (!itnim) { +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +		rc = FAILED; +		goto out; +	} + +	tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); +	if (!tskim) { +		BFA_DEV_PRINTF(bfad, BFA_ERR, +				"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. +	 */ +	cmnd->host_scribble = NULL; +	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), +			    FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	wait_event(wq, test_bit(IO_DONE_BIT, +			(unsigned long *)&cmnd->SCp.Status)); + +	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); +		rc = FAILED; +	} + +out: +	return rc; +} + +/** + * Scsi_Host template entry, resets the bus and abort all commands. + */ +static int +bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) +{ +	struct Scsi_Host *shost = cmnd->device->host; +	struct bfad_im_port_s *im_port = +				(struct bfad_im_port_s *) shost->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfad_itnim_s   *itnim; +	unsigned long   flags; +	u32        i, rc, err_cnt = 0; +	DECLARE_WAIT_QUEUE_HEAD(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); +		if (itnim) { +			cmnd->SCp.ptr = (char *)&wq; +			rc = bfad_im_target_reset_send(bfad, cmnd, itnim); +			if (rc != BFA_STATUS_OK) { +				err_cnt++; +				continue; +			} + +			/* wait target reset to complete */ +			spin_unlock_irqrestore(&bfad->bfad_lock, flags); +			wait_event(wq, test_bit(IO_DONE_BIT, +					(unsigned long *)&cmnd->SCp.Status)); +			spin_lock_irqsave(&bfad->bfad_lock, flags); + +			task_status = cmnd->SCp.Status >> 1; +			if (task_status != BFI_TSKIM_STS_OK) { +				BFA_DEV_PRINTF(bfad, BFA_ERR, +					"target reset failure," +					" status: %d\n", task_status); +				err_cnt++; +			} +		} +	} +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (err_cnt) +		return FAILED; + +	return SUCCESS; +} + +/** + * Scsi_Host template entry slave_destroy. + */ +static void +bfad_im_slave_destroy(struct scsi_device *sdev) +{ +	sdev->hostdata = NULL; +	return; +} + +/** + *  BFA FCS itnim callbacks + */ + +/** + * BFA FCS itnim alloc callback, after successful PRLI + * Context: Interrupt + */ +void +bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, +		    struct bfad_itnim_s **itnim_drv) +{ +	*itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC); +	if (*itnim_drv == NULL) +		return; + +	(*itnim_drv)->im = bfad->im; +	*itnim = &(*itnim_drv)->fcs_itnim; +	(*itnim_drv)->state = ITNIM_STATE_NONE; + +	/* +	 * Initiaze the itnim_work +	 */ +	INIT_WORK(&(*itnim_drv)->itnim_work, bfad_im_itnim_work_handler); +	bfad->bfad_flags |= BFAD_RPORT_ONLINE; +} + +/** + * BFA FCS itnim free callback. + * Context: Interrupt. bfad_lock is held + */ +void +bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) +{ +	struct bfad_port_s    *port; +	wwn_t wwpn; +	u32 fcid; +	char wwpn_str[32], fcid_str[16]; + +	/* online to free state transtion should not happen */ +	bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE); + +	itnim_drv->queue_work = 1; +	/* offline request is not yet done, use the same request to free */ +	if (itnim_drv->state == ITNIM_STATE_OFFLINE_PENDING) +		itnim_drv->queue_work = 0; + +	itnim_drv->state = ITNIM_STATE_FREE; +	port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); +	itnim_drv->im_port = port->im_port; +	wwpn = bfa_fcs_itnim_get_pwwn(&itnim_drv->fcs_itnim); +	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, +		port->im_port->shost->host_no, +		fcid_str, wwpn_str); +	bfad_os_itnim_process(itnim_drv); +} + +/** + * BFA FCS itnim online callback. + * Context: Interrupt. bfad_lock is held + */ +void +bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv) +{ +	struct bfad_port_s    *port; + +	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); +} + +/** + * BFA FCS itnim offline callback. + * Context: Interrupt. bfad_lock is held + */ +void +bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) +{ +	struct bfad_port_s    *port; +	struct bfad_s *bfad; + +	port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); +	bfad = port->bfad; +	if ((bfad->pport.flags & BFAD_PORT_DELETE) || +		 (port->flags & BFAD_PORT_DELETE)) { +		itnim_drv->state = ITNIM_STATE_OFFLINE; +		return; +	} +	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; +} + +/** + * Path TOV processing begin notification -- dummy for linux + */ +void +bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim) +{ +} + + + +/** + * Allocate a Scsi_Host for a port. + */ +int +bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port) +{ +	int error = 1; + +	if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) { +		printk(KERN_WARNING "idr_pre_get failure\n"); +		goto out; +	} + +	error = idr_get_new(&bfad_im_port_index, im_port, +					 &im_port->idr_id); +	if (error) { +		printk(KERN_WARNING "idr_get_new failure\n"); +		goto out; +	} + +	im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad); +	if (!im_port->shost) { +		error = 1; +		goto out_free_idr; +	} + +	im_port->shost->hostdata[0] = (unsigned long)im_port; +	im_port->shost->unique_id = im_port->idr_id; +	im_port->shost->this_id = -1; +	im_port->shost->max_id = MAX_FCP_TARGET; +	im_port->shost->max_lun = MAX_FCP_LUN; +	im_port->shost->max_cmd_len = 16; +	im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth; +	im_port->shost->transportt = bfad_im_scsi_transport_template; + +	error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad); +	if (error) { +		printk(KERN_WARNING "bfad_os_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); +out_free_idr: +	idr_remove(&bfad_im_port_index, im_port->idr_id); +out: +	return error; +} + +void +bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) +{ +	unsigned long flags; + +	bfa_trc(bfad, bfad->inst_no); +	bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE, +			im_port->shost->host_no); + +	fc_remove_host(im_port->shost); + +	scsi_remove_host(im_port->shost); +	scsi_host_put(im_port->shost); + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	idr_remove(&bfad_im_port_index, im_port->idr_id); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +} + +static void +bfad_im_port_delete_handler(struct work_struct *work) +{ +	struct bfad_im_port_s *im_port = +		container_of(work, struct bfad_im_port_s, port_delete_work); + +	bfad_im_scsi_host_free(im_port->bfad, im_port); +	bfad_im_port_clean(im_port); +	kfree(im_port); +} + +bfa_status_t +bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port) +{ +	int             rc = BFA_STATUS_OK; +	struct bfad_im_port_s *im_port; + +	im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC); +	if (im_port == NULL) { +		rc = BFA_STATUS_ENOMEM; +		goto ext; +	} +	port->im_port = im_port; +	im_port->port = port; +	im_port->bfad = bfad; + +	INIT_WORK(&im_port->port_delete_work, bfad_im_port_delete_handler); +	INIT_LIST_HEAD(&im_port->itnim_mapped_list); +	INIT_LIST_HEAD(&im_port->binding_list); + +ext: +	return rc; +} + +void +bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port) +{ +	struct bfad_im_port_s *im_port = port->im_port; + +	queue_work(bfad->im->drv_workq, +				&im_port->port_delete_work); +} + +void +bfad_im_port_clean(struct bfad_im_port_s *im_port) +{ +	struct bfad_fcp_binding *bp, *bp_new; +	unsigned long flags; +	struct bfad_s *bfad =  im_port->bfad; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	list_for_each_entry_safe(bp, bp_new, &im_port->binding_list, +					list_entry) { +		list_del(&bp->list_entry); +		kfree(bp); +	} + +	/* the itnim_mapped_list must be empty at this time */ +	bfa_assert(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) +{ +} + +void +bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port) +{ +} + +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; +	} + +	bfad->im = im; +	im->bfad = bfad; + +	if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) { +		kfree(im); +		rc = BFA_STATUS_FAILED; +	} + +ext: +	return rc; +} + +void +bfad_im_probe_undo(struct bfad_s *bfad) +{ +	if (bfad->im) { +		bfad_os_destroy_workq(bfad->im); +		kfree(bfad->im); +		bfad->im = NULL; +	} +} + + + + +int +bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port, +			struct bfad_s *bfad) +{ +    struct device *dev; + +    if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) +		dev = &bfad->pcidev->dev; +    else +		dev = &bfad->pport.im_port->shost->shost_gendev; + +    return scsi_add_host(shost, dev); +} + +struct Scsi_Host * +bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) +{ +	struct scsi_host_template *sht; + +	if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) +		sht = &bfad_im_scsi_host_template; +	else +		sht = &bfad_im_vport_template; + +	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) +{ +	flush_workqueue(bfad->im->drv_workq); +	bfad_im_scsi_host_free(im_port->bfad, im_port); +	bfad_im_port_clean(im_port); +	kfree(im_port); +} + +void +bfad_os_destroy_workq(struct bfad_im_s *im) +{ +	if (im && im->drv_workq) { +		destroy_workqueue(im->drv_workq); +		im->drv_workq = NULL; +	} +} + +bfa_status_t +bfad_os_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", +		 bfad->inst_no); +	im->drv_workq = create_singlethread_workqueue(im->drv_workq_name); +	if (!im->drv_workq) +		return BFA_STATUS_FAILED; + +	return BFA_STATUS_OK; +} + +/** + * Scsi_Host template entry. + * + * Description: + * OS entry point to adjust the queue_depths on a per-device basis. + * Called once per device during the bus scan. + * Return non-zero if fails. + */ +static int +bfad_im_slave_configure(struct scsi_device *sdev) +{ +	if (sdev->tagged_supported) +		scsi_activate_tcq(sdev, bfa_lun_queue_depth); +	else +		scsi_deactivate_tcq(sdev, bfa_lun_queue_depth); + +	return 0; +} + +struct scsi_host_template bfad_im_scsi_host_template = { +	.module = THIS_MODULE, +	.name = BFAD_DRIVER_NAME, +	.info = bfad_im_info, +	.queuecommand = bfad_im_queuecommand, +	.eh_abort_handler = bfad_im_abort_handler, +	.eh_device_reset_handler = bfad_im_reset_lun_handler, +	.eh_bus_reset_handler = bfad_im_reset_bus_handler, + +	.slave_alloc = bfad_im_slave_alloc, +	.slave_configure = bfad_im_slave_configure, +	.slave_destroy = bfad_im_slave_destroy, + +	.this_id = -1, +	.sg_tablesize = BFAD_IO_MAX_SGE, +	.cmd_per_lun = 3, +	.use_clustering = ENABLE_CLUSTERING, +	.shost_attrs = bfad_im_host_attrs, +	.max_sectors = 0xFFFF, +}; + +struct scsi_host_template bfad_im_vport_template = { +	.module = THIS_MODULE, +	.name = BFAD_DRIVER_NAME, +	.info = bfad_im_info, +	.queuecommand = bfad_im_queuecommand, +	.eh_abort_handler = bfad_im_abort_handler, +	.eh_device_reset_handler = bfad_im_reset_lun_handler, +	.eh_bus_reset_handler = bfad_im_reset_bus_handler, + +	.slave_alloc = bfad_im_slave_alloc, +	.slave_configure = bfad_im_slave_configure, +	.slave_destroy = bfad_im_slave_destroy, + +	.this_id = -1, +	.sg_tablesize = BFAD_IO_MAX_SGE, +	.cmd_per_lun = 3, +	.use_clustering = ENABLE_CLUSTERING, +	.shost_attrs = bfad_im_vport_attrs, +	.max_sectors = 0xFFFF, +}; + +void +bfad_im_probe_post(struct bfad_im_s *im) +{ +	flush_workqueue(im->drv_workq); +} + +bfa_status_t +bfad_im_module_init(void) +{ +	bfad_im_scsi_transport_template = +		fc_attach_transport(&bfad_im_fc_function_template); +	if (!bfad_im_scsi_transport_template) +		return BFA_STATUS_ENOMEM; + +	return BFA_STATUS_OK; +} + +void +bfad_im_module_exit(void) +{ +	if (bfad_im_scsi_transport_template) +		fc_release_transport(bfad_im_scsi_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) +{ +	struct scsi_device *tmp_sdev; + +	if (((jiffies - itnim->last_ramp_up_time) > +		BFA_QUEUE_FULL_RAMP_UP_TIME * HZ) && +		((jiffies - itnim->last_queue_full_time) > +		BFA_QUEUE_FULL_RAMP_UP_TIME * HZ)) { +		shost_for_each_device(tmp_sdev, sdev->host) { +			if (bfa_lun_queue_depth > tmp_sdev->queue_depth) { +				if (tmp_sdev->id != sdev->id) +					continue; +				if (tmp_sdev->ordered_tags) +					scsi_adjust_queue_depth(tmp_sdev, +						MSG_ORDERED_TAG, +						tmp_sdev->queue_depth + 1); +				else +					scsi_adjust_queue_depth(tmp_sdev, +						MSG_SIMPLE_TAG, +						tmp_sdev->queue_depth + 1); + +				itnim->last_ramp_up_time = jiffies; +			} +		} +	} +} + +void +bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) +{ +	struct scsi_device *tmp_sdev; + +	itnim->last_queue_full_time = jiffies; + +	shost_for_each_device(tmp_sdev, sdev->host) { +		if (tmp_sdev->id != sdev->id) +			continue; +		scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1); +	} +} + + + + +struct bfad_itnim_s * +bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id) +{ +	struct bfad_itnim_s   *itnim = NULL; + +	/* Search the mapped list for this target ID */ +	list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) { +		if (id == itnim->scsi_tgt_id) +			return itnim; +	} + +	return NULL; +} + +/** + * 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)); + +	if (!rport || fc_remote_port_chkready(rport)) +		return -ENXIO; + +	sdev->hostdata = rport->dd_data; + +	return 0; +} + +void +bfad_os_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; +	union attr { +		struct bfa_pport_attr_s pattr; +		struct bfa_ioc_attr_s  ioc_attr; +	} attr; + +	fc_host_node_name(host) = +		bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port))); +	fc_host_port_name(host) = +		bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port))); + +	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)) +		/* 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; + +	memset(&attr.ioc_attr, 0, sizeof(attr.ioc_attr)); +	bfa_get_attr(&bfad->bfa, &attr.ioc_attr); +	sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s", +		attr.ioc_attr.adapter_attr.model, +		attr.ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION); + +	fc_host_supported_speeds(host) = 0; +	fc_host_supported_speeds(host) |= +		FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | +		FC_PORTSPEED_1GBIT; + +	memset(&attr.pattr, 0, sizeof(attr.pattr)); +	bfa_pport_get_attr(&bfad->bfa, &attr.pattr); +	fc_host_maxframe_size(host) = attr.pattr.pport_cfg.maxfrsize; +} + +static void +bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) +{ +	struct fc_rport_identifiers rport_ids; +	struct fc_rport *fc_rport; +	struct bfad_itnim_data_s *itnim_data; + +	rport_ids.node_name = +		bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim)); +	rport_ids.port_name = +		bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); +	rport_ids.port_id = +		bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim)); +	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; + +	itnim->fc_rport = fc_rport = +		fc_remote_port_add(im_port->shost, 0, &rport_ids); + +	if (!fc_rport) +		return; + +	fc_rport->maxframe_size = +		bfa_fcs_itnim_get_maxfrsize(&itnim->fcs_itnim); +	fc_rport->supported_classes = bfa_fcs_itnim_get_cos(&itnim->fcs_itnim); + +	itnim_data = fc_rport->dd_data; +	itnim_data->itnim = itnim; + +	rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; + +	if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) +		fc_remote_port_rolechg(fc_rport, rport_ids.roles); + +	if ((fc_rport->scsi_target_id != -1) +	    && (fc_rport->scsi_target_id < MAX_FCP_TARGET)) +		itnim->scsi_tgt_id = fc_rport->scsi_target_id; + +	return; +} + +/** + * Work queue handler using FC transport service +* Context: kernel + */ +static void +bfad_im_itnim_work_handler(struct work_struct *work) +{ +	struct bfad_itnim_s   *itnim = container_of(work, struct bfad_itnim_s, +							itnim_work); +	struct bfad_im_s      *im = itnim->im; +	struct bfad_s         *bfad = im->bfad; +	struct bfad_im_port_s *im_port; +	unsigned long   flags; +	struct fc_rport *fc_rport; +	wwn_t wwpn; +	u32 fcid; +	char wwpn_str[32], fcid_str[16]; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	im_port = itnim->im_port; +	bfa_trc(bfad, itnim->state); +	switch (itnim->state) { +	case ITNIM_STATE_ONLINE: +		if (!itnim->fc_rport) { +			spin_unlock_irqrestore(&bfad->bfad_lock, flags); +			bfad_im_fc_rport_add(im_port, itnim); +			spin_lock_irqsave(&bfad->bfad_lock, flags); +			wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); +			fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); +			wwn2str(wwpn_str, wwpn); +			fcid2str(fcid_str, fcid); +			list_add_tail(&itnim->list_entry, +				&im_port->itnim_mapped_list); +			bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_ONLINE, +				im_port->shost->host_no, +				itnim->scsi_tgt_id, +				fcid_str, wwpn_str); +		} else { +			printk(KERN_WARNING +				"%s: itnim %llx is already in online state\n", +				__FUNCTION__, +				bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); +		} + +		break; +	case ITNIM_STATE_OFFLINE_PENDING: +		itnim->state = ITNIM_STATE_OFFLINE; +		if (itnim->fc_rport) { +			fc_rport = itnim->fc_rport; +			((struct bfad_itnim_data_s *) +				fc_rport->dd_data)->itnim = NULL; +			itnim->fc_rport = NULL; +			if (!(im_port->port->flags & BFAD_PORT_DELETE)) { +				spin_unlock_irqrestore(&bfad->bfad_lock, flags); +				fc_rport->dev_loss_tmo = +					bfa_fcpim_path_tov_get(&bfad->bfa) + 1; +				fc_remote_port_delete(fc_rport); +				spin_lock_irqsave(&bfad->bfad_lock, flags); +			} +			wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); +			fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); +			wwn2str(wwpn_str, wwpn); +			fcid2str(fcid_str, fcid); +			list_del(&itnim->list_entry); +			bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_OFFLINE, +				im_port->shost->host_no, +				itnim->scsi_tgt_id, +				fcid_str, wwpn_str); +		} +		break; +	case ITNIM_STATE_FREE: +		if (itnim->fc_rport) { +			fc_rport = itnim->fc_rport; +			((struct bfad_itnim_data_s *) +				fc_rport->dd_data)->itnim = NULL; +			itnim->fc_rport = NULL; +			if (!(im_port->port->flags & BFAD_PORT_DELETE)) { +				spin_unlock_irqrestore(&bfad->bfad_lock, flags); +				fc_rport->dev_loss_tmo = +					bfa_fcpim_path_tov_get(&bfad->bfa) + 1; +				fc_remote_port_delete(fc_rport); +				spin_lock_irqsave(&bfad->bfad_lock, flags); +			} +			list_del(&itnim->list_entry); +		} + +		kfree(itnim); +		break; +	default: +		bfa_assert(0); +		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 *)) +{ +	struct bfad_im_port_s *im_port = +		(struct bfad_im_port_s *) cmnd->device->host->hostdata[0]; +	struct bfad_s         *bfad = im_port->bfad; +	struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata; +	struct bfad_itnim_s   *itnim; +	struct bfa_ioim_s *hal_io; +	unsigned long   flags; +	int             rc; +	s16        sg_cnt = 0; +	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); + +	rc = fc_remote_port_chkready(rport); +	if (rc) { +		cmnd->result = rc; +		done(cmnd); +		return 0; +	} + +	sg_cnt = scsi_dma_map(cmnd); + +	if (sg_cnt < 0) +		return SCSI_MLQUEUE_HOST_BUSY; + +	cmnd->scsi_done = done; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	if (!(bfad->bfad_flags & BFAD_HAL_START_DONE)) { +		printk(KERN_WARNING +			"bfad%d, queuecommand %p %x failed, BFA stopped\n", +		       bfad->inst_no, cmnd, cmnd->cmnd[0]); +		cmnd->result = ScsiResult(DID_NO_CONNECT, 0); +		goto out_fail_cmd; +	} + +	itnim = itnim_data->itnim; +	if (!itnim) { +		cmnd->result = ScsiResult(DID_IMM_RETRY, 0); +		goto out_fail_cmd; +	} + +	hal_io = bfa_ioim_alloc(&bfad->bfa, (struct bfad_ioim_s *) cmnd, +				    itnim->bfa_itnim, sg_cnt); +	if (!hal_io) { +		printk(KERN_WARNING "hal_io failure\n"); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +		scsi_dma_unmap(cmnd); +		return SCSI_MLQUEUE_HOST_BUSY; +	} + +	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); + +	return 0; + +out_fail_cmd: +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	scsi_dma_unmap(cmnd); +	if (done) +		done(cmnd); + +	return 0; +} + +void +bfad_os_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); + +	if (bfad->bfad_flags & BFAD_PORT_ONLINE) { +		rport_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); + +		if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) +			schedule_timeout_uninterruptible(rport_delay * HZ); +	} +} + +int +bfad_os_get_linkup_delay(struct bfad_s *bfad) +{ + +	u8         nwwns = 0; +	wwn_t           *wwns; +	int             ldelay; + +	/* +	 * 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 +	 */ + +	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; +	} + +	return ldelay; +} + + diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h new file mode 100644 index 00000000000..189a5b29e21 --- /dev/null +++ b/drivers/scsi/bfa/bfad_im.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFAD_IM_H__ +#define __BFAD_IM_H__ + +#include "fcs/bfa_fcs_fcpim.h" +#include "bfad_im_compat.h" + +#define FCPI_NAME " fcpim" + +void bfad_flags_set(struct bfad_s *bfad, u32 flags); +bfa_status_t bfad_im_module_init(void); +void bfad_im_module_exit(void); +bfa_status_t bfad_im_probe(struct bfad_s *bfad); +void bfad_im_probe_undo(struct bfad_s *bfad); +void bfad_im_probe_post(struct bfad_im_s *im); +bfa_status_t bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port); +void bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port); +void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port); +void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port); +void bfad_im_port_clean(struct bfad_im_port_s *im_port); +int  bfad_im_scsi_host_alloc(struct bfad_s *bfad, +				struct bfad_im_port_s *im_port); +void bfad_im_scsi_host_free(struct bfad_s *bfad, +				struct bfad_im_port_s *im_port); + +#define MAX_FCP_TARGET 1024 +#define MAX_FCP_LUN 16384 +#define BFAD_TARGET_RESET_TMO 60 +#define BFAD_LUN_RESET_TMO 60 +#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) +#define BFA_QUEUE_FULL_RAMP_UP_TIME 120 +#define BFAD_KOBJ_NAME_LEN 20 + +/* + * itnim flags + */ +#define ITNIM_MAPPED		0x00000001 + +#define SCSI_TASK_MGMT		0x00000001 +#define IO_DONE_BIT			0 + +struct bfad_itnim_data_s { +	struct bfad_itnim_s *itnim; +}; + +struct bfad_im_port_s { +	struct bfad_s         *bfad; +	struct bfad_port_s    *port; +	struct work_struct port_delete_work; +	int             idr_id; +	u16        cur_scsi_id; +	struct list_head binding_list; +	struct Scsi_Host *shost; +	struct list_head itnim_mapped_list; +}; + +enum bfad_itnim_state { +	ITNIM_STATE_NONE, +	ITNIM_STATE_ONLINE, +	ITNIM_STATE_OFFLINE_PENDING, +	ITNIM_STATE_OFFLINE, +	ITNIM_STATE_TIMEOUT, +	ITNIM_STATE_FREE, +}; + +/* + * Per itnim data structure + */ +struct bfad_itnim_s { +	struct list_head list_entry; +	struct bfa_fcs_itnim_s fcs_itnim; +	struct work_struct itnim_work; +	u32        flags; +	enum bfad_itnim_state state; +	struct bfad_im_s *im; +	struct bfad_im_port_s *im_port; +	struct bfad_rport_s *drv_rport; +	struct fc_rport *fc_rport; +	struct bfa_itnim_s *bfa_itnim; +	u16        scsi_tgt_id; +	u16        queue_work; +	unsigned long	last_ramp_up_time; +	unsigned long	last_queue_full_time; +}; + +enum bfad_binding_type { +	FCP_PWWN_BINDING = 0x1, +	FCP_NWWN_BINDING = 0x2, +	FCP_FCID_BINDING = 0x3, +}; + +struct bfad_fcp_binding { +	struct list_head list_entry; +	enum bfad_binding_type binding_type; +	u16        scsi_target_id; +	u32        fc_id; +	wwn_t           nwwn; +	wwn_t           pwwn; +}; + +struct bfad_im_s { +	struct bfad_s         *bfad; +	struct workqueue_struct *drv_workq; +	char   drv_workq_name[BFAD_KOBJ_NAME_LEN]; +}; + +struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, +				struct bfad_s *); +bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad); +void bfad_os_destroy_workq(struct bfad_im_s *im); +void bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv); +void bfad_os_fc_host_init(struct bfad_im_port_s *im_port); +void bfad_os_init_work(struct bfad_im_port_s *im_port); +void bfad_os_scsi_host_free(struct bfad_s *bfad, +				 struct bfad_im_port_s *im_port); +void 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); +struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id); +int bfad_os_scsi_add_host(struct Scsi_Host *shost, +		struct bfad_im_port_s *im_port, struct bfad_s *bfad); + +/* + * scsi_host_template entries + */ +void bfad_im_itnim_unmap(struct bfad_im_port_s  *im_port, +			 struct bfad_itnim_s *itnim); + +extern struct scsi_host_template bfad_im_scsi_host_template; +extern struct scsi_host_template bfad_im_vport_template; +extern struct fc_function_template bfad_im_fc_function_template; +extern struct scsi_transport_template *bfad_im_scsi_transport_template; + +#endif diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h new file mode 100644 index 00000000000..1d3e74ec338 --- /dev/null +++ b/drivers/scsi/bfa/bfad_im_compat.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFAD_IM_COMPAT_H__ +#define __BFAD_IM_COMPAT_H__ + +extern u32 *bfi_image_buf; +extern u32 bfi_image_size; + +extern struct device_attribute *bfad_im_host_attrs[]; +extern struct device_attribute *bfad_im_vport_attrs[]; + +u32 *bfad_get_firmware_buf(struct pci_dev *pdev); +u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, +			u32 *bfi_image_size, char *fw_name); + +static inline u32 * +bfad_load_fwimg(struct pci_dev *pdev) +{ +	return(bfad_get_firmware_buf(pdev)); +} + +static inline void +bfad_free_fwimg(void) +{ +	if (bfi_image_ct_size && bfi_image_ct) +		vfree(bfi_image_ct); +	if (bfi_image_cb_size && bfi_image_cb) +		vfree(bfi_image_cb); +} + +#endif diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c new file mode 100644 index 00000000000..f104e029cac --- /dev/null +++ b/drivers/scsi/bfa/bfad_intr.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include "bfad_drv.h" +#include "bfad_trcmod.h" + +BFA_TRC_FILE(LDRV, INTR); + +/** + *  bfa_isr BFA driver interrupt functions + */ +irqreturn_t bfad_intx(int irq, void *dev_id); +static int msix_disable; +module_param(msix_disable, int, S_IRUGO | S_IWUSR); +/** + * Line based interrupt handler. + */ +irqreturn_t +bfad_intx(int irq, void *dev_id) +{ +	struct bfad_s         *bfad = dev_id; +	struct list_head         doneq; +	unsigned long   flags; +	bfa_boolean_t rc; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); +	rc = bfa_intx(&bfad->bfa); +	if (!rc) { +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +		return IRQ_NONE; +	} + +	bfa_comp_deq(&bfad->bfa, &doneq); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (!list_empty(&doneq)) { +		bfa_comp_process(&bfad->bfa, &doneq); + +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		bfa_comp_free(&bfad->bfa, &doneq); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +		bfa_trc_fp(bfad, irq); +	} + +	return IRQ_HANDLED; + +} + +static irqreturn_t +bfad_msix(int irq, void *dev_id) +{ +	struct bfad_msix_s *vec = dev_id; +	struct bfad_s *bfad = vec->bfad; +	struct list_head doneq; +	unsigned long   flags; + +	spin_lock_irqsave(&bfad->bfad_lock, flags); + +	bfa_msix(&bfad->bfa, vec->msix.entry); +	bfa_comp_deq(&bfad->bfa, &doneq); +	spin_unlock_irqrestore(&bfad->bfad_lock, flags); + +	if (!list_empty(&doneq)) { +		bfa_comp_process(&bfad->bfa, &doneq); + +		spin_lock_irqsave(&bfad->bfad_lock, flags); +		bfa_comp_free(&bfad->bfa, &doneq); +		spin_unlock_irqrestore(&bfad->bfad_lock, flags); +	} + +	return IRQ_HANDLED; +} + +/** + * Initialize the MSIX entry table. + */ +static void +bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries, +			 int mask, int max_bit) +{ +	int             i; +	int             match = 0x00000001; + +	for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) { +		if (mask & match) { +			bfad->msix_tab[bfad->nvec].msix.entry = i; +			bfad->msix_tab[bfad->nvec].bfad = bfad; +			msix_entries[bfad->nvec].entry = i; +			bfad->nvec++; +		} + +		match <<= 1; +	} + +} + +int +bfad_install_msix_handler(struct bfad_s *bfad) +{ +	int             i, error = 0; + +	for (i = 0; i < bfad->nvec; i++) { +		error = request_irq(bfad->msix_tab[i].msix.vector, +				    (irq_handler_t) bfad_msix, 0, +				    BFAD_DRIVER_NAME, &bfad->msix_tab[i]); +		bfa_trc(bfad, i); +		bfa_trc(bfad, bfad->msix_tab[i].msix.vector); +		if (error) { +			int             j; + +			for (j = 0; j < i; j++) +				free_irq(bfad->msix_tab[j].msix.vector, +						&bfad->msix_tab[j]); + +			return 1; +		} +	} + +	return 0; +} + +/** + * Setup MSIX based interrupt. + */ +int +bfad_setup_intr(struct bfad_s *bfad) +{ +	int error = 0; +	u32 mask = 0, i, num_bit = 0, max_bit = 0; +	struct msix_entry msix_entries[MAX_MSIX_ENTRY]; + +	/* Call BFA to get the msix map for this PCI function.  */ +	bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); + +	/* Set up the msix entry table */ +	bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); + +	if (!msix_disable) { +		error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); +		if (error) { +			/* +			 * Only error number of vector is available. +			 * We don't have a mechanism to map multiple +			 * interrupts into one vector, so even if we +			 * can try to request less vectors, we don't +			 * know how to associate interrupt events to +			 *  vectors. Linux doesn't dupicate vectors +			 * in the MSIX table for this case. +			 */ + +			printk(KERN_WARNING "bfad%d: " +				"pci_enable_msix failed (%d)," +				" use line based.\n", bfad->inst_no, error); + +			goto line_based; +		} + +		/* Save the vectors */ +		for (i = 0; i < bfad->nvec; i++) { +			bfa_trc(bfad, msix_entries[i].vector); +			bfad->msix_tab[i].msix.vector = msix_entries[i].vector; +		} + +		bfa_msix_init(&bfad->bfa, bfad->nvec); + +		bfad->bfad_flags |= BFAD_MSIX_ON; + +		return error; +	} + +line_based: +	error = 0; +	if (request_irq +	    (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS, +	     BFAD_DRIVER_NAME, bfad) != 0) { +		/* Enable interrupt handler failed */ +		return 1; +	} + +	return error; +} + +void +bfad_remove_intr(struct bfad_s *bfad) +{ +	int             i; + +	if (bfad->bfad_flags & BFAD_MSIX_ON) { +		for (i = 0; i < bfad->nvec; i++) +			free_irq(bfad->msix_tab[i].msix.vector, +					&bfad->msix_tab[i]); + +		pci_disable_msix(bfad->pcidev); +		bfad->bfad_flags &= ~BFAD_MSIX_ON; +	} else { +		free_irq(bfad->pcidev->irq, bfad); +	} +} + + diff --git a/drivers/scsi/bfa/bfad_ipfc.h b/drivers/scsi/bfa/bfad_ipfc.h new file mode 100644 index 00000000000..718bc522767 --- /dev/null +++ b/drivers/scsi/bfa/bfad_ipfc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DRV_IPFC_H__ +#define __BFA_DRV_IPFC_H__ + + +#define IPFC_NAME "" + +#define bfad_ipfc_module_init(x) do {} while (0) +#define bfad_ipfc_module_exit(x) do {} while (0) +#define bfad_ipfc_probe(x) do {} while (0) +#define bfad_ipfc_probe_undo(x) do {} while (0) +#define bfad_ipfc_port_config(x, y) BFA_STATUS_OK +#define bfad_ipfc_port_unconfig(x, y) do {} while (0) + +#define bfad_ipfc_probe_post(x) do {} while (0) +#define bfad_ipfc_port_new(x, y, z) BFA_STATUS_OK +#define bfad_ipfc_port_delete(x, y) do {} while (0) +#define bfad_ipfc_port_online(x, y) do {} while (0) +#define bfad_ipfc_port_offline(x, y) do {} while (0) + +#define bfad_ip_get_attr(x) BFA_STATUS_FAILED +#define bfad_ip_reset_drv_stats(x) BFA_STATUS_FAILED +#define bfad_ip_get_drv_stats(x, y) BFA_STATUS_FAILED +#define bfad_ip_enable_ipfc(x, y, z) BFA_STATUS_FAILED + + +#endif diff --git a/drivers/scsi/bfa/bfad_os.c b/drivers/scsi/bfa/bfad_os.c new file mode 100644 index 00000000000..faf47b4f1a3 --- /dev/null +++ b/drivers/scsi/bfa/bfad_os.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfad_os.c Linux driver OS specific calls. + */ + +#include "bfa_os_inc.h" +#include "bfad_drv.h" + +void +bfa_os_gettimeofday(struct bfa_timeval_s *tv) +{ +	struct timeval  tmp_tv; + +	do_gettimeofday(&tmp_tv); +	tv->tv_sec = (u32) tmp_tv.tv_sec; +	tv->tv_usec = (u32) tmp_tv.tv_usec; +} + +void +bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id, +			const char *fmt, ...) +{ +	va_list ap; +	#define BFA_STRING_256	256 +	char tmp[BFA_STRING_256]; + +	va_start(ap, fmt); +	vsprintf(tmp, fmt, ap); +	va_end(ap); + +	printk(tmp); +} + + diff --git a/drivers/scsi/bfa/bfad_tm.h b/drivers/scsi/bfa/bfad_tm.h new file mode 100644 index 00000000000..4901b1b7df0 --- /dev/null +++ b/drivers/scsi/bfa/bfad_tm.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* + * Brocade Fibre Channel HBA Linux Target Mode Driver + */ + +/** + *  tm/dummy/bfad_tm.h BFA callback dummy header file for BFA Linux target mode PCI interface module. + */ + +#ifndef __BFAD_TM_H__ +#define __BFAD_TM_H__ + +#include <defs/bfa_defs_status.h> + +#define FCPT_NAME 		"" + +/* + * Called from base Linux driver on (De)Init events + */ + +/* attach tgt template with scst */ +#define bfad_tm_module_init()	do {} while (0) + +/* detach/release tgt template */ +#define bfad_tm_module_exit()	do {} while (0) + +#define bfad_tm_probe(x)	do {} while (0) +#define bfad_tm_probe_undo(x)	do {} while (0) +#define bfad_tm_probe_post(x)	do {} while (0) + +/* + * Called by base Linux driver but triggered by BFA FCS on config events + */ +#define bfad_tm_port_new(x, y)		BFA_STATUS_OK +#define bfad_tm_port_delete(x, y)	do {} while (0) + +/* + * Called by base Linux driver but triggered by BFA FCS on PLOGI/O events + */ +#define bfad_tm_port_online(x, y)	do {} while (0) +#define bfad_tm_port_offline(x, y)	do {} while (0) + +#endif diff --git a/drivers/scsi/bfa/bfad_trcmod.h b/drivers/scsi/bfa/bfad_trcmod.h new file mode 100644 index 00000000000..2827b2acd04 --- /dev/null +++ b/drivers/scsi/bfa/bfad_trcmod.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfad_trcmod.h Linux driver trace modules + */ + + +#ifndef __BFAD_TRCMOD_H__ +#define __BFAD_TRCMOD_H__ + +#include <cs/bfa_trc.h> + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { +	/* 2.6 Driver */ +	BFA_TRC_LDRV_BFAD		= 1, +	BFA_TRC_LDRV_BFAD_2_6		= 2, +	BFA_TRC_LDRV_BFAD_2_6_9		= 3, +	BFA_TRC_LDRV_BFAD_2_6_10	= 4, +	BFA_TRC_LDRV_INTR		= 5, +	BFA_TRC_LDRV_IOCTL		= 6, +	BFA_TRC_LDRV_OS			= 7, +	BFA_TRC_LDRV_IM			= 8, +	BFA_TRC_LDRV_IM_2_6		= 9, +	BFA_TRC_LDRV_IM_2_6_9		= 10, +	BFA_TRC_LDRV_IM_2_6_10		= 11, +	BFA_TRC_LDRV_TM			= 12, +	BFA_TRC_LDRV_IPFC		= 13, +	BFA_TRC_LDRV_IM_2_4		= 14, +	BFA_TRC_LDRV_IM_VMW		= 15, +	BFA_TRC_LDRV_IM_LT_2_6_10	= 16, +}; + +#endif /* __BFAD_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/fab.c b/drivers/scsi/bfa/fab.c new file mode 100644 index 00000000000..7e3a4d5d7bb --- /dev/null +++ b/drivers/scsi/bfa/fab.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "lport_priv.h" + +/** + *  fab.c port fab implementation. + */ + +/** + *  bfa_fcs_port_fab_public port fab public functions + */ + +/** + *   Called by port to initialize fabric services of the base port. + */ +void +bfa_fcs_port_fab_init(struct bfa_fcs_port_s *port) +{ +	bfa_fcs_port_ns_init(port); +	bfa_fcs_port_scn_init(port); +	bfa_fcs_port_ms_init(port); +} + +/** + *   Called by port to notify transition to online state. + */ +void +bfa_fcs_port_fab_online(struct bfa_fcs_port_s *port) +{ +	bfa_fcs_port_ns_online(port); +	bfa_fcs_port_scn_online(port); +} + +/** + *   Called by port to notify transition to offline state. + */ +void +bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *port) +{ +	bfa_fcs_port_ns_offline(port); +	bfa_fcs_port_scn_offline(port); +	bfa_fcs_port_ms_offline(port); +} diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c new file mode 100644 index 00000000000..a8b14c47b00 --- /dev/null +++ b/drivers/scsi/bfa/fabric.c @@ -0,0 +1,1278 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fabric.c Fabric module implementation. + */ + +#include "fcs_fabric.h" +#include "fcs_lport.h" +#include "fcs_vport.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs_auth.h" +#include "fcs.h" +#include "fcbuild.h" +#include <log/bfa_log_fcs.h> +#include <aen/bfa_aen_port.h> +#include <bfa_svc.h> + +BFA_TRC_FILE(FCS, FABRIC); + +#define BFA_FCS_FABRIC_RETRY_DELAY	(2000)	/* Milliseconds */ +#define BFA_FCS_FABRIC_CLEANUP_DELAY	(10000)	/* Milliseconds */ + +#define bfa_fcs_fabric_set_opertype(__fabric) do {          \ +    if (bfa_pport_get_topology((__fabric)->fcs->bfa)    \ +				== BFA_PPORT_TOPOLOGY_P2P)   \ +	    (__fabric)->oper_type = BFA_PPORT_TYPE_NPORT;       \ +    else                                                    \ +	    (__fabric)->oper_type = BFA_PPORT_TYPE_NLPORT;      \ +} while (0) + +/* + * forward declarations + */ +static void     bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_delay(void *cbarg); +static void     bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_delete_comp(void *cbarg); +static void     bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, +					  struct fchs_s *fchs, u16 len); +static void     bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, +					     struct fchs_s *fchs, u16 len); +static void     bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric); +static void     bfa_fcs_fabric_flogiacc_comp(void *fcsarg, +					     struct bfa_fcxp_s *fcxp, +					     void *cbarg, bfa_status_t status, +					     u32 rsp_len, +					     u32 resid_len, +					     struct fchs_s *rspfchs); +/** + *  fcs_fabric_sm fabric state machine functions + */ + +/** + * Fabric state machine events + */ +enum bfa_fcs_fabric_event { +	BFA_FCS_FABRIC_SM_CREATE = 1,	/*  fabric create from driver */ +	BFA_FCS_FABRIC_SM_DELETE = 2,	/*  fabric delete from driver */ +	BFA_FCS_FABRIC_SM_LINK_DOWN = 3,	/*  link down from port */ +	BFA_FCS_FABRIC_SM_LINK_UP = 4,	/*  link up from port */ +	BFA_FCS_FABRIC_SM_CONT_OP = 5,	/*  continue op from flogi/auth */ +	BFA_FCS_FABRIC_SM_RETRY_OP = 6,	/*  continue op from flogi/auth */ +	BFA_FCS_FABRIC_SM_NO_FABRIC = 7,	/*  no fabric from flogi/auth +						 */ +	BFA_FCS_FABRIC_SM_PERF_EVFP = 8,	/*  perform EVFP from +						 *flogi/auth */ +	BFA_FCS_FABRIC_SM_ISOLATE = 9,	/*  isolate from EVFP processing */ +	BFA_FCS_FABRIC_SM_NO_TAGGING = 10,/*  no VFT tagging from EVFP */ +	BFA_FCS_FABRIC_SM_DELAYED = 11,	/*  timeout delay event */ +	BFA_FCS_FABRIC_SM_AUTH_FAILED = 12,	/*  authentication failed */ +	BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13,	/*  authentication successful +						 */ +	BFA_FCS_FABRIC_SM_DELCOMP = 14,	/*  all vports deleted event */ +	BFA_FCS_FABRIC_SM_LOOPBACK = 15,	/*  Received our own FLOGI */ +	BFA_FCS_FABRIC_SM_START = 16,	/*  fabric delete from driver */ +}; + +static void     bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, +					 enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, +					  enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, +					   enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, +					enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, +					      enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, +				       enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, +					      enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, +					   enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, +					   enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, +					 enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, +				       enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, +					    enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, +					   enum bfa_fcs_fabric_event event); +static void     bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, +					   enum bfa_fcs_fabric_event event); +/** + *   Beginning state before fabric creation. + */ +static void +bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, +			 enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_CREATE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); +		bfa_fcs_fabric_init(fabric); +		bfa_fcs_lport_init(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, +				   &fabric->bport.port_cfg, NULL); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_UP: +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Beginning state before fabric creation. + */ +static void +bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, +			  enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_START: +		if (bfa_pport_is_linkup(fabric->fcs->bfa)) { +			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); +			bfa_fcs_fabric_login(fabric); +		} else +			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_UP: +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); +		bfa_fcs_modexit_comp(fabric->fcs); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Link is down, awaiting LINK UP event from port. This is also the + *   first state at fabric creation. + */ +static void +bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, +			   enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_LINK_UP: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); +		bfa_fcs_fabric_login(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_RETRY_OP: +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   FLOGI is in progress, awaiting FLOGI reply. + */ +static void +bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, +			enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_CONT_OP: + +		bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); +		fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; + +		if (fabric->auth_reqd && fabric->is_auth) { +			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth); +			bfa_trc(fabric->fcs, event); +		} else { +			bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); +			bfa_fcs_fabric_notify_online(fabric); +		} +		break; + +	case BFA_FCS_FABRIC_SM_RETRY_OP: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry); +		bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer, +				bfa_fcs_fabric_delay, fabric, +				BFA_FCS_FABRIC_RETRY_DELAY); +		break; + +	case BFA_FCS_FABRIC_SM_LOOPBACK: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback); +		bfa_lps_discard(fabric->lps); +		bfa_fcs_fabric_set_opertype(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_NO_FABRIC: +		fabric->fab_type = BFA_FCS_FABRIC_N2N; +		bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); +		bfa_fcs_fabric_notify_online(fabric); +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_lps_discard(fabric->lps); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_lps_discard(fabric->lps); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + + +static void +bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, +			      enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_DELAYED: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); +		bfa_fcs_fabric_login(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_timer_stop(&fabric->delay_timer); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_timer_stop(&fabric->delay_timer); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Authentication is in progress, awaiting authentication results. + */ +static void +bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, +		       enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_AUTH_FAILED: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); +		bfa_lps_discard(fabric->lps); +		break; + +	case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); +		bfa_fcs_fabric_notify_online(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_PERF_EVFP: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_lps_discard(fabric->lps); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Authentication failed + */ +static void +bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, +			      enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_fcs_fabric_notify_offline(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Port is in loopback mode. + */ +static void +bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, +			   enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_fcs_fabric_notify_offline(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   There is no attached fabric - private loop or NPort-to-NPort topology. + */ +static void +bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, +			   enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_lps_discard(fabric->lps); +		bfa_fcs_fabric_notify_offline(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_NO_FABRIC: +		bfa_trc(fabric->fcs, fabric->bb_credit); +		bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Fabric is online - normal operating state. + */ +static void +bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, +			 enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); +		bfa_lps_discard(fabric->lps); +		bfa_fcs_fabric_notify_offline(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_DELETE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); +		bfa_fcs_fabric_delete(fabric); +		break; + +	case BFA_FCS_FABRIC_SM_AUTH_FAILED: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); +		bfa_lps_discard(fabric->lps); +		break; + +	case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   Exchanging virtual fabric parameters. + */ +static void +bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, +		       enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_CONT_OP: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done); +		break; + +	case BFA_FCS_FABRIC_SM_ISOLATE: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + +/** + *   EVFP exchange complete and VFT tagging is enabled. + */ +static void +bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, +			    enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); +} + +/** + *   Port is isolated after EVFP exchange due to VF_ID mismatch (N and F). + */ +static void +bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, +			   enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	bfa_log(fabric->fcs->logm, BFA_LOG_FCS_FABRIC_ISOLATED, +		fabric->bport.port_cfg.pwwn, fabric->fcs->port_vfid, +		fabric->event_arg.swp_vfid); +} + +/** + *   Fabric is being deleted, awaiting vport delete completions. + */ +static void +bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, +			   enum bfa_fcs_fabric_event event) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, event); + +	switch (event) { +	case BFA_FCS_FABRIC_SM_DELCOMP: +		bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); +		bfa_fcs_modexit_comp(fabric->fcs); +		break; + +	case BFA_FCS_FABRIC_SM_LINK_UP: +		break; + +	case BFA_FCS_FABRIC_SM_LINK_DOWN: +		bfa_fcs_fabric_notify_offline(fabric); +		break; + +	default: +		bfa_sm_fault(fabric->fcs, event); +	} +} + + + +/** + *  fcs_fabric_private fabric private functions + */ + +static void +bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg; + +	port_cfg->roles = BFA_PORT_ROLE_FCP_IM; +	port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc); +	port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc); +} + +/** + * Port Symbolic Name Creation for base port. + */ +void +bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg; +	struct bfa_adapter_attr_s adapter_attr; +	struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info; + +	bfa_os_memset((void *)&adapter_attr, 0, +		      sizeof(struct bfa_adapter_attr_s)); +	bfa_ioc_get_adapter_attr(&fabric->fcs->bfa->ioc, &adapter_attr); + +	/* +	 * Model name/number +	 */ +	strncpy((char *)&port_cfg->sym_name, adapter_attr.model, +		BFA_FCS_PORT_SYMBNAME_MODEL_SZ); +	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, +		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + +	/* +	 * Driver Version +	 */ +	strncat((char *)&port_cfg->sym_name, (char *)driver_info->version, +		BFA_FCS_PORT_SYMBNAME_VERSION_SZ); +	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, +		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + +	/* +	 * Host machine name +	 */ +	strncat((char *)&port_cfg->sym_name, +		(char *)driver_info->host_machine_name, +		BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ); +	strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, +		sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + +	/* +	 * Host OS Info : +	 * If OS Patch Info is not there, do not truncate any bytes from the +	 * OS name string and instead copy the entire OS info string (64 bytes). +	 */ +	if (driver_info->host_os_patch[0] == '\0') { +		strncat((char *)&port_cfg->sym_name, +			(char *)driver_info->host_os_name, BFA_FCS_OS_STR_LEN); +		strncat((char *)&port_cfg->sym_name, +			BFA_FCS_PORT_SYMBNAME_SEPARATOR, +			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); +	} else { +		strncat((char *)&port_cfg->sym_name, +			(char *)driver_info->host_os_name, +			BFA_FCS_PORT_SYMBNAME_OSINFO_SZ); +		strncat((char *)&port_cfg->sym_name, +			BFA_FCS_PORT_SYMBNAME_SEPARATOR, +			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); + +		/* +		 * Append host OS Patch Info +		 */ +		strncat((char *)&port_cfg->sym_name, +			(char *)driver_info->host_os_patch, +			BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ); +	} + +	/* +	 * null terminate +	 */ +	port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; +} + +/** + * bfa lps login completion callback + */ +void +bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) +{ +	struct bfa_fcs_fabric_s *fabric = uarg; + +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_trc(fabric->fcs, status); + +	switch (status) { +	case BFA_STATUS_OK: +		fabric->stats.flogi_accepts++; +		break; + +	case BFA_STATUS_INVALID_MAC: +		/* +		 * Only for CNA +		 */ +		fabric->stats.flogi_acc_err++; +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + +		return; + +	case BFA_STATUS_EPROTOCOL: +		switch (bfa_lps_get_extstatus(fabric->lps)) { +		case BFA_EPROTO_BAD_ACCEPT: +			fabric->stats.flogi_acc_err++; +			break; + +		case BFA_EPROTO_UNKNOWN_RSP: +			fabric->stats.flogi_unknown_rsp++; +			break; + +		default: +			break; +		} +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); + +		return; + +	case BFA_STATUS_FABRIC_RJT: +		fabric->stats.flogi_rejects++; +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); +		return; + +	default: +		fabric->stats.flogi_rsp_err++; +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); +		return; +	} + +	fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps); +	bfa_trc(fabric->fcs, fabric->bb_credit); + +	if (!bfa_lps_is_brcd_fabric(fabric->lps)) +		fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps); + +	/* +	 * Check port type. It should be 1 = F-port. +	 */ +	if (bfa_lps_is_fport(fabric->lps)) { +		fabric->bport.pid = bfa_lps_get_pid(fabric->lps); +		fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps); +		fabric->is_auth = bfa_lps_is_authreq(fabric->lps); +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP); +	} else { +		/* +		 * Nport-2-Nport direct attached +		 */ +		fabric->bport.port_topo.pn2n.rem_port_wwn = +			bfa_lps_get_peer_pwwn(fabric->lps); +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); +	} + +	bfa_trc(fabric->fcs, fabric->bport.pid); +	bfa_trc(fabric->fcs, fabric->is_npiv); +	bfa_trc(fabric->fcs, fabric->is_auth); +} + +/** + * 		Allocate and send FLOGI. + */ +static void +bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_s   *bfa = fabric->fcs->bfa; +	struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg; +	u8         alpa = 0; + +	if (bfa_pport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP) +		alpa = bfa_pport_get_myalpa(bfa); + +	bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_pport_get_maxfrsize(bfa), +		      pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd); + +	fabric->stats.flogi_sent++; +} + +static void +bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_fcs_vport_s *vport; +	struct list_head *qe, *qen; + +	bfa_trc(fabric->fcs, fabric->fabric_name); + +	bfa_fcs_fabric_set_opertype(fabric); +	fabric->stats.fabric_onlines++; + +	/** +	 * notify online event to base and then virtual ports +	 */ +	bfa_fcs_port_online(&fabric->bport); + +	list_for_each_safe(qe, qen, &fabric->vport_q) { +		vport = (struct bfa_fcs_vport_s *)qe; +		bfa_fcs_vport_online(vport); +	} +} + +static void +bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_fcs_vport_s *vport; +	struct list_head *qe, *qen; + +	bfa_trc(fabric->fcs, fabric->fabric_name); +	fabric->stats.fabric_offlines++; + +	/** +	 * notify offline event first to vports and then base port. +	 */ +	list_for_each_safe(qe, qen, &fabric->vport_q) { +		vport = (struct bfa_fcs_vport_s *)qe; +		bfa_fcs_vport_offline(vport); +	} + +	bfa_fcs_port_offline(&fabric->bport); + +	fabric->fabric_name = 0; +	fabric->fabric_ip_addr[0] = 0; +} + +static void +bfa_fcs_fabric_delay(void *cbarg) +{ +	struct bfa_fcs_fabric_s *fabric = cbarg; + +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); +} + +/** + * Delete all vports and wait for vport delete completions. + */ +static void +bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_fcs_vport_s *vport; +	struct list_head *qe, *qen; + +	list_for_each_safe(qe, qen, &fabric->vport_q) { +		vport = (struct bfa_fcs_vport_s *)qe; +		bfa_fcs_vport_delete(vport); +	} + +	bfa_fcs_port_delete(&fabric->bport); +	bfa_wc_wait(&fabric->wc); +} + +static void +bfa_fcs_fabric_delete_comp(void *cbarg) +{ +	struct bfa_fcs_fabric_s *fabric = cbarg; + +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); +} + + + +/** + *  fcs_fabric_public fabric public functions + */ + +/** + *   Module initialization + */ +void +bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) +{ +	struct bfa_fcs_fabric_s *fabric; + +	fabric = &fcs->fabric; +	bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); + +	/** +	 * Initialize base fabric. +	 */ +	fabric->fcs = fcs; +	INIT_LIST_HEAD(&fabric->vport_q); +	INIT_LIST_HEAD(&fabric->vf_q); +	fabric->lps = bfa_lps_alloc(fcs->bfa); +	bfa_assert(fabric->lps); + +	/** +	 * Initialize fabric delete completion handler. Fabric deletion is complete +	 * when the last vport delete is complete. +	 */ +	bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); +	bfa_wc_up(&fabric->wc);	/* For the base port */ + +	bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CREATE); +	bfa_trc(fcs, 0); +} + +/** + *   Module cleanup + */ +void +bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) +{ +	struct bfa_fcs_fabric_s *fabric; + +	bfa_trc(fcs, 0); + +	/** +	 * Cleanup base fabric. +	 */ +	fabric = &fcs->fabric; +	bfa_lps_delete(fabric->lps); +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); +} + +/** + * Fabric module start -- kick starts FCS actions + */ +void +bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs) +{ +	struct bfa_fcs_fabric_s *fabric; + +	bfa_trc(fcs, 0); +	fabric = &fcs->fabric; +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START); +} + +/** + *   Suspend fabric activity as part of driver suspend. + */ +void +bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs) +{ +} + +bfa_boolean_t +bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric) +{ +	return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_loopback)); +} + +enum bfa_pport_type +bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric) +{ +	return fabric->oper_type; +} + +/** + *   Link up notification from BFA physical port module. + */ +void +bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP); +} + +/** + *   Link down notification from BFA physical port module. + */ +void +bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) +{ +	bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); +} + +/** + *   A child vport is being created in the fabric. + * + *   Call from vport module at vport creation. A list of base port and vports + *   belonging to a fabric is maintained to propagate link events. + * + *   param[in] fabric - Fabric instance. This can be a base fabric or vf. + *   param[in] vport  - Vport being created. + * + *   @return None (always succeeds) + */ +void +bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, +			struct bfa_fcs_vport_s *vport) +{ +	/** +	 * - add vport to fabric's vport_q +	 */ +	bfa_trc(fabric->fcs, fabric->vf_id); + +	list_add_tail(&vport->qe, &fabric->vport_q); +	fabric->num_vports++; +	bfa_wc_up(&fabric->wc); +} + +/** + *   A child vport is being deleted from fabric. + * + *   Vport is being deleted. + */ +void +bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, +			struct bfa_fcs_vport_s *vport) +{ +	list_del(&vport->qe); +	fabric->num_vports--; +	bfa_wc_down(&fabric->wc); +} + +/** + *   Base port is deleted. + */ +void +bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric) +{ +	bfa_wc_down(&fabric->wc); +} + +/** + *    Check if fabric is online. + * + *   param[in] fabric - Fabric instance. This can be a base fabric or vf. + * + *   @return  TRUE/FALSE + */ +int +bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric) +{ +	return (bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online)); +} + + +bfa_status_t +bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs, +		     struct bfa_port_cfg_s *port_cfg, +		     struct bfad_vf_s *vf_drv) +{ +	bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit); +	return BFA_STATUS_OK; +} + +/** + * Lookup for a vport withing a fabric given its pwwn + */ +struct bfa_fcs_vport_s * +bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) +{ +	struct bfa_fcs_vport_s *vport; +	struct list_head *qe; + +	list_for_each(qe, &fabric->vport_q) { +		vport = (struct bfa_fcs_vport_s *)qe; +		if (bfa_fcs_port_get_pwwn(&vport->lport) == pwwn) +			return vport; +	} + +	return NULL; +} + +/** + *    In a given fabric, return the number of lports. + * + *   param[in] fabric - Fabric instance. This can be a base fabric or vf. + * +*    @return : 1 or more. + */ +u16 +bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric) +{ +	return (fabric->num_vports); +} + +/** + * 		Unsolicited frame receive handling. + */ +void +bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, +		       u16 len) +{ +	u32        pid = fchs->d_id; +	struct bfa_fcs_vport_s *vport; +	struct list_head *qe; +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); +	struct fc_logi_s     *flogi = (struct fc_logi_s *) els_cmd; + +	bfa_trc(fabric->fcs, len); +	bfa_trc(fabric->fcs, pid); + +	/** +	 * Look for our own FLOGI frames being looped back. This means an +	 * external loopback cable is in place. Our own FLOGI frames are +	 * sometimes looped back when switch port gets temporarily bypassed. +	 */ +	if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT)) +	    && (els_cmd->els_code == FC_ELS_FLOGI) +	    && (flogi->port_name == bfa_fcs_port_get_pwwn(&fabric->bport))) { +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK); +		return; +	} + +	/** +	 * FLOGI/EVFP exchanges should be consumed by base fabric. +	 */ +	if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) { +		bfa_trc(fabric->fcs, pid); +		bfa_fcs_fabric_process_uf(fabric, fchs, len); +		return; +	} + +	if (fabric->bport.pid == pid) { +		/** +		 * All authentication frames should be routed to auth +		 */ +		bfa_trc(fabric->fcs, els_cmd->els_code); +		if (els_cmd->els_code == FC_ELS_AUTH) { +			bfa_trc(fabric->fcs, els_cmd->els_code); +			fabric->auth.response = (u8 *) els_cmd; +			return; +		} + +		bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs)); +		bfa_fcs_port_uf_recv(&fabric->bport, fchs, len); +		return; +	} + +	/** +	 * look for a matching local port ID +	 */ +	list_for_each(qe, &fabric->vport_q) { +		vport = (struct bfa_fcs_vport_s *)qe; +		if (vport->lport.pid == pid) { +			bfa_fcs_port_uf_recv(&vport->lport, fchs, len); +			return; +		} +	} +	bfa_trc(fabric->fcs, els_cmd->els_code); +	bfa_fcs_port_uf_recv(&fabric->bport, fchs, len); +} + +/** + * 		Unsolicited frames to be processed by fabric. + */ +static void +bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, +			  u16 len) +{ +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	bfa_trc(fabric->fcs, els_cmd->els_code); + +	switch (els_cmd->els_code) { +	case FC_ELS_FLOGI: +		bfa_fcs_fabric_process_flogi(fabric, fchs, len); +		break; + +	default: +		/* +		 * need to generate a LS_RJT +		 */ +		break; +	} +} + +/** + * 	Process	incoming FLOGI + */ +static void +bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, +			struct fchs_s *fchs, u16 len) +{ +	struct fc_logi_s     *flogi = (struct fc_logi_s *) (fchs + 1); +	struct bfa_fcs_port_s *bport = &fabric->bport; + +	bfa_trc(fabric->fcs, fchs->s_id); + +	fabric->stats.flogi_rcvd++; +	/* +	 * Check port type. It should be 0 = n-port. +	 */ +	if (flogi->csp.port_type) { +		/* +		 * @todo: may need to send a LS_RJT +		 */ +		bfa_trc(fabric->fcs, flogi->port_name); +		fabric->stats.flogi_rejected++; +		return; +	} + +	fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred); +	bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; +	bport->port_topo.pn2n.reply_oxid = fchs->ox_id; + +	/* +	 * Send a Flogi Acc +	 */ +	bfa_fcs_fabric_send_flogi_acc(fabric); +	bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); +} + +static void +bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) +{ +	struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg; +	struct bfa_fcs_port_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n; +	struct bfa_s   *bfa = fabric->fcs->bfa; +	struct bfa_fcxp_s *fcxp; +	u16        reqlen; +	struct fchs_s          fchs; + +	fcxp = bfa_fcs_fcxp_alloc(fabric->fcs); +	/** +	 * Do not expect this failure -- expect remote node to retry +	 */ +	if (!fcxp) +		return; + +	reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +				    bfa_os_hton3b(FC_FABRIC_PORT), +				    n2n_port->reply_oxid, pcfg->pwwn, +				    pcfg->nwwn, bfa_pport_get_maxfrsize(bfa), +				    bfa_pport_get_rx_bbcredit(bfa)); + +	bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps), +			BFA_FALSE, FC_CLASS_3, reqlen, &fchs, +			bfa_fcs_fabric_flogiacc_comp, fabric, +			FC_MAX_PDUSZ, 0); /* Timeout 0 indicates no +					   * response expected +					   */ +} + +/** + *   Flogi Acc completion callback. + */ +static void +bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			     bfa_status_t status, u32 rsp_len, +			     u32 resid_len, struct fchs_s *rspfchs) +{ +	struct bfa_fcs_fabric_s *fabric = cbarg; + +	bfa_trc(fabric->fcs, status); +} + +/* + * + * @param[in] fabric - fabric + * @param[in] result - 1 + * + * @return - none + */ +void +bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, enum auth_status status) +{ +	bfa_trc(fabric->fcs, status); + +	if (status == FC_AUTH_STATE_SUCCESS) +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_SUCCESS); +	else +		bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_FAILED); +} + +/** + * Send AEN notification + */ +static void +bfa_fcs_fabric_aen_post(struct bfa_fcs_port_s *port, +			enum bfa_port_aen_event event) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = port->fcs->logm; +	wwn_t           pwwn = bfa_fcs_port_get_pwwn(port); +	wwn_t           fwwn = bfa_fcs_port_get_fabric_name(port); +	char            pwwn_ptr[BFA_STRING_32]; +	char            fwwn_ptr[BFA_STRING_32]; + +	wwn2str(pwwn_ptr, pwwn); +	wwn2str(fwwn_ptr, fwwn); + +	switch (event) { +	case BFA_PORT_AEN_FABRIC_NAME_CHANGE: +		bfa_log(logmod, BFA_AEN_PORT_FABRIC_NAME_CHANGE, pwwn_ptr, +			fwwn_ptr); +		break; +	default: +		break; +	} + +	aen_data.port.pwwn = pwwn; +	aen_data.port.fwwn = fwwn; +} + +/* + * + * @param[in] fabric - fabric + * @param[in] wwn_t - new fabric name + * + * @return - none + */ +void +bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, +			       wwn_t fabric_name) +{ +	bfa_trc(fabric->fcs, fabric_name); + +	if (fabric->fabric_name == 0) { +		/* +		 * With BRCD switches, we don't get Fabric Name in FLOGI. +		 * Don't generate a fabric name change event in this case. +		 */ +		fabric->fabric_name = fabric_name; +	} else { +		fabric->fabric_name = fabric_name; +		/* +		 * Generate a Event +		 */ +		bfa_fcs_fabric_aen_post(&fabric->bport, +					BFA_PORT_AEN_FABRIC_NAME_CHANGE); +	} + +} + +/** + * Not used by FCS. + */ +void +bfa_cb_lps_flogo_comp(void *bfad, void *uarg) +{ +} + + diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/fcbuild.c new file mode 100644 index 00000000000..d174706b9ca --- /dev/null +++ b/drivers/scsi/bfa/fcbuild.c @@ -0,0 +1,1449 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +/* + * fcbuild.c - FC link service frame building and parsing routines + */ + +#include <bfa_os_inc.h> +#include "fcbuild.h" + +/* + * static build functions + */ +static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id); +static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id); +static struct fchs_s   fc_els_req_tmpl; +static struct fchs_s   fc_els_rsp_tmpl; +static struct fchs_s   fc_bls_req_tmpl; +static struct fchs_s   fc_bls_rsp_tmpl; +static struct fc_ba_acc_s ba_acc_tmpl; +static struct fc_logi_s plogi_tmpl; +static struct fc_prli_s prli_tmpl; +static struct fc_rrq_s rrq_tmpl; +static struct fchs_s   fcp_fchs_tmpl; + +void +fcbuild_init(void) +{ +	/* +	 * fc_els_req_tmpl +	 */ +	fc_els_req_tmpl.routing = FC_RTG_EXT_LINK; +	fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST; +	fc_els_req_tmpl.type = FC_TYPE_ELS; +	fc_els_req_tmpl.f_ctl = +		bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ | +			      FCTL_SI_XFER); +	fc_els_req_tmpl.rx_id = FC_RXID_ANY; + +	/* +	 * fc_els_rsp_tmpl +	 */ +	fc_els_rsp_tmpl.routing = FC_RTG_EXT_LINK; +	fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY; +	fc_els_rsp_tmpl.type = FC_TYPE_ELS; +	fc_els_rsp_tmpl.f_ctl = +		bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | +			      FCTL_END_SEQ | FCTL_SI_XFER); +	fc_els_rsp_tmpl.rx_id = FC_RXID_ANY; + +	/* +	 * fc_bls_req_tmpl +	 */ +	fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK; +	fc_bls_req_tmpl.type = FC_TYPE_BLS; +	fc_bls_req_tmpl.f_ctl = bfa_os_hton3b(FCTL_END_SEQ | FCTL_SI_XFER); +	fc_bls_req_tmpl.rx_id = FC_RXID_ANY; + +	/* +	 * fc_bls_rsp_tmpl +	 */ +	fc_bls_rsp_tmpl.routing = FC_RTG_BASIC_LINK; +	fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC; +	fc_bls_rsp_tmpl.type = FC_TYPE_BLS; +	fc_bls_rsp_tmpl.f_ctl = +		bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | +			      FCTL_END_SEQ | FCTL_SI_XFER); +	fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY; + +	/* +	 * ba_acc_tmpl +	 */ +	ba_acc_tmpl.seq_id_valid = 0; +	ba_acc_tmpl.low_seq_cnt = 0; +	ba_acc_tmpl.high_seq_cnt = 0xFFFF; + +	/* +	 * plogi_tmpl +	 */ +	plogi_tmpl.csp.verhi = FC_PH_VER_PH_3; +	plogi_tmpl.csp.verlo = FC_PH_VER_4_3; +	plogi_tmpl.csp.bbcred = bfa_os_htons(0x0004); +	plogi_tmpl.csp.ciro = 0x1; +	plogi_tmpl.csp.cisc = 0x0; +	plogi_tmpl.csp.altbbcred = 0x0; +	plogi_tmpl.csp.conseq = bfa_os_htons(0x00FF); +	plogi_tmpl.csp.ro_bitmap = bfa_os_htons(0x0002); +	plogi_tmpl.csp.e_d_tov = bfa_os_htonl(2000); + +	plogi_tmpl.class3.class_valid = 1; +	plogi_tmpl.class3.sequential = 1; +	plogi_tmpl.class3.conseq = 0xFF; +	plogi_tmpl.class3.ospx = 1; + +	/* +	 * prli_tmpl +	 */ +	prli_tmpl.command = FC_ELS_PRLI; +	prli_tmpl.pglen = 0x10; +	prli_tmpl.pagebytes = bfa_os_htons(0x0014); +	prli_tmpl.parampage.type = FC_TYPE_FCP; +	prli_tmpl.parampage.imagepair = 1; +	prli_tmpl.parampage.servparams.rxrdisab = 1; + +	/* +	 * rrq_tmpl +	 */ +	rrq_tmpl.els_cmd.els_code = FC_ELS_RRQ; + +	/* +	 * fcp_fchs_tmpl +	 */ +	fcp_fchs_tmpl.routing = FC_RTG_FC4_DEV_DATA; +	fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD; +	fcp_fchs_tmpl.type = FC_TYPE_FCP; +	fcp_fchs_tmpl.f_ctl = +		bfa_os_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER); +	fcp_fchs_tmpl.seq_id = 1; +	fcp_fchs_tmpl.rx_id = FC_RXID_ANY; +} + +static void +fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u32 ox_id) +{ +	bfa_os_memset(fchs, 0, sizeof(struct fchs_s)); + +	fchs->routing = FC_RTG_FC4_DEV_DATA; +	fchs->cat_info = FC_CAT_UNSOLICIT_CTRL; +	fchs->type = FC_TYPE_SERVICES; +	fchs->f_ctl = +		bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ | +			      FCTL_SI_XFER); +	fchs->rx_id = FC_RXID_ANY; +	fchs->d_id = (d_id); +	fchs->s_id = (s_id); +	fchs->ox_id = bfa_os_htons(ox_id); + +	/** +	 * @todo no need to set ox_id for request +	 *       no need to set rx_id for response +	 */ +} + +void +fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id) +{ +	bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s)); +	fchs->d_id = (d_id); +	fchs->s_id = (s_id); +	fchs->ox_id = bfa_os_htons(ox_id); +} + +static void +fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id) +{ +	bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s)); +	fchs->d_id = d_id; +	fchs->s_id = s_id; +	fchs->ox_id = ox_id; +} + +enum fc_parse_status +fc_els_rsp_parse(struct fchs_s *fchs, int len) +{ +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); +	struct fc_ls_rjt_s    *ls_rjt = (struct fc_ls_rjt_s *) els_cmd; + +	len = len; + +	switch (els_cmd->els_code) { +	case FC_ELS_LS_RJT: +		if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) +			return (FC_PARSE_BUSY); +		else +			return (FC_PARSE_FAILURE); + +	case FC_ELS_ACC: +		return (FC_PARSE_OK); +	} +	return (FC_PARSE_OK); +} + +static void +fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id) +{ +	bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s)); +	fchs->d_id = d_id; +	fchs->s_id = s_id; +	fchs->ox_id = ox_id; +} + +static          u16 +fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +		 u16 ox_id, wwn_t port_name, wwn_t node_name, +		 u16 pdu_size, u8 els_code) +{ +	struct fc_logi_s     *plogi = (struct fc_logi_s *) (pld); + +	bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s)); + +	plogi->els_cmd.els_code = els_code; +	if (els_code == FC_ELS_PLOGI) +		fc_els_req_build(fchs, d_id, s_id, ox_id); +	else +		fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	plogi->csp.rxsz = plogi->class3.rxsz = bfa_os_htons(pdu_size); + +	bfa_os_memcpy(&plogi->port_name, &port_name, sizeof(wwn_t)); +	bfa_os_memcpy(&plogi->node_name, &node_name, sizeof(wwn_t)); + +	return (sizeof(struct fc_logi_s)); +} + +u16 +fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, +		u16 ox_id, wwn_t port_name, wwn_t node_name, +		u16 pdu_size, u8 set_npiv, u8 set_auth, +		u16 local_bb_credits) +{ +	u32        d_id = bfa_os_hton3b(FC_FABRIC_PORT); +	u32 	*vvl_info; + +	bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); + +	flogi->els_cmd.els_code = FC_ELS_FLOGI; +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size); +	flogi->port_name = port_name; +	flogi->node_name = node_name; + +	/* +	 * Set the NPIV Capability Bit ( word 1, bit 31) of Common +	 * Service Parameters. +	 */ +	flogi->csp.ciro = set_npiv; + +	/* set AUTH capability */ +	flogi->csp.security = set_auth; + +	flogi->csp.bbcred = bfa_os_htons(local_bb_credits); + +	/* Set brcd token in VVL */ +	vvl_info = (u32 *)&flogi->vvl[0]; + +	/* set the flag to indicate the presence of VVL */ +	flogi->csp.npiv_supp    = 1; /* @todo. field name is not correct */ +	vvl_info[0]	= bfa_os_htonl(FLOGI_VVL_BRCD); + +	return (sizeof(struct fc_logi_s)); +} + +u16 +fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, +		   u16 ox_id, wwn_t port_name, wwn_t node_name, +		   u16 pdu_size, u16 local_bb_credits) +{ +	u32        d_id = 0; + +	bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	flogi->els_cmd.els_code = FC_ELS_ACC; +	flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size); +	flogi->port_name = port_name; +	flogi->node_name = node_name; + +	flogi->csp.bbcred = bfa_os_htons(local_bb_credits); + +	return (sizeof(struct fc_logi_s)); +} + +u16 +fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, +		u16 ox_id, wwn_t port_name, wwn_t node_name, +		u16 pdu_size) +{ +	u32        d_id = bfa_os_hton3b(FC_FABRIC_PORT); + +	bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); + +	flogi->els_cmd.els_code = FC_ELS_FDISC; +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size); +	flogi->port_name = port_name; +	flogi->node_name = node_name; + +	return (sizeof(struct fc_logi_s)); +} + +u16 +fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +	       u16 ox_id, wwn_t port_name, wwn_t node_name, +	       u16 pdu_size) +{ +	return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, +				node_name, pdu_size, FC_ELS_PLOGI); +} + +u16 +fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +		   u16 ox_id, wwn_t port_name, wwn_t node_name, +		   u16 pdu_size) +{ +	return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, +				node_name, pdu_size, FC_ELS_ACC); +} + +enum fc_parse_status +fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) +{ +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); +	struct fc_logi_s     *plogi; +	struct fc_ls_rjt_s    *ls_rjt; + +	switch (els_cmd->els_code) { +	case FC_ELS_LS_RJT: +		ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1); +		if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) +			return (FC_PARSE_BUSY); +		else +			return (FC_PARSE_FAILURE); +	case FC_ELS_ACC: +		plogi = (struct fc_logi_s *) (fchs + 1); +		if (len < sizeof(struct fc_logi_s)) +			return (FC_PARSE_FAILURE); + +		if (!wwn_is_equal(plogi->port_name, port_name)) +			return (FC_PARSE_FAILURE); + +		if (!plogi->class3.class_valid) +			return (FC_PARSE_FAILURE); + +		if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ)) +			return (FC_PARSE_FAILURE); + +		return (FC_PARSE_OK); +	default: +		return (FC_PARSE_FAILURE); +	} +} + +enum fc_parse_status +fc_plogi_parse(struct fchs_s *fchs) +{ +	struct fc_logi_s     *plogi = (struct fc_logi_s *) (fchs + 1); + +	if (plogi->class3.class_valid != 1) +		return FC_PARSE_FAILURE; + +	if ((bfa_os_ntohs(plogi->class3.rxsz) < FC_MIN_PDUSZ) +	    || (bfa_os_ntohs(plogi->class3.rxsz) > FC_MAX_PDUSZ) +	    || (plogi->class3.rxsz == 0)) +		return (FC_PARSE_FAILURE); + +	return FC_PARSE_OK; +} + +u16 +fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +	      u16 ox_id) +{ +	struct fc_prli_s      *prli = (struct fc_prli_s *) (pld); + +	fc_els_req_build(fchs, d_id, s_id, ox_id); +	bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); + +	prli->command = FC_ELS_PRLI; +	prli->parampage.servparams.initiator     = 1; +	prli->parampage.servparams.retry         = 1; +	prli->parampage.servparams.rec_support   = 1; +	prli->parampage.servparams.task_retry_id = 0; +	prli->parampage.servparams.confirm       = 1; + +	return (sizeof(struct fc_prli_s)); +} + +u16 +fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +		  u16 ox_id, enum bfa_port_role role) +{ +	struct fc_prli_s      *prli = (struct fc_prli_s *) (pld); + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); +	bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); + +	prli->command = FC_ELS_ACC; + +	if ((role & BFA_PORT_ROLE_FCP_TM) == BFA_PORT_ROLE_FCP_TM) +		prli->parampage.servparams.target = 1; +	else +		prli->parampage.servparams.initiator = 1; + +	prli->parampage.rspcode = FC_PRLI_ACC_XQTD; + +	return (sizeof(struct fc_prli_s)); +} + +enum fc_parse_status +fc_prli_rsp_parse(struct fc_prli_s *prli, int len) +{ +	if (len < sizeof(struct fc_prli_s)) +		return (FC_PARSE_FAILURE); + +	if (prli->command != FC_ELS_ACC) +		return (FC_PARSE_FAILURE); + +	if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD) +	    && (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG)) +		return (FC_PARSE_FAILURE); + +	if (prli->parampage.servparams.target != 1) +		return (FC_PARSE_FAILURE); + +	return (FC_PARSE_OK); +} + +enum fc_parse_status +fc_prli_parse(struct fc_prli_s *prli) +{ +	if (prli->parampage.type != FC_TYPE_FCP) +		return (FC_PARSE_FAILURE); + +	if (!prli->parampage.imagepair) +		return (FC_PARSE_FAILURE); + +	if (!prli->parampage.servparams.initiator) +		return (FC_PARSE_FAILURE); + +	return (FC_PARSE_OK); +} + +u16 +fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, +			u32 s_id, u16 ox_id, wwn_t port_name) +{ +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	memset(logo, '\0', sizeof(struct fc_logo_s)); +	logo->els_cmd.els_code = FC_ELS_LOGO; +	logo->nport_id = (s_id); +	logo->orig_port_name = port_name; + +	return (sizeof(struct fc_logo_s)); +} + +static          u16 +fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, +		 u32 s_id, u16 ox_id, wwn_t port_name, +		 wwn_t node_name, u8 els_code) +{ +	memset(adisc, '\0', sizeof(struct fc_adisc_s)); + +	adisc->els_cmd.els_code = els_code; + +	if (els_code == FC_ELS_ADISC) +		fc_els_req_build(fchs, d_id, s_id, ox_id); +	else +		fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	adisc->orig_HA = 0; +	adisc->orig_port_name = port_name; +	adisc->orig_node_name = node_name; +	adisc->nport_id = (s_id); + +	return (sizeof(struct fc_adisc_s)); +} + +u16 +fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, +		u32 s_id, u16 ox_id, wwn_t port_name, +		wwn_t node_name) +{ +	return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name, +				node_name, FC_ELS_ADISC); +} + +u16 +fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, +		   u32 s_id, u16 ox_id, wwn_t port_name, +		   wwn_t node_name) +{ +	return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name, +				node_name, FC_ELS_ACC); +} + +enum fc_parse_status +fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name, +				 wwn_t node_name) +{ + +	if (len < sizeof(struct fc_adisc_s)) +		return (FC_PARSE_FAILURE); + +	if (adisc->els_cmd.els_code != FC_ELS_ACC) +		return (FC_PARSE_FAILURE); + +	if (!wwn_is_equal(adisc->orig_port_name, port_name)) +		return (FC_PARSE_FAILURE); + +	return (FC_PARSE_OK); +} + +enum fc_parse_status +fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, +		 wwn_t node_name, wwn_t port_name) +{ +	struct fc_adisc_s     *adisc = (struct fc_adisc_s *) pld; + +	if (adisc->els_cmd.els_code != FC_ELS_ACC) +		return (FC_PARSE_FAILURE); + +	if ((adisc->nport_id == (host_dap)) +	    && wwn_is_equal(adisc->orig_port_name, port_name) +	    && wwn_is_equal(adisc->orig_node_name, node_name)) +		return (FC_PARSE_OK); + +	return (FC_PARSE_FAILURE); +} + +enum fc_parse_status +fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name) +{ +	struct fc_logi_s     *pdisc = (struct fc_logi_s *) (fchs + 1); + +	if (pdisc->class3.class_valid != 1) +		return FC_PARSE_FAILURE; + +	if ((bfa_os_ntohs(pdisc->class3.rxsz) < +		 (FC_MIN_PDUSZ - sizeof(struct fchs_s))) +	    || (pdisc->class3.rxsz == 0)) +		return (FC_PARSE_FAILURE); + +	if (!wwn_is_equal(pdisc->port_name, port_name)) +		return (FC_PARSE_FAILURE); + +	if (!wwn_is_equal(pdisc->node_name, node_name)) +		return (FC_PARSE_FAILURE); + +	return FC_PARSE_OK; +} + +u16 +fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) +{ +	bfa_os_memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s)); +	fchs->cat_info = FC_CAT_ABTS; +	fchs->d_id = (d_id); +	fchs->s_id = (s_id); +	fchs->ox_id = bfa_os_htons(ox_id); + +	return (sizeof(struct fchs_s)); +} + +enum fc_parse_status +fc_abts_rsp_parse(struct fchs_s *fchs, int len) +{ +	if ((fchs->cat_info == FC_CAT_BA_ACC) +	    || (fchs->cat_info == FC_CAT_BA_RJT)) +		return (FC_PARSE_OK); + +	return (FC_PARSE_FAILURE); +} + +u16 +fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, +			 u32 s_id, u16 ox_id, u16 rrq_oxid) +{ +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	/* +	 * build rrq payload +	 */ +	bfa_os_memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s)); +	rrq->s_id = (s_id); +	rrq->ox_id = bfa_os_htons(rrq_oxid); +	rrq->rx_id = FC_RXID_ANY; + +	return (sizeof(struct fc_rrq_s)); +} + +u16 +fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, +		  u16 ox_id) +{ +	struct fc_els_cmd_s   *acc = pld; + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	memset(acc, 0, sizeof(struct fc_els_cmd_s)); +	acc->els_code = FC_ELS_ACC; + +	return (sizeof(struct fc_els_cmd_s)); +} + +u16 +fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id, +		u32 s_id, u16 ox_id, u8 reason_code, +		u8 reason_code_expl) +{ +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); +	memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s)); + +	ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT; +	ls_rjt->reason_code = reason_code; +	ls_rjt->reason_code_expl = reason_code_expl; +	ls_rjt->vendor_unique = 0x00; + +	return (sizeof(struct fc_ls_rjt_s)); +} + +u16 +fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, +		u32 s_id, u16 ox_id, u16 rx_id) +{ +	fc_bls_rsp_build(fchs, d_id, s_id, ox_id); + +	bfa_os_memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s)); + +	fchs->rx_id = rx_id; + +	ba_acc->ox_id = fchs->ox_id; +	ba_acc->rx_id = fchs->rx_id; + +	return (sizeof(struct fc_ba_acc_s)); +} + +u16 +fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, +			u32 d_id, u32 s_id, u16 ox_id) +{ +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); +	memset(els_cmd, 0, sizeof(struct fc_els_cmd_s)); +	els_cmd->els_code = FC_ELS_ACC; + +	return (sizeof(struct fc_els_cmd_s)); +} + +int +fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code) +{ +	int             num_pages = 0; +	struct fc_prlo_s      *prlo; +	struct fc_tprlo_s     *tprlo; + +	if (els_code == FC_ELS_PRLO) { +		prlo = (struct fc_prlo_s *) (fc_frame + 1); +		num_pages = (bfa_os_ntohs(prlo->payload_len) - 4) / 16; +	} else { +		tprlo = (struct fc_tprlo_s *) (fc_frame + 1); +		num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16; +	} +	return num_pages; +} + +u16 +fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			int num_pages) +{ +	int             page; + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	memset(tprlo_acc, 0, (num_pages * 16) + 4); +	tprlo_acc->command = FC_ELS_ACC; + +	tprlo_acc->page_len = 0x10; +	tprlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4); + +	for (page = 0; page < num_pages; page++) { +		tprlo_acc->tprlo_acc_params[page].opa_valid = 0; +		tprlo_acc->tprlo_acc_params[page].rpa_valid = 0; +		tprlo_acc->tprlo_acc_params[page].fc4type_csp = FC_TYPE_FCP; +		tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0; +		tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0; +	} +	return (bfa_os_ntohs(tprlo_acc->payload_len)); +} + +u16 +fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			int num_pages) +{ +	int             page; + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	memset(prlo_acc, 0, (num_pages * 16) + 4); +	prlo_acc->command = FC_ELS_ACC; +	prlo_acc->page_len = 0x10; +	prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4); + +	for (page = 0; page < num_pages; page++) { +		prlo_acc->prlo_acc_params[page].opa_valid = 0; +		prlo_acc->prlo_acc_params[page].rpa_valid = 0; +		prlo_acc->prlo_acc_params[page].fc4type_csp = FC_TYPE_FCP; +		prlo_acc->prlo_acc_params[page].orig_process_assc = 0; +		prlo_acc->prlo_acc_params[page].resp_process_assc = 0; +	} + +	return (bfa_os_ntohs(prlo_acc->payload_len)); +} + +u16 +fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id, +			u32 s_id, u16 ox_id, u32 data_format) +{ +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	memset(rnid, 0, sizeof(struct fc_rnid_cmd_s)); + +	rnid->els_cmd.els_code = FC_ELS_RNID; +	rnid->node_id_data_format = data_format; + +	return (sizeof(struct fc_rnid_cmd_s)); +} + +u16 +fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			u32 data_format, +			struct fc_rnid_common_id_data_s *common_id_data, +			struct fc_rnid_general_topology_data_s *gen_topo_data) +{ +	memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s)); + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	rnid_acc->els_cmd.els_code = FC_ELS_ACC; +	rnid_acc->node_id_data_format = data_format; +	rnid_acc->common_id_data_length = +			sizeof(struct fc_rnid_common_id_data_s); +	rnid_acc->common_id_data = *common_id_data; + +	if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { +		rnid_acc->specific_id_data_length = +			sizeof(struct fc_rnid_general_topology_data_s); +		bfa_os_assign(rnid_acc->gen_topology_data, *gen_topo_data); +		return (sizeof(struct fc_rnid_acc_s)); +	} else { +		return (sizeof(struct fc_rnid_acc_s) - +			sizeof(struct fc_rnid_general_topology_data_s)); +	} + +} + +u16 +fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id, +			u32 s_id, u16 ox_id) +{ +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s)); + +	rpsc->els_cmd.els_code = FC_ELS_RPSC; +	return (sizeof(struct fc_rpsc_cmd_s)); +} + +u16 +fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, +			u32 d_id, u32 s_id, u32 *pid_list, +			u16 npids) +{ +	u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id)); +	int i = 0; + +	fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0); + +	memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s)); + +	rpsc2->els_cmd.els_code = FC_ELS_RPSC; +	rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN); +	rpsc2->num_pids  = bfa_os_htons(npids); +	for (i = 0; i < npids; i++) +		rpsc2->pid_list[i].pid = pid_list[i]; + +	return (sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) * +			(sizeof(u32)))); +} + +u16 +fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			struct fc_rpsc_speed_info_s *oper_speed) +{ +	memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s)); + +	fc_els_rsp_build(fchs, d_id, s_id, ox_id); + +	rpsc_acc->command = FC_ELS_ACC; +	rpsc_acc->num_entries = bfa_os_htons(1); + +	rpsc_acc->speed_info[0].port_speed_cap = +		bfa_os_htons(oper_speed->port_speed_cap); + +	rpsc_acc->speed_info[0].port_op_speed = +		bfa_os_htons(oper_speed->port_op_speed); + +	return (sizeof(struct fc_rpsc_acc_s)); + +} + +/* + * TBD - + * . get rid of unnecessary memsets + */ + +u16 +fc_logo_rsp_parse(struct fchs_s *fchs, int len) +{ +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	len = len; +	if (els_cmd->els_code != FC_ELS_ACC) +		return FC_PARSE_FAILURE; + +	return FC_PARSE_OK; +} + +u16 +fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, wwn_t port_name, wwn_t node_name, +			u16 pdu_size) +{ +	struct fc_logi_s     *pdisc = (struct fc_logi_s *) (fchs + 1); + +	bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s)); + +	pdisc->els_cmd.els_code = FC_ELS_PDISC; +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	pdisc->csp.rxsz = pdisc->class3.rxsz = bfa_os_htons(pdu_size); +	pdisc->port_name = port_name; +	pdisc->node_name = node_name; + +	return (sizeof(struct fc_logi_s)); +} + +u16 +fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) +{ +	struct fc_logi_s     *pdisc = (struct fc_logi_s *) (fchs + 1); + +	if (len < sizeof(struct fc_logi_s)) +		return (FC_PARSE_LEN_INVAL); + +	if (pdisc->els_cmd.els_code != FC_ELS_ACC) +		return (FC_PARSE_ACC_INVAL); + +	if (!wwn_is_equal(pdisc->port_name, port_name)) +		return (FC_PARSE_PWWN_NOT_EQUAL); + +	if (!pdisc->class3.class_valid) +		return (FC_PARSE_NWWN_NOT_EQUAL); + +	if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ)) +		return (FC_PARSE_RXSZ_INVAL); + +	return (FC_PARSE_OK); +} + +u16 +fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, +	      int num_pages) +{ +	struct fc_prlo_s      *prlo = (struct fc_prlo_s *) (fchs + 1); +	int             page; + +	fc_els_req_build(fchs, d_id, s_id, ox_id); +	memset(prlo, 0, (num_pages * 16) + 4); +	prlo->command = FC_ELS_PRLO; +	prlo->page_len = 0x10; +	prlo->payload_len = bfa_os_htons((num_pages * 16) + 4); + +	for (page = 0; page < num_pages; page++) { +		prlo->prlo_params[page].type = FC_TYPE_FCP; +		prlo->prlo_params[page].opa_valid = 0; +		prlo->prlo_params[page].rpa_valid = 0; +		prlo->prlo_params[page].orig_process_assc = 0; +		prlo->prlo_params[page].resp_process_assc = 0; +	} + +	return (bfa_os_ntohs(prlo->payload_len)); +} + +u16 +fc_prlo_rsp_parse(struct fchs_s *fchs, int len) +{ +	struct fc_prlo_acc_s  *prlo = (struct fc_prlo_acc_s *) (fchs + 1); +	int             num_pages = 0; +	int             page = 0; + +	len = len; + +	if (prlo->command != FC_ELS_ACC) +		return (FC_PARSE_FAILURE); + +	num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16; + +	for (page = 0; page < num_pages; page++) { +		if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP) +			return FC_PARSE_FAILURE; + +		if (prlo->prlo_acc_params[page].opa_valid != 0) +			return FC_PARSE_FAILURE; + +		if (prlo->prlo_acc_params[page].rpa_valid != 0) +			return FC_PARSE_FAILURE; + +		if (prlo->prlo_acc_params[page].orig_process_assc != 0) +			return FC_PARSE_FAILURE; + +		if (prlo->prlo_acc_params[page].resp_process_assc != 0) +			return FC_PARSE_FAILURE; +	} +	return (FC_PARSE_OK); + +} + +u16 +fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, int num_pages, +			enum fc_tprlo_type tprlo_type, u32 tpr_id) +{ +	struct fc_tprlo_s     *tprlo = (struct fc_tprlo_s *) (fchs + 1); +	int             page; + +	fc_els_req_build(fchs, d_id, s_id, ox_id); +	memset(tprlo, 0, (num_pages * 16) + 4); +	tprlo->command = FC_ELS_TPRLO; +	tprlo->page_len = 0x10; +	tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4); + +	for (page = 0; page < num_pages; page++) { +		tprlo->tprlo_params[page].type = FC_TYPE_FCP; +		tprlo->tprlo_params[page].opa_valid = 0; +		tprlo->tprlo_params[page].rpa_valid = 0; +		tprlo->tprlo_params[page].orig_process_assc = 0; +		tprlo->tprlo_params[page].resp_process_assc = 0; +		if (tprlo_type == FC_GLOBAL_LOGO) { +			tprlo->tprlo_params[page].global_process_logout = 1; +		} else if (tprlo_type == FC_TPR_LOGO) { +			tprlo->tprlo_params[page].tpo_nport_valid = 1; +			tprlo->tprlo_params[page].tpo_nport_id = (tpr_id); +		} +	} + +	return (bfa_os_ntohs(tprlo->payload_len)); +} + +u16 +fc_tprlo_rsp_parse(struct fchs_s *fchs, int len) +{ +	struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1); +	int             num_pages = 0; +	int             page = 0; + +	len = len; + +	if (tprlo->command != FC_ELS_ACC) +		return (FC_PARSE_ACC_INVAL); + +	num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16; + +	for (page = 0; page < num_pages; page++) { +		if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP) +			return (FC_PARSE_NOT_FCP); +		if (tprlo->tprlo_acc_params[page].opa_valid != 0) +			return (FC_PARSE_OPAFLAG_INVAL); +		if (tprlo->tprlo_acc_params[page].rpa_valid != 0) +			return (FC_PARSE_RPAFLAG_INVAL); +		if (tprlo->tprlo_acc_params[page].orig_process_assc != 0) +			return (FC_PARSE_OPA_INVAL); +		if (tprlo->tprlo_acc_params[page].resp_process_assc != 0) +			return (FC_PARSE_RPA_INVAL); +	} +	return (FC_PARSE_OK); +} + +enum fc_parse_status +fc_rrq_rsp_parse(struct fchs_s *fchs, int len) +{ +	struct fc_els_cmd_s   *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	len = len; +	if (els_cmd->els_code != FC_ELS_ACC) +		return FC_PARSE_FAILURE; + +	return FC_PARSE_OK; +} + +u16 +fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, u32 reason_code, +			u32 reason_expl) +{ +	struct fc_ba_rjt_s    *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1); + +	fc_bls_rsp_build(fchs, d_id, s_id, ox_id); + +	fchs->cat_info = FC_CAT_BA_RJT; +	ba_rjt->reason_code = reason_code; +	ba_rjt->reason_expl = reason_expl; +	return (sizeof(struct fc_ba_rjt_s)); +} + +static void +fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code) +{ +	bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s)); +	cthdr->rev_id = CT_GS3_REVISION; +	cthdr->gs_type = CT_GSTYPE_DIRSERVICE; +	cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER; +	cthdr->cmd_rsp_code = bfa_os_htons(cmd_code); +} + +static void +fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code) +{ +	bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s)); +	cthdr->rev_id = CT_GS3_REVISION; +	cthdr->gs_type = CT_GSTYPE_MGMTSERVICE; +	cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER; +	cthdr->cmd_rsp_code = bfa_os_htons(cmd_code); +} + +static void +fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code, +					 u8 sub_type) +{ +	bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s)); +	cthdr->rev_id = CT_GS3_REVISION; +	cthdr->gs_type = CT_GSTYPE_MGMTSERVICE; +	cthdr->gs_sub_type = sub_type; +	cthdr->cmd_rsp_code = bfa_os_htons(cmd_code); +} + +u16 +fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +	       wwn_t port_name) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_gidpn_req_s *gidpn = +			(struct fcgs_gidpn_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN); + +	bfa_os_memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s)); +	gidpn->port_name = port_name; +	return (sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +	       u32 port_id) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID); + +	bfa_os_memset(gpnid, 0, sizeof(fcgs_gpnid_req_t)); +	gpnid->dap = port_id; +	return (sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +	       u32 port_id) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID); + +	bfa_os_memset(gnnid, 0, sizeof(fcgs_gnnid_req_t)); +	gnnid->dap = port_id; +	return (sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_ct_rsp_parse(struct ct_hdr_s *cthdr) +{ +	if (bfa_os_ntohs(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) { +		if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY) +			return FC_PARSE_BUSY; +		else +			return FC_PARSE_FAILURE; +	} + +	return FC_PARSE_OK; +} + +u16 +fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg, +			u32 s_id, u16 ox_id) +{ +	u32        d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER); + +	fc_els_req_build(fchs, d_id, s_id, ox_id); + +	bfa_os_memset(scr, 0, sizeof(struct fc_scr_s)); +	scr->command = FC_ELS_SCR; +	scr->reg_func = FC_SCR_REG_FUNC_FULL; +	if (set_br_reg) +		scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE; + +	return (sizeof(struct fc_scr_s)); +} + +u16 +fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, +			u16 ox_id) +{ +	u32        d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER); +	u16        payldlen; + +	fc_els_req_build(fchs, d_id, s_id, ox_id); +	rscn->command = FC_ELS_RSCN; +	rscn->pagelen = sizeof(rscn->event[0]); + +	payldlen = sizeof(u32) + rscn->pagelen; +	rscn->payldlen = bfa_os_htons(payldlen); + +	rscn->event[0].format = FC_RSCN_FORMAT_PORTID; +	rscn->event[0].portid = s_id; + +	return (sizeof(struct fc_rscn_pl_s)); +} + +u16 +fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +	       enum bfa_port_role roles) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rftid_req_s *rftid = +			(struct fcgs_rftid_req_s *) (cthdr + 1); +	u32        type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER); +	u8         index; + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID); + +	bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s)); + +	rftid->dap = s_id; + +	/* By default, FCP FC4 Type is registered */ +	index = FC_TYPE_FCP >> 5; +	type_value = 1 << (FC_TYPE_FCP % 32); +	rftid->fc4_type[index] = bfa_os_htonl(type_value); + +	if (roles & BFA_PORT_ROLE_FCP_IPFC) { +		index = FC_TYPE_IP >> 5; +		type_value = 1 << (FC_TYPE_IP % 32); +		rftid->fc4_type[index] |= bfa_os_htonl(type_value); +	} + +	return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 ox_id, u8 *fc4_bitmap, +			u32 bitmap_size) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rftid_req_s *rftid = +			(struct fcgs_rftid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID); + +	bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s)); + +	rftid->dap = s_id; +	bfa_os_memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap, +			(bitmap_size < 32 ? bitmap_size : 32)); + +	return (sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +	       u8 fc4_type, u8 fc4_ftrs) +{ +	struct ct_hdr_s         *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rffid_req_s *rffid = +			(struct fcgs_rffid_req_s *) (cthdr + 1); +	u32         d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID); + +	bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s)); + +	rffid->dap 		 	= s_id; +	rffid->fc4ftr_bits  = fc4_ftrs; +	rffid->fc4_type		= fc4_type; + +	return (sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, +		u8 *name) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rspnid_req_s *rspnid = +			(struct fcgs_rspnid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); +	fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID); + +	bfa_os_memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s)); + +	rspnid->dap = s_id; +	rspnid->spn_len = (u8) strlen((char *)name); +	strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len); + +	return (sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u8 fc4_type) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_gidft_req_s *gidft = +			(struct fcgs_gidft_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); + +	fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT); + +	bfa_os_memset(gidft, 0, sizeof(struct fcgs_gidft_req_s)); +	gidft->fc4_type = fc4_type; +	gidft->domain_id = 0; +	gidft->area_id = 0; + +	return (sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, +	       wwn_t port_name) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rpnid_req_s *rpnid = +			(struct fcgs_rpnid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID); + +	bfa_os_memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s)); +	rpnid->port_id = port_id; +	rpnid->port_name = port_name; + +	return (sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, +	       wwn_t node_name) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rnnid_req_s *rnnid = +			(struct fcgs_rnnid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID); + +	bfa_os_memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s)); +	rnnid->port_id = port_id; +	rnnid->node_name = node_name; + +	return (sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, +	       u32 cos) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rcsid_req_s *rcsid = +			(struct fcgs_rcsid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID); + +	bfa_os_memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s)); +	rcsid->port_id = port_id; +	rcsid->cos = cos; + +	return (sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, +	       u8 port_type) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_rptid_req_s *rptid = +			(struct fcgs_rptid_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID); + +	bfa_os_memset(rptid, 0, sizeof(struct fcgs_rptid_req_s)); +	rptid->port_id = port_id; +	rptid->port_type = port_type; + +	return (sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s)); +} + +u16 +fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	struct fcgs_ganxt_req_s *ganxt = +			(struct fcgs_ganxt_req_s *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_NAME_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT); + +	bfa_os_memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s)); +	ganxt->port_id = port_id; + +	return (sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s)); +} + +/* + * Builds fc hdr and ct hdr for FDMI requests. + */ +u16 +fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, +		     u16 cmd_code) +{ + +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	u32        d_id = bfa_os_hton3b(FC_MGMT_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code); + +	return (sizeof(struct ct_hdr_s)); +} + +/* + * Given a FC4 Type, this function returns a fc4 type bitmask + */ +void +fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask) +{ +	u8         index; +	u32       *ptr = (u32 *) bit_mask; +	u32        type_value; + +	/* +	 * @todo : Check for bitmask size +	 */ + +	index = fc4_type >> 5; +	type_value = 1 << (fc4_type % 32); +	ptr[index] = bfa_os_htonl(type_value); + +} + +/* + * GMAL Request + */ +u16 +fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_MGMT_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD, +			CT_GSSUBTYPE_CFGSERVER); + +	bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t)); +	gmal->wwn = wwn; + +	return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t)); +} + +/* + * GFN (Get Fabric Name) Request + */ +u16 +fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) +{ +	struct ct_hdr_s       *cthdr = (struct ct_hdr_s *) pyld; +	fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1); +	u32        d_id = bfa_os_hton3b(FC_MGMT_SERVER); + +	fc_gs_fchdr_build(fchs, d_id, s_id, 0); +	fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD, +			CT_GSSUBTYPE_CFGSERVER); + +	bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t)); +	gfn->wwn = wwn; + +	return (sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t)); +} diff --git a/drivers/scsi/bfa/fcbuild.h b/drivers/scsi/bfa/fcbuild.h new file mode 100644 index 00000000000..4d248424f7b --- /dev/null +++ b/drivers/scsi/bfa/fcbuild.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +/* + * fcbuild.h - FC link service frame building and parsing routines + */ + +#ifndef __FCBUILD_H__ +#define __FCBUILD_H__ + +#include <bfa_os_inc.h> +#include <protocol/fc.h> +#include <protocol/fcp.h> +#include <protocol/ct.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_pport.h> + +/* + * Utility Macros/functions + */ + +#define fcif_sof_set(_ifhdr, _sof)	(_ifhdr)->sof = FC_ ## _sof +#define fcif_eof_set(_ifhdr, _eof)	(_ifhdr)->eof = FC_ ## _eof + +#define wwn_is_equal(_wwn1, _wwn2)		\ +	(memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0) + +#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) + +/* + * Given the fc response length, this routine will return + * the length of the actual payload bytes following the CT header. + * + * Assumes the input response length does not include the crc, eof, etc. + */ +static inline   u32 +fc_get_ctresp_pyld_len(u32 resp_len) +{ +	return (resp_len - sizeof(struct ct_hdr_s)); +} + +/* + * Convert bfa speed to rpsc speed value. + */ +static inline enum bfa_pport_speed +fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed_s speed) +{ +	switch (speed) { + +	case RPSC_OP_SPEED_1G: +		return BFA_PPORT_SPEED_1GBPS; + +	case RPSC_OP_SPEED_2G: +		return BFA_PPORT_SPEED_2GBPS; + +	case RPSC_OP_SPEED_4G: +		return BFA_PPORT_SPEED_4GBPS; + +	case RPSC_OP_SPEED_8G: +		return BFA_PPORT_SPEED_8GBPS; + +	default: +		return BFA_PPORT_SPEED_UNKNOWN; +	} +} + +/* + * Convert RPSC speed to bfa speed value. + */ +static inline   enum fc_rpsc_op_speed_s +fc_bfa_speed_to_rpsc_operspeed(enum bfa_pport_speed op_speed) +{ +	switch (op_speed) { + +	case BFA_PPORT_SPEED_1GBPS: +		return RPSC_OP_SPEED_1G; + +	case BFA_PPORT_SPEED_2GBPS: +		return RPSC_OP_SPEED_2G; + +	case BFA_PPORT_SPEED_4GBPS: +		return RPSC_OP_SPEED_4G; + +	case BFA_PPORT_SPEED_8GBPS: +		return RPSC_OP_SPEED_8G; + +	default: +		return RPSC_OP_SPEED_NOT_EST; +	} +} +enum fc_parse_status { +	FC_PARSE_OK = 0, +	FC_PARSE_FAILURE = 1, +	FC_PARSE_BUSY = 2, +	FC_PARSE_LEN_INVAL, +	FC_PARSE_ACC_INVAL, +	FC_PARSE_PWWN_NOT_EQUAL, +	FC_PARSE_NWWN_NOT_EQUAL, +	FC_PARSE_RXSZ_INVAL, +	FC_PARSE_NOT_FCP, +	FC_PARSE_OPAFLAG_INVAL, +	FC_PARSE_RPAFLAG_INVAL, +	FC_PARSE_OPA_INVAL, +	FC_PARSE_RPA_INVAL, + +}; + +struct fc_templates_s { +	struct fchs_s          fc_els_req; +	struct fchs_s          fc_bls_req; +	struct fc_logi_s      plogi; +	struct fc_rrq_s        rrq; +}; + +void fcbuild_init(void); + +u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, +			u32 s_id, u16 ox_id, wwn_t port_name, +			wwn_t node_name, u16 pdu_size, u8 set_npiv, +			u8 set_auth, u16 local_bb_credits); +u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, +			u32 s_id, u16 ox_id, wwn_t port_name, +			wwn_t node_name, u16 pdu_size); +u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, +			u32 s_id, u16 ox_id, wwn_t port_name, +			wwn_t node_name, u16 pdu_size, +			u16 local_bb_credits); +u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, +			u32 s_id, u16 ox_id, wwn_t port_name, +			wwn_t node_name, u16 pdu_size); +enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); +u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id, +			u16 ox_id); +enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); +u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, +			u32 s_id, u16 ox_id, u16 rrq_oxid); +enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len); +u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, +			u16 ox_id, u8 *name); +u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id, +			u16 ox_id, enum bfa_port_role role); +u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 ox_id, u8 *fc4_bitmap, +			u32 bitmap_size); +u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 ox_id, u8 fc4_type, u8 fc4_ftrs); +u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 ox_id, wwn_t port_name); +u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, +			u16 ox_id, u32 port_id); +u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, +			u8 set_br_reg, u32 s_id, u16 ox_id); +u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, +			u32 s_id, u16 ox_id, +			wwn_t port_name, wwn_t node_name, u16 pdu_size); + +u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, +			u32 d_id, u32 s_id, u16 ox_id, +			wwn_t port_name, wwn_t node_name); +enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld, +			u32 host_dap, +			wwn_t node_name, wwn_t port_name); +enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, +			wwn_t port_name, wwn_t node_name); +u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, +			u32 d_id, u32 s_id, u16 ox_id, +			wwn_t port_name, wwn_t node_name); +u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, +			u32 d_id, u32 s_id, u16 ox_id, +			u8 reason_code, u8 reason_code_expl); +u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, +			u32 d_id, u32 s_id, u16 ox_id); +u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, +			u32 s_id, u16 ox_id); +enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len); + +u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, +			u32 s_id, u16 ox_id, +			enum bfa_port_role role); +u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, +			u32 d_id, u32 s_id, u16 ox_id, +			u32 data_format); +u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			u32 data_format, +			struct fc_rnid_common_id_data_s *common_id_data, +			struct fc_rnid_general_topology_data_s * +			gen_topo_data); +u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c, +			u32 d_id, u32 s_id, +			u32 *pid_list, u16 npids); +u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, +			u32 d_id, u32 s_id, u16 ox_id); +u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			struct fc_rpsc_speed_info_s *oper_speed); +u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id, +			u8 fc4_type); +u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u32 port_id, wwn_t port_name); +u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u32 port_id, wwn_t node_name); +u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u32 port_id, u32 cos); +u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u32 port_id, u8 port_type); +u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u32 port_id); +u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, +			u32 d_id, u32 s_id, u16 ox_id, +			wwn_t port_name); +u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, +			u32 s_id, u16 ox_id); +u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 cmd_code); +u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			wwn_t wwn); +u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			wwn_t wwn); +void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); +void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id); +enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len); +enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, +			 wwn_t port_name); +enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli); +enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, +			wwn_t port_name); +u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			u16 rx_id); +int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code); +u16 fc_tprlo_acc_build(struct fchs_s *fchs, +			struct fc_tprlo_acc_s *tprlo_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			int num_pages); +u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, +			u32 d_id, u32 s_id, u16 ox_id, +			int num_pages); +u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len); +u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, wwn_t port_name, wwn_t node_name, +			u16 pdu_size); +u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); +u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, int num_pages); +u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len); +u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, int num_pages, +			enum fc_tprlo_type tprlo_type, u32 tpr_id); +u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len); +u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, +			u16 ox_id, u32 reason_code, +			u32 reason_expl); +u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, +			u16 ox_id, u32 port_id); +u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr); +u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, +			u32 s_id, u16 ox_id); +#endif diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c new file mode 100644 index 00000000000..8ce5d893467 --- /dev/null +++ b/drivers/scsi/bfa/fcpim.c @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcpim.c - FCP initiator mode i-t nexus state machine + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_fcpim.h" +#include "fcs_rport.h" +#include "fcs_lport.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs.h" +#include <fcs/bfa_fcs_fcpim.h> +#include <fcb/bfa_fcb_fcpim.h> +#include <aen/bfa_aen_itnim.h> + +BFA_TRC_FILE(FCS, FCPIM); + +/* + * forward declarations + */ +static void     bfa_fcs_itnim_timeout(void *arg); +static void     bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim); +static void     bfa_fcs_itnim_send_prli(void *itnim_cbarg, +					struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_itnim_prli_response(void *fcsarg, +					    struct bfa_fcxp_s *fcxp, +					    void *cbarg, +					    bfa_status_t req_status, +					    u32 rsp_len, +					    u32 resid_len, +					    struct fchs_s *rsp_fchs); +static void     bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, +				       enum bfa_itnim_aen_event event); + +/** + *  fcs_itnim_sm FCS itnim state machine events + */ + +enum bfa_fcs_itnim_event { +	BFA_FCS_ITNIM_SM_ONLINE = 1,	/*  rport online event */ +	BFA_FCS_ITNIM_SM_OFFLINE = 2,	/*  rport offline */ +	BFA_FCS_ITNIM_SM_FRMSENT = 3,	/*  prli frame is sent */ +	BFA_FCS_ITNIM_SM_RSP_OK = 4,	/*  good response */ +	BFA_FCS_ITNIM_SM_RSP_ERROR = 5,	/*  error response */ +	BFA_FCS_ITNIM_SM_TIMEOUT = 6,	/*  delay timeout */ +	BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7,	/*  BFA online callback */ +	BFA_FCS_ITNIM_SM_HCB_ONLINE = 8,	/*  BFA offline callback */ +	BFA_FCS_ITNIM_SM_INITIATOR = 9,	/*  rport is initiator */ +	BFA_FCS_ITNIM_SM_DELETE = 10,	/*  delete event from rport */ +	BFA_FCS_ITNIM_SM_PRLO = 11,	/*  delete event from rport */ +}; + +static void     bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, +					 enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, +					   enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, +				      enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, +					    enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, +					    enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, +					enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, +					     enum bfa_fcs_itnim_event event); +static void     bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, +					   enum bfa_fcs_itnim_event event); + +static struct bfa_sm_table_s itnim_sm_table[] = { +	{BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE}, +	{BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND}, +	{BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT}, +	{BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY}, +	{BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE}, +	{BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE}, +	{BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE}, +	{BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR}, +}; + +/** + *  fcs_itnim_sm FCS itnim state machine + */ + +static void +bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, +			 enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_ONLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); +		bfa_fcs_itnim_send_prli(itnim, NULL); +		break; + +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_INITIATOR: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} + +} + +static void +bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, +			   enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_FRMSENT: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli); +		break; + +	case BFA_FCS_ITNIM_SM_INITIATOR: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); +		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); +		break; + +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, +		      enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_RSP_OK: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online); +		bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec); +		break; + +	case BFA_FCS_ITNIM_SM_RSP_ERROR: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry); +		bfa_timer_start(itnim->fcs->bfa, &itnim->timer, +				bfa_fcs_itnim_timeout, itnim, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcxp_discard(itnim->fcxp); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_INITIATOR: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); +		/* +		 * dont discard fcxp. accept will reach same state +		 */ +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcxp_discard(itnim->fcxp); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, +			    enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_TIMEOUT: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); +		bfa_fcs_itnim_send_prli(itnim, NULL); +		break; + +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_timer_stop(&itnim->timer); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_INITIATOR: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); +		bfa_timer_stop(&itnim->timer); +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_timer_stop(&itnim->timer); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, +			    enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_HCB_ONLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online); +		bfa_fcb_itnim_online(itnim->itnim_drv); +		bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE); +		break; + +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_itnim_offline(itnim->bfa_itnim); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, +			enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline); +		bfa_fcb_itnim_offline(itnim->itnim_drv); +		bfa_itnim_offline(itnim->bfa_itnim); +		if (bfa_fcs_port_is_online(itnim->rport->port) == BFA_TRUE) { +			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT); +		} else { +			bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE); +		} +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, +			     enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_HCB_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + +/* + * This state is set when a discovered rport is also in intiator mode. + * This ITN is marked as no_op and is not active and will not be truned into + * online state. + */ +static void +bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, +			   enum bfa_fcs_itnim_event event) +{ +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_trc(itnim->fcs, event); + +	switch (event) { +	case BFA_FCS_ITNIM_SM_OFFLINE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_rport_itnim_ack(itnim->rport); +		break; + +	case BFA_FCS_ITNIM_SM_RSP_ERROR: +	case BFA_FCS_ITNIM_SM_ONLINE: +	case BFA_FCS_ITNIM_SM_INITIATOR: +		break; + +	case BFA_FCS_ITNIM_SM_DELETE: +		bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); +		bfa_fcs_itnim_free(itnim); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  itnim_private FCS ITNIM private interfaces + */ + +static void +bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, +		       enum bfa_itnim_aen_event event) +{ +	struct bfa_fcs_rport_s *rport = itnim->rport; +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = rport->fcs->logm; +	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(rport->port); +	wwn_t           rpwwn = rport->pwwn; +	char            lpwwn_ptr[BFA_STRING_32]; +	char            rpwwn_ptr[BFA_STRING_32]; + +	/* +	 * Don't post events for well known addresses +	 */ +	if (BFA_FCS_PID_IS_WKA(rport->pid)) +		return; + +	wwn2str(lpwwn_ptr, lpwwn); +	wwn2str(rpwwn_ptr, rpwwn); + +	switch (event) { +	case BFA_ITNIM_AEN_ONLINE: +		bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_ITNIM_AEN_OFFLINE: +		bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_ITNIM_AEN_DISCONNECT: +		bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr); +		break; +	default: +		break; +	} + +	aen_data.itnim.vf_id = rport->port->fabric->vf_id; +	aen_data.itnim.ppwwn = +		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs)); +	aen_data.itnim.lpwwn = lpwwn; +	aen_data.itnim.rpwwn = rpwwn; +} + +static void +bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_itnim_s *itnim = itnim_cbarg; +	struct bfa_fcs_rport_s *rport = itnim->rport; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(itnim->fcs, itnim->rport->pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		itnim->stats.fcxp_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe, +				    bfa_fcs_itnim_send_prli, itnim); +		return; +	} +	itnim->fcxp = fcxp; + +	len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid, +			    bfa_fcs_port_get_fcid(port), 0); + +	bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag, +		      BFA_FALSE, FC_CLASS_3, len, &fchs, +		      bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ, +		      FC_RA_TOV); + +	itnim->stats.prli_sent++; +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT); +} + +static void +bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			    bfa_status_t req_status, u32 rsp_len, +			    u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; +	struct fc_els_cmd_s   *els_cmd; +	struct fc_prli_s      *prli_resp; +	struct fc_ls_rjt_s    *ls_rjt; +	struct fc_prli_params_s *sparams; + +	bfa_trc(itnim->fcs, req_status); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		itnim->stats.prli_rsp_err++; +		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + +	if (els_cmd->els_code == FC_ELS_ACC) { +		prli_resp = (struct fc_prli_s *) els_cmd; + +		if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) { +			bfa_trc(itnim->fcs, rsp_len); +			/* +			 * Check if this  r-port is also in Initiator mode. +			 * If so, we need to set this ITN as a no-op. +			 */ +			if (prli_resp->parampage.servparams.initiator) { +				bfa_trc(itnim->fcs, prli_resp->parampage.type); +				itnim->rport->scsi_function = +					BFA_RPORT_INITIATOR; +				itnim->stats.prli_rsp_acc++; +				bfa_sm_send_event(itnim, +						  BFA_FCS_ITNIM_SM_INITIATOR); +				return; +			} + +			itnim->stats.prli_rsp_parse_err++; +			return; +		} +		itnim->rport->scsi_function = BFA_RPORT_TARGET; + +		sparams = &prli_resp->parampage.servparams; +		itnim->seq_rec = sparams->retry; +		itnim->rec_support = sparams->rec_support; +		itnim->task_retry_id = sparams->task_retry_id; +		itnim->conf_comp = sparams->confirm; + +		itnim->stats.prli_rsp_acc++; +		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); +	} else { +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + +		bfa_trc(itnim->fcs, ls_rjt->reason_code); +		bfa_trc(itnim->fcs, ls_rjt->reason_code_expl); + +		itnim->stats.prli_rsp_rjt++; +		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); +	} +} + +static void +bfa_fcs_itnim_timeout(void *arg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg; + +	itnim->stats.timeout++; +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT); +} + +static void +bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim) +{ +	bfa_itnim_delete(itnim->bfa_itnim); +	bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv); +} + + + +/** + *  itnim_public FCS ITNIM public interfaces + */ + +/** + * 	Called by rport when a new rport is created. + * + * @param[in] rport	-  remote port. + */ +struct bfa_fcs_itnim_s * +bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_port_s *port = rport->port; +	struct bfa_fcs_itnim_s *itnim; +	struct bfad_itnim_s *itnim_drv; +	struct bfa_itnim_s *bfa_itnim; + +	/* +	 * call bfad to allocate the itnim +	 */ +	bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv); +	if (itnim == NULL) { +		bfa_trc(port->fcs, rport->pwwn); +		return NULL; +	} + +	/* +	 * Initialize itnim +	 */ +	itnim->rport = rport; +	itnim->fcs = rport->fcs; +	itnim->itnim_drv = itnim_drv; + +	/* +	 * call BFA to create the itnim +	 */ +	bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim); + +	if (bfa_itnim == NULL) { +		bfa_trc(port->fcs, rport->pwwn); +		bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv); +		bfa_assert(0); +		return NULL; +	} + +	itnim->bfa_itnim = bfa_itnim; +	itnim->seq_rec = BFA_FALSE; +	itnim->rec_support = BFA_FALSE; +	itnim->conf_comp = BFA_FALSE; +	itnim->task_retry_id = BFA_FALSE; + +	/* +	 * Set State machine +	 */ +	bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); + +	return itnim; +} + +/** + * 	Called by rport to delete  the instance of FCPIM. + * + * @param[in] rport	-  remote port. + */ +void +bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim) +{ +	bfa_trc(itnim->fcs, itnim->rport->pid); +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE); +} + +/** + * Notification from rport that PLOGI is complete to initiate FC-4 session. + */ +void +bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim) +{ +	itnim->stats.onlines++; + +	if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) { +		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE); +	} else { +		/* +		 * For well known addresses, we set the itnim to initiator +		 * state +		 */ +		itnim->stats.initiator++; +		bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); +	} +} + +/** + * Called by rport to handle a remote device offline. + */ +void +bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim) +{ +	itnim->stats.offlines++; +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE); +} + +/** + * Called by rport when remote port is known to be an initiator from + * PRLI received. + */ +void +bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim) +{ +	bfa_trc(itnim->fcs, itnim->rport->pid); +	itnim->stats.initiator++; +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); +} + +/** + * Called by rport to check if the itnim is online. + */ +bfa_status_t +bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) +{ +	bfa_trc(itnim->fcs, itnim->rport->pid); +	switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) { +	case BFA_ITNIM_ONLINE: +	case BFA_ITNIM_INITIATIOR: +		return BFA_STATUS_OK; + +	default: +		return BFA_STATUS_NO_FCPIM_NEXUS; + +	} +} + +/** + * BFA completion callback for bfa_itnim_online(). + */ +void +bfa_cb_itnim_online(void *cbarg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg; + +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE); +} + +/** + * BFA completion callback for bfa_itnim_offline(). + */ +void +bfa_cb_itnim_offline(void *cb_arg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE); +} + +/** + * Mark the beginning of PATH TOV handling. IO completion callbacks + * are still pending. + */ +void +bfa_cb_itnim_tov_begin(void *cb_arg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_fcb_itnim_tov_begin(itnim->itnim_drv); +} + +/** + * Mark the end of PATH TOV handling. All pending IOs are already cleaned up. + */ +void +bfa_cb_itnim_tov(void *cb_arg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_fcb_itnim_tov(itnim->itnim_drv); +} + +/** + * 		BFA notification to FCS/driver for second level error recovery. + * + * Atleast one I/O request has timedout and target is unresponsive to + * repeated abort requests. Second level error recovery should be initiated + * by starting implicit logout and recovery procedures. + */ +void +bfa_cb_itnim_sler(void *cb_arg) +{ +	struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg; + +	itnim->stats.sler++; +	bfa_trc(itnim->fcs, itnim->rport->pwwn); +	bfa_fcs_rport_logo_imp(itnim->rport); +} + +struct bfa_fcs_itnim_s * +bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) +{ +	struct bfa_fcs_rport_s *rport; +	rport = bfa_fcs_rport_lookup(port, rpwwn); + +	if (!rport) +		return NULL; + +	bfa_assert(rport->itnim != NULL); +	return (rport->itnim); +} + +bfa_status_t +bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +		       struct bfa_itnim_attr_s *attr) +{ +	struct bfa_fcs_itnim_s *itnim = NULL; + +	itnim = bfa_fcs_itnim_lookup(port, rpwwn); + +	if (itnim == NULL) +		return BFA_STATUS_NO_FCPIM_NEXUS; + +	attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); +	attr->retry = itnim->seq_rec; +	attr->rec_support = itnim->rec_support; +	attr->conf_comp = itnim->conf_comp; +	attr->task_retry_id = itnim->task_retry_id; + +	return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +			struct bfa_itnim_stats_s *stats) +{ +	struct bfa_fcs_itnim_s *itnim = NULL; + +	bfa_assert(port != NULL); + +	itnim = bfa_fcs_itnim_lookup(port, rpwwn); + +	if (itnim == NULL) +		return BFA_STATUS_NO_FCPIM_NEXUS; + +	bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s)); + +	return BFA_STATUS_OK; +} + +bfa_status_t +bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn) +{ +	struct bfa_fcs_itnim_s *itnim = NULL; + +	bfa_assert(port != NULL); + +	itnim = bfa_fcs_itnim_lookup(port, rpwwn); + +	if (itnim == NULL) +		return BFA_STATUS_NO_FCPIM_NEXUS; + +	bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s)); +	return BFA_STATUS_OK; +} + +void +bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, +		      u16 len) +{ +	struct fc_els_cmd_s   *els_cmd; + +	bfa_trc(itnim->fcs, fchs->type); + +	if (fchs->type != FC_TYPE_ELS) +		return; + +	els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	bfa_trc(itnim->fcs, els_cmd->els_code); + +	switch (els_cmd->els_code) { +	case FC_ELS_PRLO: +		/* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */ +		break; + +	default: +		bfa_assert(0); +	} +} + +void +bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim) +{ +} + +void +bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim) +{ +} + +/** + *   Module initialization + */ +void +bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs) +{ +} + +/** + *   Module cleanup + */ +void +bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} + + diff --git a/drivers/scsi/bfa/fcptm.c b/drivers/scsi/bfa/fcptm.c new file mode 100644 index 00000000000..8c8b08c72e7 --- /dev/null +++ b/drivers/scsi/bfa/fcptm.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + * This file contains dummy FCPTM routines to aid in Initiator Mode only + * compilation of OS driver. + * + */ + +#include "bfa_os_inc.h" +#include "fcs_rport.h" +#include "fcs_fcptm.h" +#include "fcs/bfa_fcs_rport.h" + +struct bfa_fcs_tin_s * +bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport) +{ +	return NULL; +} + +void +bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin) +{ +} + +void +bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin) +{ +} + +void +bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin) +{ +} + +void +bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len) +{ +} + +void +bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len) +{ +} + +void +bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin) +{ +} + +void +bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin) +{ +} diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h new file mode 100644 index 00000000000..deee685e847 --- /dev/null +++ b/drivers/scsi/bfa/fcs.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs.h FCS module functions + */ + + +#ifndef __FCS_H__ +#define __FCS_H__ + +#define __fcs_min_cfg(__fcs)       (__fcs)->min_cfg + +void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs); + +#endif /* __FCS_H__ */ diff --git a/drivers/scsi/bfa/fcs_auth.h b/drivers/scsi/bfa/fcs_auth.h new file mode 100644 index 00000000000..65d155fea3d --- /dev/null +++ b/drivers/scsi/bfa/fcs_auth.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_uf.h FCS unsolicited frame receive + */ + + +#ifndef __FCS_AUTH_H__ +#define __FCS_AUTH_H__ + +#include <fcs/bfa_fcs.h> +#include <fcs/bfa_fcs_vport.h> +#include <fcs/bfa_fcs_lport.h> + +/* + * fcs friend functions: only between fcs modules + */ +void bfa_fcs_auth_uf_recv(struct bfa_fcs_fabric_s *fabric, int len); +void bfa_fcs_auth_start(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_auth_stop(struct bfa_fcs_fabric_s *fabric); + +#endif /* __FCS_UF_H__ */ diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h new file mode 100644 index 00000000000..eee960820f8 --- /dev/null +++ b/drivers/scsi/bfa/fcs_fabric.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_lport.h FCS logical port interfaces + */ + +#ifndef __FCS_FABRIC_H__ +#define __FCS_FABRIC_H__ + +#include <fcs/bfa_fcs.h> +#include <fcs/bfa_fcs_vport.h> +#include <fcs/bfa_fcs_lport.h> + +/* +* fcs friend functions: only between fcs modules + */ +void            bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); +void            bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); +void            bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs); +void            bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); +void            bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); +void            bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, +					struct bfa_fcs_vport_s *vport); +void            bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, +					struct bfa_fcs_vport_s *vport); +int             bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric); +struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup( +			struct bfa_fcs_fabric_s *fabric, wwn_t pwwn); +void            bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs); +void            bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, +			struct fchs_s *fchs, u16 len); +u16        bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric); +bfa_boolean_t   bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric); +enum bfa_pport_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric); +void     	bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric); +void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric); + +bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, +			struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg, +			struct bfad_vf_s *vf_drv); +void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, +			enum auth_status status); + +void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, +			wwn_t fabric_name); +#endif /* __FCS_FABRIC_H__ */ diff --git a/drivers/scsi/bfa/fcs_fcpim.h b/drivers/scsi/bfa/fcs_fcpim.h new file mode 100644 index 00000000000..61e9e2687de --- /dev/null +++ b/drivers/scsi/bfa/fcs_fcpim.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __FCS_FCPIM_H__ +#define __FCS_FCPIM_H__ + +#include <defs/bfa_defs_port.h> +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_rport.h> + +/* + * Following routines are from FCPIM and will be called by rport. + */ +struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport); +void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim); +bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim); + +void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim); +void bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim); + +/* + * Modudle init/cleanup routines. + */ +void bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs); +void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, +			u16 len); +#endif /* __FCS_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/fcs_fcptm.h b/drivers/scsi/bfa/fcs_fcptm.h new file mode 100644 index 00000000000..ffff0829fd3 --- /dev/null +++ b/drivers/scsi/bfa/fcs_fcptm.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FCS_FCPTM_H__ +#define __FCS_FCPTM_H__ + +#include <defs/bfa_defs_port.h> +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_rport.h> + +/* + * Following routines are from FCPTM and will be called by rport. + */ +struct bfa_fcs_tin_s *bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport); +void bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin); +void bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin); +void bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin); +void bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, +			u16 len); +void bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin); +void bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin); + +/* + * Modudle init/cleanup routines. + */ +void bfa_fcs_fcptm_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_fcptm_modexit(struct bfa_fcs_s *fcs); +void bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, +			u16 len); + +#endif /* __FCS_FCPTM_H__ */ diff --git a/drivers/scsi/bfa/fcs_fcxp.h b/drivers/scsi/bfa/fcs_fcxp.h new file mode 100644 index 00000000000..8277fe9c2b7 --- /dev/null +++ b/drivers/scsi/bfa/fcs_fcxp.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_fcxp.h FCXP helper macros for FCS + */ + + +#ifndef __FCS_FCXP_H__ +#define __FCS_FCXP_H__ + +#define bfa_fcs_fcxp_alloc(__fcs)	\ +	bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL) + +#endif /* __FCS_FCXP_H__ */ diff --git a/drivers/scsi/bfa/fcs_lport.h b/drivers/scsi/bfa/fcs_lport.h new file mode 100644 index 00000000000..ae744ba3567 --- /dev/null +++ b/drivers/scsi/bfa/fcs_lport.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_lport.h FCS logical port interfaces + */ + +#ifndef __FCS_LPORT_H__ +#define __FCS_LPORT_H__ + +#define __VPORT_H__ +#include <defs/bfa_defs_port.h> +#include <bfa_svc.h> +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_rport.h> +#include <fcs/bfa_fcs_vport.h> +#include <fcs_fabric.h> +#include <fcs_ms.h> +#include <cs/bfa_q.h> +#include <fcbuild.h> + +/* + * PID used in P2P/N2N ( In Big Endian) + */ +#define N2N_LOCAL_PID	    0x010000 +#define N2N_REMOTE_PID		0x020000 + +/* + * Misc Timeouts + */ +/* + * To be used when spawning a timer before retrying a failed command. Milli + * Secs. + */ +#define	BFA_FCS_RETRY_TIMEOUT 2000 + +/* + * Check for Port/Vport Mode/Role + */ +#define	BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \ +		(port->port_cfg.roles & BFA_PORT_ROLE_FCP_IM) + +#define	BFA_FCS_VPORT_IS_TARGET_MODE(port) \ +		(port->port_cfg.roles & BFA_PORT_ROLE_FCP_TM) + +#define	BFA_FCS_VPORT_IS_IPFC_MODE(port) \ +		(port->port_cfg.roles & BFA_PORT_ROLE_FCP_IPFC) + +/* + * Is this a Well Known Address + */ +#define BFA_FCS_PID_IS_WKA(pid)  ((bfa_os_ntoh3b(pid) > 0xFFF000) ?  1 : 0) + +/* + * Pointer to elements within Port + */ +#define BFA_FCS_GET_HAL_FROM_PORT(port)  (port->fcs->bfa) +#define BFA_FCS_GET_NS_FROM_PORT(port)  (&port->port_topo.pfab.ns) +#define BFA_FCS_GET_SCN_FROM_PORT(port)  (&port->port_topo.pfab.scn) +#define BFA_FCS_GET_MS_FROM_PORT(port)  (&port->port_topo.pfab.ms) +#define BFA_FCS_GET_FDMI_FROM_PORT(port)  (&port->port_topo.pfab.ms.fdmi) + +/* + * handler for unsolicied frames + */ +void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs, +			u16 len); + +/* + * Following routines will be called by Fabric to indicate port + * online/offline to vport. + */ +void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs, +			u16 vf_id, struct bfa_port_cfg_s *port_cfg, +			struct bfa_fcs_vport_s *vport); +void bfa_fcs_port_online(struct bfa_fcs_port_s *port); +void bfa_fcs_port_offline(struct bfa_fcs_port_s *port); +void bfa_fcs_port_delete(struct bfa_fcs_port_s *port); +bfa_boolean_t   bfa_fcs_port_is_online(struct bfa_fcs_port_s *port); + +/* + * Lookup rport based on PID + */ +struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pid( +			struct bfa_fcs_port_s *port, u32 pid); + +/* + * Lookup rport based on PWWN + */ +struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pwwn( +			struct bfa_fcs_port_s *port, wwn_t pwwn); +struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_nwwn( +			struct bfa_fcs_port_s *port, wwn_t nwwn); +void bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port, +			struct bfa_fcs_rport_s *rport); +void bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port, +			struct bfa_fcs_rport_s *rport); + +void bfa_fcs_port_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_port_modexit(struct bfa_fcs_s *fcs); +void bfa_fcs_port_lip(struct bfa_fcs_port_s *port); + +#endif /* __FCS_LPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_ms.h b/drivers/scsi/bfa/fcs_ms.h new file mode 100644 index 00000000000..b6a8c12876f --- /dev/null +++ b/drivers/scsi/bfa/fcs_ms.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_ms.h FCS ms interfaces + */ +#ifndef __FCS_MS_H__ +#define __FCS_MS_H__ + +/* MS FCS routines */ +void bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port); +void bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port); +void bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port); +void bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port); + +/* FDMI FCS routines */ +void bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms); +void bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms); +void bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms); + +#endif diff --git a/drivers/scsi/bfa/fcs_port.h b/drivers/scsi/bfa/fcs_port.h new file mode 100644 index 00000000000..abb65191dd2 --- /dev/null +++ b/drivers/scsi/bfa/fcs_port.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_pport.h FCS physical port interfaces + */ + + +#ifndef __FCS_PPORT_H__ +#define __FCS_PPORT_H__ + +/* + * fcs friend functions: only between fcs modules + */ +void bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs); + +#endif /* __FCS_PPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h new file mode 100644 index 00000000000..f601e9d7423 --- /dev/null +++ b/drivers/scsi/bfa/fcs_rport.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_rport.h FCS rport interfaces and defines + */ + +#ifndef __FCS_RPORT_H__ +#define __FCS_RPORT_H__ + +#include <fcs/bfa_fcs_rport.h> + +void bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs); + +void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, +			u16 len); +void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport); + +struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_port_s *port, +			u32 pid); +void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs, +			struct fc_logi_s *plogi_rsp); +void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs, +			struct fc_logi_s *plogi); +void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, +			struct fc_logi_s *plogi); +void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport); +int  bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport); +struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, +			wwn_t wwn); + + +/* Rport Features */ +void  bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport); +void  bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport); +void  bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport); + +#endif /* __FCS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/fcs_trcmod.h b/drivers/scsi/bfa/fcs_trcmod.h new file mode 100644 index 00000000000..41b5ae8d764 --- /dev/null +++ b/drivers/scsi/bfa/fcs_trcmod.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_trcmod.h BFA FCS trace modules + */ + +#ifndef __FCS_TRCMOD_H__ +#define __FCS_TRCMOD_H__ + +#include <cs/bfa_trc.h> + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { +	BFA_TRC_FCS_FABRIC		= 1, +	BFA_TRC_FCS_VFAPI		= 2, +	BFA_TRC_FCS_PORT		= 3, +	BFA_TRC_FCS_VPORT		= 4, +	BFA_TRC_FCS_VP_API		= 5, +	BFA_TRC_FCS_VPS			= 6, +	BFA_TRC_FCS_RPORT		= 7, +	BFA_TRC_FCS_FCPIM		= 8, +	BFA_TRC_FCS_FCPTM		= 9, +	BFA_TRC_FCS_NS			= 10, +	BFA_TRC_FCS_SCN			= 11, +	BFA_TRC_FCS_LOOP		= 12, +	BFA_TRC_FCS_UF			= 13, +	BFA_TRC_FCS_PPORT		= 14, +	BFA_TRC_FCS_FCPIP		= 15, +	BFA_TRC_FCS_PORT_API	= 16, +	BFA_TRC_FCS_RPORT_API	= 17, +	BFA_TRC_FCS_AUTH		= 18, +	BFA_TRC_FCS_N2N			= 19, +	BFA_TRC_FCS_MS			= 20, +	BFA_TRC_FCS_FDMI		= 21, +	BFA_TRC_FCS_RPORT_FTRS	= 22, +}; + +#endif /* __FCS_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/fcs_uf.h b/drivers/scsi/bfa/fcs_uf.h new file mode 100644 index 00000000000..96f1bdcb31e --- /dev/null +++ b/drivers/scsi/bfa/fcs_uf.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  fcs_uf.h FCS unsolicited frame receive + */ + + +#ifndef __FCS_UF_H__ +#define __FCS_UF_H__ + +/* + * fcs friend functions: only between fcs modules + */ +void bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs); + +#endif /* __FCS_UF_H__ */ diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h new file mode 100644 index 00000000000..9e80b6a97b7 --- /dev/null +++ b/drivers/scsi/bfa/fcs_vport.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FCS_VPORT_H__ +#define __FCS_VPORT_H__ + +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_vport.h> +#include <defs/bfa_defs_pci.h> + +/* + * Modudle init/cleanup routines. + */ + +void bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs); +void bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs); + +void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); +u32 bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs); + +#endif /* __FCS_VPORT_H__ */ + diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c new file mode 100644 index 00000000000..b845eb272c7 --- /dev/null +++ b/drivers/scsi/bfa/fdmi.c @@ -0,0 +1,1223 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  port_api.c BFA FCS port + */ + + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "lport_priv.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include <fcs/bfa_fcs_fdmi.h> + +BFA_TRC_FILE(FCS, FDMI); + +#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2 + +/* + * forward declarations + */ +static void     bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, +					   struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_fdmi_rhba_response(void *fcsarg, +						struct bfa_fcxp_s *fcxp, +						void *cbarg, +						bfa_status_t req_status, +						u32 rsp_len, +						u32 resid_len, +						struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_fdmi_rprt_response(void *fcsarg, +						struct bfa_fcxp_s *fcxp, +						void *cbarg, +						bfa_status_t req_status, +						u32 rsp_len, +						u32 resid_len, +						struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_fdmi_rpa_response(void *fcsarg, +					       struct bfa_fcxp_s *fcxp, +					       void *cbarg, +					       bfa_status_t req_status, +					       u32 rsp_len, +					       u32 resid_len, +					       struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_fdmi_timeout(void *arg); +static u16 bfa_fcs_port_fdmi_build_rhba_pyld( +			struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); +static u16 bfa_fcs_port_fdmi_build_rprt_pyld( +			struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); +static u16 bfa_fcs_port_fdmi_build_rpa_pyld( +			struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); +static u16 bfa_fcs_port_fdmi_build_portattr_block( +			struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld); +void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi, +			struct bfa_fcs_fdmi_hba_attr_s *hba_attr); +void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi, +			struct bfa_fcs_fdmi_port_attr_s *port_attr); +/** + *  fcs_fdmi_sm FCS FDMI state machine + */ + +/** + *  FDMI State Machine events + */ +enum port_fdmi_event { +	FDMISM_EVENT_PORT_ONLINE = 1, +	FDMISM_EVENT_PORT_OFFLINE = 2, +	FDMISM_EVENT_RSP_OK = 4, +	FDMISM_EVENT_RSP_ERROR = 5, +	FDMISM_EVENT_TIMEOUT = 6, +	FDMISM_EVENT_RHBA_SENT = 7, +	FDMISM_EVENT_RPRT_SENT = 8, +	FDMISM_EVENT_RPA_SENT = 9, +}; + +static void bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void     bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void     bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +static void     bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi, +			enum port_fdmi_event event); +/** + * 		Start in offline state - awaiting MS to send start. + */ +static void +bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi, +			     enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	fdmi->retry_cnt = 0; + +	switch (event) { +	case FDMISM_EVENT_PORT_ONLINE: +		if (port->vport) { +			/* +			 * For Vports, register a new port. +			 */ +			bfa_sm_set_state(fdmi, +					 bfa_fcs_port_fdmi_sm_sending_rprt); +			bfa_fcs_port_fdmi_send_rprt(fdmi, NULL); +		} else { +			/* +			 * For a base port, we should first register the HBA +			 * atribute. The HBA attribute also contains the base +			 *  port registration. +			 */ +			bfa_sm_set_state(fdmi, +					 bfa_fcs_port_fdmi_sm_sending_rhba); +			bfa_fcs_port_fdmi_send_rhba(fdmi, NULL); +		} +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi, +				  enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RHBA_SENT: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), +				       &fdmi->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi, +			  enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RSP_ERROR: +		/* +		 * if max retries have not been reached, start timer for a +		 * delayed retry +		 */ +		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba_retry); +			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), +					&fdmi->timer, bfa_fcs_port_fdmi_timeout, +					fdmi, BFA_FCS_RETRY_TIMEOUT); +		} else { +			/* +			 * set state to offline +			 */ +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		} +		break; + +	case FDMISM_EVENT_RSP_OK: +		/* +		 * Initiate Register Port Attributes +		 */ +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa); +		fdmi->retry_cnt = 0; +		bfa_fcs_port_fdmi_send_rpa(fdmi, NULL); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_fcxp_discard(fdmi->fcxp); +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi, +				enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rhba); +		bfa_fcs_port_fdmi_send_rhba(fdmi, NULL); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_timer_stop(&fdmi->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +/* +* RPRT : Register Port + */ +static void +bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi, +				  enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RPRT_SENT: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), +				       &fdmi->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi, +			  enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RSP_ERROR: +		/* +		 * if max retries have not been reached, start timer for a +		 * delayed retry +		 */ +		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt_retry); +			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), +					&fdmi->timer, bfa_fcs_port_fdmi_timeout, +					fdmi, BFA_FCS_RETRY_TIMEOUT); + +		} else { +			/* +			 * set state to offline +			 */ +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +			fdmi->retry_cnt = 0; +		} +		break; + +	case FDMISM_EVENT_RSP_OK: +		fdmi->retry_cnt = 0; +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_fcxp_discard(fdmi->fcxp); +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi, +				enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rprt); +		bfa_fcs_port_fdmi_send_rprt(fdmi, NULL); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_timer_stop(&fdmi->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +/* + * Register Port Attributes + */ +static void +bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi, +				 enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RPA_SENT: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), +				       &fdmi->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi, +			 enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_RSP_ERROR: +		/* +		 * if max retries have not been reached, start timer for a +		 * delayed retry +		 */ +		if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa_retry); +			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), +					&fdmi->timer, bfa_fcs_port_fdmi_timeout, +					fdmi, BFA_FCS_RETRY_TIMEOUT); +		} else { +			/* +			 * set state to offline +			 */ +			bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +			fdmi->retry_cnt = 0; +		} +		break; + +	case FDMISM_EVENT_RSP_OK: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online); +		fdmi->retry_cnt = 0; +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_fcxp_discard(fdmi->fcxp); +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi, +			       enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa); +		bfa_fcs_port_fdmi_send_rpa(fdmi, NULL); +		break; + +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		bfa_timer_stop(&fdmi->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi, +			    enum port_fdmi_event event) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); +	bfa_trc(port->fcs, event); + +	switch (event) { +	case FDMISM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + + +/** +*   RHBA : Register HBA Attributes. + */ +static void +bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct fchs_s          fchs; +	int             len, attr_len; +	struct bfa_fcxp_s *fcxp; +	u8        *pyld; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, +				    bfa_fcs_port_fdmi_send_rhba, fdmi); +		return; +	} +	fdmi->fcxp = fcxp; + +	pyld = bfa_fcxp_get_reqbuf(fcxp); +	bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + +	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), +				   FDMI_RHBA); + +	attr_len = bfa_fcs_port_fdmi_build_rhba_pyld(fdmi, +			(u8 *) ((struct ct_hdr_s *) pyld + 1)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, (len + attr_len), &fchs, +		      bfa_fcs_port_fdmi_rhba_response, (void *)fdmi, +		      FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT); +} + +static          u16 +bfa_fcs_port_fdmi_build_rhba_pyld(struct bfa_fcs_port_fdmi_s *fdmi, +				  u8 *pyld) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct bfa_fcs_fdmi_hba_attr_s hba_attr;	/* @todo */ +	struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; /* @todo */ +	struct fdmi_rhba_s    *rhba = (struct fdmi_rhba_s *) pyld; +	struct fdmi_attr_s    *attr; +	u8        *curr_ptr; +	u16        len, count; + +	/* +	 * get hba attributes +	 */ +	bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr); + +	rhba->hba_id = bfa_fcs_port_get_pwwn(port); +	rhba->port_list.num_ports = bfa_os_htonl(1); +	rhba->port_list.port_entry = bfa_fcs_port_get_pwwn(port); + +	len = sizeof(rhba->hba_id) + sizeof(rhba->port_list); + +	count = 0; +	len += sizeof(rhba->hba_attr_blk.attr_count); + +	/* +	 * fill out the invididual entries of the HBA attrib Block +	 */ +	curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr; + +	/* +	 * Node Name +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME); +	attr->len = sizeof(wwn_t); +	memcpy(attr->value, &bfa_fcs_port_get_nwwn(port), attr->len); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Manufacturer +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER); +	attr->len = (u16) strlen(fcs_hba_attr->manufacturer); +	memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Serial Number +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM); +	attr->len = (u16) strlen(fcs_hba_attr->serial_num); +	memcpy(attr->value, fcs_hba_attr->serial_num, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Model +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL); +	attr->len = (u16) strlen(fcs_hba_attr->model); +	memcpy(attr->value, fcs_hba_attr->model, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Model Desc +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC); +	attr->len = (u16) strlen(fcs_hba_attr->model_desc); +	memcpy(attr->value, fcs_hba_attr->model_desc, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * H/W Version +	 */ +	if (fcs_hba_attr->hw_version[0] != '\0') { +		attr = (struct fdmi_attr_s *) curr_ptr; +		attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION); +		attr->len = (u16) strlen(fcs_hba_attr->hw_version); +		memcpy(attr->value, fcs_hba_attr->hw_version, attr->len); +		/* variable fields need to be 4 byte aligned */ +		attr->len = fc_roundup(attr->len, sizeof(u32)); +		curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +		len += attr->len; +		count++; +		attr->len = +			bfa_os_htons(attr->len + sizeof(attr->type) + +				     sizeof(attr->len)); +	} + +	/* +	 * Driver Version +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION); +	attr->len = (u16) strlen(fcs_hba_attr->driver_version); +	memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len;; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Option Rom Version +	 */ +	if (fcs_hba_attr->option_rom_ver[0] != '\0') { +		attr = (struct fdmi_attr_s *) curr_ptr; +		attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION); +		attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver); +		memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len); +		/* variable fields need to be 4 byte aligned */ +		attr->len = fc_roundup(attr->len, sizeof(u32)); +		curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +		len += attr->len; +		count++; +		attr->len = +			bfa_os_htons(attr->len + sizeof(attr->type) + +				     sizeof(attr->len)); +	} + +	/* +	 * f/w Version = driver version +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION); +	attr->len = (u16) strlen(fcs_hba_attr->driver_version); +	memcpy(attr->value, fcs_hba_attr->driver_version, attr->len); +	/* variable fields need to be 4 byte aligned */ +	attr->len = fc_roundup(attr->len, sizeof(u32)); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * OS Name +	 */ +	if (fcs_hba_attr->os_name[0] != '\0') { +		attr = (struct fdmi_attr_s *) curr_ptr; +		attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME); +		attr->len = (u16) strlen(fcs_hba_attr->os_name); +		memcpy(attr->value, fcs_hba_attr->os_name, attr->len); +		/* variable fields need to be 4 byte aligned */ +		attr->len = fc_roundup(attr->len, sizeof(u32)); +		curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +		len += attr->len; +		count++; +		attr->len = +			bfa_os_htons(attr->len + sizeof(attr->type) + +				     sizeof(attr->len)); +	} + +	/* +	 * MAX_CT_PAYLOAD +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT); +	attr->len = sizeof(fcs_hba_attr->max_ct_pyld); +	memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len); +	len += attr->len; +	count++; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Update size of payload +	 */ +	len += ((sizeof(attr->type) + sizeof(attr->len)) * count); + +	rhba->hba_attr_blk.attr_count = bfa_os_htonl(count); +	return len; +} + +static void +bfa_fcs_port_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				void *cbarg, bfa_status_t req_status, +				u32 rsp_len, u32 resid_len, +				struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); +		return; +	} + +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +/** +*   RPRT : Register Port + */ +static void +bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct fchs_s          fchs; +	u16        len, attr_len; +	struct bfa_fcxp_s *fcxp; +	u8        *pyld; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, +				    bfa_fcs_port_fdmi_send_rprt, fdmi); +		return; +	} +	fdmi->fcxp = fcxp; + +	pyld = bfa_fcxp_get_reqbuf(fcxp); +	bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + +	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), +				   FDMI_RPRT); + +	attr_len = bfa_fcs_port_fdmi_build_rprt_pyld(fdmi, +			(u8 *) ((struct ct_hdr_s *) pyld + 1)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len + attr_len, &fchs, +		      bfa_fcs_port_fdmi_rprt_response, (void *)fdmi, +		      FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT); +} + +/** + * This routine builds Port Attribute Block that used in RPA, RPRT commands. + */ +static          u16 +bfa_fcs_port_fdmi_build_portattr_block(struct bfa_fcs_port_fdmi_s *fdmi, +				       u8 *pyld) +{ +	struct bfa_fcs_fdmi_port_attr_s fcs_port_attr; +	struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld; +	struct fdmi_attr_s    *attr; +	u8        *curr_ptr; +	u16        len; +	u8         count = 0; + +	/* +	 * get port attributes +	 */ +	bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr); + +	len = sizeof(port_attrib->attr_count); + +	/* +	 * fill out the invididual entries +	 */ +	curr_ptr = (u8 *) &port_attrib->port_attr; + +	/* +	 * FC4 Types +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES); +	attr->len = sizeof(fcs_port_attr.supp_fc4_types); +	memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	++count; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * Supported Speed +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED); +	attr->len = sizeof(fcs_port_attr.supp_speed); +	memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	++count; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * current Port Speed +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED); +	attr->len = sizeof(fcs_port_attr.curr_speed); +	memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	++count; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * max frame size +	 */ +	attr = (struct fdmi_attr_s *) curr_ptr; +	attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE); +	attr->len = sizeof(fcs_port_attr.max_frm_size); +	memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len); +	curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +	len += attr->len; +	++count; +	attr->len = +		bfa_os_htons(attr->len + sizeof(attr->type) + +			     sizeof(attr->len)); + +	/* +	 * OS Device Name +	 */ +	if (fcs_port_attr.os_device_name[0] != '\0') { +		attr = (struct fdmi_attr_s *) curr_ptr; +		attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME); +		attr->len = (u16) strlen(fcs_port_attr.os_device_name); +		memcpy(attr->value, fcs_port_attr.os_device_name, attr->len); +		/* variable fields need to be 4 byte aligned */ +		attr->len = fc_roundup(attr->len, sizeof(u32)); +		curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +		len += attr->len; +		++count; +		attr->len = +			bfa_os_htons(attr->len + sizeof(attr->type) + +				     sizeof(attr->len)); + +	} +	/* +	 * Host Name +	 */ +	if (fcs_port_attr.host_name[0] != '\0') { +		attr = (struct fdmi_attr_s *) curr_ptr; +		attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME); +		attr->len = (u16) strlen(fcs_port_attr.host_name); +		memcpy(attr->value, fcs_port_attr.host_name, attr->len); +		/* variable fields need to be 4 byte aligned */ +		attr->len = fc_roundup(attr->len, sizeof(u32)); +		curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len; +		len += attr->len; +		++count; +		attr->len = +			bfa_os_htons(attr->len + sizeof(attr->type) + +				     sizeof(attr->len)); + +	} + +	/* +	 * Update size of payload +	 */ +	port_attrib->attr_count = bfa_os_htonl(count); +	len += ((sizeof(attr->type) + sizeof(attr->len)) * count); +	return len; +} + +static          u16 +bfa_fcs_port_fdmi_build_rprt_pyld(struct bfa_fcs_port_fdmi_s *fdmi, +				  u8 *pyld) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct fdmi_rprt_s    *rprt = (struct fdmi_rprt_s *) pyld; +	u16        len; + +	rprt->hba_id = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); +	rprt->port_name = bfa_fcs_port_get_pwwn(port); + +	len = bfa_fcs_port_fdmi_build_portattr_block(fdmi, +			(u8 *) &rprt->port_attr_blk); + +	len += sizeof(rprt->hba_id) + sizeof(rprt->port_name); + +	return len; +} + +static void +bfa_fcs_port_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				void *cbarg, bfa_status_t req_status, +				u32 rsp_len, u32 resid_len, +				struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); +		return; +	} + +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +/** +*   RPA : Register Port Attributes. + */ +static void +bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct fchs_s          fchs; +	u16        len, attr_len; +	struct bfa_fcxp_s *fcxp; +	u8        *pyld; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, +				    bfa_fcs_port_fdmi_send_rpa, fdmi); +		return; +	} +	fdmi->fcxp = fcxp; + +	pyld = bfa_fcxp_get_reqbuf(fcxp); +	bfa_os_memset(pyld, 0, FC_MAX_PDUSZ); + +	len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port), +				   FDMI_RPA); + +	attr_len = bfa_fcs_port_fdmi_build_rpa_pyld(fdmi, +			(u8 *) ((struct ct_hdr_s *) pyld + 1)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len + attr_len, &fchs, +		      bfa_fcs_port_fdmi_rpa_response, (void *)fdmi, +		      FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT); +} + +static          u16 +bfa_fcs_port_fdmi_build_rpa_pyld(struct bfa_fcs_port_fdmi_s *fdmi, +				 u8 *pyld) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct fdmi_rpa_s     *rpa = (struct fdmi_rpa_s *) pyld; +	u16        len; + +	rpa->port_name = bfa_fcs_port_get_pwwn(port); + +	len = bfa_fcs_port_fdmi_build_portattr_block(fdmi, +			(u8 *) &rpa->port_attr_blk); + +	len += sizeof(rpa->port_name); + +	return len; +} + +static void +bfa_fcs_port_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +			       void *cbarg, bfa_status_t req_status, +			       u32 rsp_len, u32 resid_len, +			       struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg; +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); +		return; +	} + +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); +} + +static void +bfa_fcs_port_fdmi_timeout(void *arg) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)arg; + +	bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT); +} + +void +bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi, +			 struct bfa_fcs_fdmi_hba_attr_s *hba_attr) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; +	struct bfa_adapter_attr_s adapter_attr; + +	bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s)); +	bfa_os_memset(&adapter_attr, 0, sizeof(struct bfa_adapter_attr_s)); + +	bfa_ioc_get_adapter_attr(&port->fcs->bfa->ioc, &adapter_attr); + +	strncpy(hba_attr->manufacturer, adapter_attr.manufacturer, +		sizeof(adapter_attr.manufacturer)); + +	strncpy(hba_attr->serial_num, adapter_attr.serial_num, +		sizeof(adapter_attr.serial_num)); + +	strncpy(hba_attr->model, adapter_attr.model, sizeof(hba_attr->model)); + +	strncpy(hba_attr->model_desc, adapter_attr.model_descr, +		sizeof(hba_attr->model_desc)); + +	strncpy(hba_attr->hw_version, adapter_attr.hw_ver, +		sizeof(hba_attr->hw_version)); + +	strncpy(hba_attr->driver_version, (char *)driver_info->version, +		sizeof(hba_attr->driver_version)); + +	strncpy(hba_attr->option_rom_ver, adapter_attr.optrom_ver, +		sizeof(hba_attr->option_rom_ver)); + +	strncpy(hba_attr->fw_version, adapter_attr.fw_ver, +		sizeof(hba_attr->fw_version)); + +	strncpy(hba_attr->os_name, driver_info->host_os_name, +		sizeof(hba_attr->os_name)); + +	/* +	 * If there is a patch level, append it to the os name along with a +	 * separator +	 */ +	if (driver_info->host_os_patch[0] != '\0') { +		strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, +			sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); +		strncat(hba_attr->os_name, driver_info->host_os_patch, +			sizeof(driver_info->host_os_patch)); +	} + +	hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ); + +} + +void +bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi, +			  struct bfa_fcs_fdmi_port_attr_s *port_attr) +{ +	struct bfa_fcs_port_s *port = fdmi->ms->port; +	struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; +	struct bfa_pport_attr_s pport_attr; + +	bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s)); + +	/* +	 * get pport attributes from hal +	 */ +	bfa_pport_get_attr(port->fcs->bfa, &pport_attr); + +	/* +	 * get FC4 type Bitmask +	 */ +	fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types); + +	/* +	 * Supported Speeds +	 */ +	port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS); + +	/* +	 * Current Speed +	 */ +	port_attr->curr_speed = bfa_os_htonl(pport_attr.speed); + +	/* +	 * Max PDU Size. +	 */ +	port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ); + +	/* +	 * OS device Name +	 */ +	strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name, +		sizeof(port_attr->os_device_name)); + +	/* +	 * Host name +	 */ +	strncpy(port_attr->host_name, (char *)driver_info->host_machine_name, +		sizeof(port_attr->host_name)); + +} + + +void +bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; + +	fdmi->ms = ms; +	bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline); +} + +void +bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; + +	fdmi->ms = ms; +	bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms) +{ +	struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi; + +	fdmi->ms = ms; +	bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE); +} diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h new file mode 100644 index 00000000000..da8cac093d3 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_AEN_H__ +#define __BFA_AEN_H__ + +#include "defs/bfa_defs_aen.h" + +#define BFA_AEN_MAX_ENTRY   512 + +extern s32 bfa_aen_max_cfg_entry; +struct bfa_aen_s { +	void		*bfad; +	s32		max_entry; +	s32		write_index; +	s32		read_index; +	u32	bfad_num; +	u32	seq_num; +	void		(*aen_cb_notify)(void *bfad); +	void		(*gettimeofday)(struct bfa_timeval_s *tv); +	struct bfa_trc_mod_s 	*trcmod; +	struct bfa_aen_entry_s	list[BFA_AEN_MAX_ENTRY]; /* Must be the last */ +}; + + +/** + * Public APIs + */ +static inline void +bfa_aen_set_max_cfg_entry(int max_entry) +{ +	bfa_aen_max_cfg_entry = max_entry; +} + +static inline s32 +bfa_aen_get_max_cfg_entry(void) +{ +	return bfa_aen_max_cfg_entry; +} + +static inline s32 +bfa_aen_get_meminfo(void) +{ +	return (sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry()); +} + +static inline s32 +bfa_aen_get_wi(struct bfa_aen_s *aen) +{ +	return aen->write_index; +} + +static inline s32 +bfa_aen_get_ri(struct bfa_aen_s *aen) +{ +	return aen->read_index; +} + +static inline s32 +bfa_aen_fetch_count(struct bfa_aen_s *aen, s32 read_index) +{ +	return ((aen->write_index + aen->max_entry) - read_index) +		% aen->max_entry; +} + +s32 bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod, +		void *bfad, u32 inst_id, void (*aen_cb_notify)(void *), +		void (*gettimeofday)(struct bfa_timeval_s *)); + +s32 bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category, +		     int aen_type, union bfa_aen_data_u *aen_data); + +s32 bfa_aen_fetch(struct bfa_aen_s *aen, struct bfa_aen_entry_s *aen_entry, +		      s32 entry_space, s32 rii, s32 *ri_arr, +		      s32 ri_arr_cnt); + +s32 bfa_aen_get_inst(struct bfa_aen_s *aen); + +#endif /* __BFA_AEN_H__ */ diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h new file mode 100644 index 00000000000..260d3ea1cab --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_ADAPTER Module */ +#ifndef	__bfa_aen_adapter_h__ +#define	__bfa_aen_adapter_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_ADAPTER_ADD \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_ADD) +#define BFA_AEN_ADAPTER_REMOVE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_REMOVE) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_audit.h b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h new file mode 100644 index 00000000000..12cd7aab5d5 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_AUDIT Module */ +#ifndef	__bfa_aen_audit_h__ +#define	__bfa_aen_audit_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_AUDIT_AUTH_ENABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_ENABLE) +#define BFA_AEN_AUDIT_AUTH_DISABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_DISABLE) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h new file mode 100644 index 00000000000..507d0b58d14 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_ETHPORT Module */ +#ifndef	__bfa_aen_ethport_h__ +#define	__bfa_aen_ethport_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_ETHPORT_LINKUP \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKUP) +#define BFA_AEN_ETHPORT_LINKDOWN \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKDOWN) +#define BFA_AEN_ETHPORT_ENABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_ENABLE) +#define BFA_AEN_ETHPORT_DISABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_DISABLE) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h new file mode 100644 index 00000000000..71378b446b6 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_IOC Module */ +#ifndef	__bfa_aen_ioc_h__ +#define	__bfa_aen_ioc_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_IOC_HBGOOD \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBGOOD) +#define BFA_AEN_IOC_HBFAIL \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBFAIL) +#define BFA_AEN_IOC_ENABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_ENABLE) +#define BFA_AEN_IOC_DISABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE) +#define BFA_AEN_IOC_FWMISMATCH \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h new file mode 100644 index 00000000000..a7d8ddcfef9 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_ITNIM Module */ +#ifndef	__bfa_aen_itnim_h__ +#define	__bfa_aen_itnim_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_ITNIM_ONLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_ONLINE) +#define BFA_AEN_ITNIM_OFFLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_OFFLINE) +#define BFA_AEN_ITNIM_DISCONNECT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_DISCONNECT) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_lport.h b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h new file mode 100644 index 00000000000..5a8ebb65193 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_LPORT Module */ +#ifndef	__bfa_aen_lport_h__ +#define	__bfa_aen_lport_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_LPORT_NEW \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW) +#define BFA_AEN_LPORT_DELETE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE) +#define BFA_AEN_LPORT_ONLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_ONLINE) +#define BFA_AEN_LPORT_OFFLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_OFFLINE) +#define BFA_AEN_LPORT_DISCONNECT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DISCONNECT) +#define BFA_AEN_LPORT_NEW_PROP \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_PROP) +#define BFA_AEN_LPORT_DELETE_PROP \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_PROP) +#define BFA_AEN_LPORT_NEW_STANDARD \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_STANDARD) +#define BFA_AEN_LPORT_DELETE_STANDARD \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_STANDARD) +#define BFA_AEN_LPORT_NPIV_DUP_WWN \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_DUP_WWN) +#define BFA_AEN_LPORT_NPIV_FABRIC_MAX \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_FABRIC_MAX) +#define BFA_AEN_LPORT_NPIV_UNKNOWN \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_UNKNOWN) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_port.h b/drivers/scsi/bfa/include/aen/bfa_aen_port.h new file mode 100644 index 00000000000..9add905a622 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_port.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_PORT Module */ +#ifndef	__bfa_aen_port_h__ +#define	__bfa_aen_port_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_PORT_ONLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ONLINE) +#define BFA_AEN_PORT_OFFLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_OFFLINE) +#define BFA_AEN_PORT_RLIR \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_RLIR) +#define BFA_AEN_PORT_SFP_INSERT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_INSERT) +#define BFA_AEN_PORT_SFP_REMOVE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_REMOVE) +#define BFA_AEN_PORT_SFP_POM \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_POM) +#define BFA_AEN_PORT_ENABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ENABLE) +#define BFA_AEN_PORT_DISABLE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISABLE) +#define BFA_AEN_PORT_AUTH_ON \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_ON) +#define BFA_AEN_PORT_AUTH_OFF \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_OFF) +#define BFA_AEN_PORT_DISCONNECT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISCONNECT) +#define BFA_AEN_PORT_QOS_NEG \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_QOS_NEG) +#define BFA_AEN_PORT_FABRIC_NAME_CHANGE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_FABRIC_NAME_CHANGE) +#define BFA_AEN_PORT_SFP_ACCESS_ERROR \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_ACCESS_ERROR) +#define BFA_AEN_PORT_SFP_UNSUPPORT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_UNSUPPORT) + +#endif + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_rport.h b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h new file mode 100644 index 00000000000..7e4be1fd5e1 --- /dev/null +++ b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for BFA_AEN_CAT_RPORT Module */ +#ifndef	__bfa_aen_rport_h__ +#define	__bfa_aen_rport_h__ + +#include  <cs/bfa_log.h> +#include  <defs/bfa_defs_aen.h> + +#define BFA_AEN_RPORT_ONLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_ONLINE) +#define BFA_AEN_RPORT_OFFLINE \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_OFFLINE) +#define BFA_AEN_RPORT_DISCONNECT \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_DISCONNECT) +#define BFA_AEN_RPORT_QOS_PRIO \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_PRIO) +#define BFA_AEN_RPORT_QOS_FLOWID \ +	BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_FLOWID) + +#endif + diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h new file mode 100644 index 00000000000..64c1412c570 --- /dev/null +++ b/drivers/scsi/bfa/include/bfa.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_H__ +#define __BFA_H__ + +#include <bfa_os_inc.h> +#include <cs/bfa_debug.h> +#include <cs/bfa_q.h> +#include <cs/bfa_trc.h> +#include <cs/bfa_log.h> +#include <cs/bfa_plog.h> +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_ioc.h> +#include <defs/bfa_defs_iocfc.h> +#include <aen/bfa_aen.h> +#include <bfi/bfi.h> + +struct bfa_s; +#include <bfa_intr_priv.h> + +struct bfa_pcidev_s; + +/** + * PCI devices supported by the current BFA + */ +struct bfa_pciid_s { +	u16        device_id; +	u16        vendor_id; +}; + +extern char     bfa_version[]; + +/** + * BFA Power Mgmt Commands + */ +enum bfa_pm_cmd { +	BFA_PM_CTL_D0 = 0, +	BFA_PM_CTL_D1 = 1, +	BFA_PM_CTL_D2 = 2, +	BFA_PM_CTL_D3 = 3, +}; + +/** + * BFA memory resources + */ +enum bfa_mem_type { +	BFA_MEM_TYPE_KVA = 1,	/*! Kernel Virtual Memory *(non-dma-able) */ +	BFA_MEM_TYPE_DMA = 2,	/*! DMA-able memory */ +	BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA, +}; + +struct bfa_mem_elem_s { +	enum bfa_mem_type mem_type;	/*  see enum bfa_mem_type 	*/ +	u32        mem_len;	/*  Total Length in Bytes	*/ +	u8       	*kva;		/*  kernel virtual address	*/ +	u64        dma;		/*  dma address if DMA memory	*/ +	u8       	*kva_curp;	/*  kva allocation cursor	*/ +	u64        dma_curp;	/*  dma allocation cursor	*/ +}; + +struct bfa_meminfo_s { +	struct bfa_mem_elem_s meminfo[BFA_MEM_TYPE_MAX]; +}; +#define bfa_meminfo_kva(_m)	\ +	(_m)->meminfo[BFA_MEM_TYPE_KVA - 1].kva_curp +#define bfa_meminfo_dma_virt(_m)	\ +	(_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp +#define bfa_meminfo_dma_phys(_m)	\ +	(_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp + +/** + * Generic Scatter Gather Element used by driver + */ +struct bfa_sge_s { +	u32        sg_len; +	void           *sg_addr; +}; + +#define bfa_sge_to_be(__sge) do {                                          \ +	((u32 *)(__sge))[0] = bfa_os_htonl(((u32 *)(__sge))[0]);      \ +	((u32 *)(__sge))[1] = bfa_os_htonl(((u32 *)(__sge))[1]);      \ +	((u32 *)(__sge))[2] = bfa_os_htonl(((u32 *)(__sge))[2]);      \ +} while (0) + + +/* + * bfa stats interfaces + */ +#define bfa_stats(_mod, _stats)	(_mod)->stats._stats ++ + +#define bfa_ioc_get_stats(__bfa, __ioc_stats)	\ +	bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats) +#define bfa_ioc_clear_stats(__bfa)	\ +	bfa_ioc_clr_stats(&(__bfa)->ioc) + +/* + * bfa API functions + */ +void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); +void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); +void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); +void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, +			struct bfa_meminfo_s *meminfo); +void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, +			struct bfa_meminfo_s *meminfo, +			struct bfa_pcidev_s *pcidev); +void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod); +void bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod); +void bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen); +void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog); +void bfa_detach(struct bfa_s *bfa); +void bfa_init(struct bfa_s *bfa); +void bfa_start(struct bfa_s *bfa); +void bfa_stop(struct bfa_s *bfa); +void bfa_attach_fcs(struct bfa_s *bfa); +void bfa_cb_init(void *bfad, bfa_status_t status); +void bfa_cb_stop(void *bfad, bfa_status_t status); +void bfa_cb_updateq(void *bfad, bfa_status_t status); + +bfa_boolean_t bfa_intx(struct bfa_s *bfa); +void bfa_isr_enable(struct bfa_s *bfa); +void bfa_isr_disable(struct bfa_s *bfa); +void bfa_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, +			u32 *num_vecs, u32 *max_vec_bit); +#define bfa_msix(__bfa, __vec) (__bfa)->msix.handler[__vec](__bfa, __vec) + +void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q); +void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q); +void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q); + +typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status); +void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr); +bfa_status_t bfa_iocfc_get_stats(struct bfa_s *bfa, +			struct bfa_iocfc_stats_s *stats, +			bfa_cb_ioc_t cbfn, void *cbarg); +bfa_status_t bfa_iocfc_clear_stats(struct bfa_s *bfa, +			bfa_cb_ioc_t cbfn, void *cbarg); +void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr); + +void bfa_adapter_get_attr(struct bfa_s *bfa, +			struct bfa_adapter_attr_s *ad_attr); +u64 bfa_adapter_get_id(struct bfa_s *bfa); + +bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa, +			struct bfa_iocfc_intr_attr_s *attr); + +void bfa_iocfc_enable(struct bfa_s *bfa); +void bfa_iocfc_disable(struct bfa_s *bfa); +void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); +void bfa_cb_ioc_disable(void *bfad); +void bfa_timer_tick(struct bfa_s *bfa); +#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout)	\ +	bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout) + +/* + * BFA debug API functions + */ +bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen); +bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen); + +#include "bfa_priv.h" + +#endif /* __BFA_H__ */ diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h new file mode 100644 index 00000000000..04789795fa5 --- /dev/null +++ b/drivers/scsi/bfa/include/bfa_fcpim.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCPIM_H__ +#define __BFA_FCPIM_H__ + +#include <bfa.h> +#include <bfa_svc.h> +#include <bfi/bfi_fcpim.h> +#include <defs/bfa_defs_fcpim.h> + +/* + * forward declarations + */ +struct bfa_itnim_s; +struct bfa_ioim_s; +struct bfa_tskim_s; +struct bfad_ioim_s; +struct bfad_tskim_s; + +/* + * bfa fcpim module API functions + */ +void		bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); +u16	bfa_fcpim_path_tov_get(struct bfa_s *bfa); +void		bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth); +u16	bfa_fcpim_qdepth_get(struct bfa_s *bfa); +bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa, +			struct bfa_fcpim_stats_s *modstats); +bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa); + +/* + * bfa itnim API functions + */ +struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa, +					struct bfa_rport_s *rport, void *itnim); +void		bfa_itnim_delete(struct bfa_itnim_s *itnim); +void		bfa_itnim_online(struct bfa_itnim_s *itnim, +				 bfa_boolean_t seq_rec); +void		bfa_itnim_offline(struct bfa_itnim_s *itnim); +void		bfa_itnim_get_stats(struct bfa_itnim_s *itnim, +			struct bfa_itnim_hal_stats_s *stats); +void		bfa_itnim_clear_stats(struct bfa_itnim_s *itnim); + + +/** + * 		BFA completion callback for bfa_itnim_online(). + * + * @param[in]		itnim		FCS or driver itnim instance + * + * return None + */ +void            bfa_cb_itnim_online(void *itnim); + +/** + * 		BFA completion callback for bfa_itnim_offline(). + * + * @param[in]		itnim		FCS or driver itnim instance + * + * return None + */ +void            bfa_cb_itnim_offline(void *itnim); +void            bfa_cb_itnim_tov_begin(void *itnim); +void            bfa_cb_itnim_tov(void *itnim); + +/** + * 		BFA notification to FCS/driver for second level error recovery. + * + * Atleast one I/O request has timedout and target is unresponsive to + * repeated abort requests. Second level error recovery should be initiated + * by starting implicit logout and recovery procedures. + * + * @param[in]		itnim		FCS or driver itnim instance + * + * return None + */ +void            bfa_cb_itnim_sler(void *itnim); + +/* + * bfa ioim API functions + */ +struct bfa_ioim_s	*bfa_ioim_alloc(struct bfa_s *bfa, +					struct bfad_ioim_s *dio, +					struct bfa_itnim_s *itnim, +					u16 nsgles); + +void		bfa_ioim_free(struct bfa_ioim_s *ioim); +void		bfa_ioim_start(struct bfa_ioim_s *ioim); +void		bfa_ioim_abort(struct bfa_ioim_s *ioim); +void 		bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, +				      bfa_boolean_t iotov); + + +/** + * 		I/O completion notification. + * + * @param[in]		dio			driver IO structure + * @param[in]		io_status		IO completion status + * @param[in]		scsi_status		SCSI status returned by target + * @param[in]		sns_len			SCSI sense length, 0 if none + * @param[in]		sns_info		SCSI sense data, if any + * @param[in]		residue			Residual length + * + * @return None + */ +void            bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio, +				  enum bfi_ioim_status io_status, +				  u8 scsi_status, int sns_len, +				  u8 *sns_info, s32 residue); + +/** + * 		I/O good completion notification. + * + * @param[in]		dio			driver IO structure + * + * @return None + */ +void            bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio); + +/** + * 		I/O abort completion notification + * + * @param[in]		dio			driver IO that was aborted + * + * @return None + */ +void            bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio); +void		bfa_cb_ioim_resfree(void *hcb_bfad); + +void 			bfa_cb_ioim_resfree(void *hcb_bfad); + +/* + * bfa tskim API functions + */ +struct bfa_tskim_s	*bfa_tskim_alloc(struct bfa_s *bfa, +					struct bfad_tskim_s *dtsk); +void		bfa_tskim_free(struct bfa_tskim_s *tskim); +void		bfa_tskim_start(struct bfa_tskim_s *tskim, +				struct bfa_itnim_s *itnim, lun_t lun, +				enum fcp_tm_cmnd tm, u8 t_secs); +void		bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, +				  enum bfi_tskim_status tsk_status); + +#endif /* __BFA_FCPIM_H__ */ + diff --git a/drivers/scsi/bfa/include/bfa_fcptm.h b/drivers/scsi/bfa/include/bfa_fcptm.h new file mode 100644 index 00000000000..5f5ffe0bb1b --- /dev/null +++ b/drivers/scsi/bfa/include/bfa_fcptm.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCPTM_H__ +#define __BFA_FCPTM_H__ + +#include <bfa.h> +#include <bfa_svc.h> +#include <bfi/bfi_fcptm.h> + +/* + * forward declarations + */ +struct bfa_tin_s; +struct bfa_iotm_s; +struct bfa_tsktm_s; + +/* + * bfa fcptm module API functions + */ +void bfa_fcptm_path_tov_set(struct bfa_s *bfa, u16 path_tov); +u16 bfa_fcptm_path_tov_get(struct bfa_s *bfa); +void bfa_fcptm_qdepth_set(struct bfa_s *bfa, u16 q_depth); +u16 bfa_fcptm_qdepth_get(struct bfa_s *bfa); + +/* + * bfa tin API functions + */ +void bfa_tin_get_stats(struct bfa_tin_s *tin, struct bfa_tin_stats_s *stats); +void bfa_tin_clear_stats(struct bfa_tin_s *tin); + +#endif /* __BFA_FCPTM_H__ */ + diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h new file mode 100644 index 00000000000..0c80b74f72e --- /dev/null +++ b/drivers/scsi/bfa/include/bfa_svc.h @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_SVC_H__ +#define __BFA_SVC_H__ + +/* + * forward declarations + */ +struct bfa_fcxp_s; + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_pport.h> +#include <defs/bfa_defs_rport.h> +#include <defs/bfa_defs_qos.h> +#include <cs/bfa_sm.h> +#include <bfa.h> + +/** + * 		BFA rport information. + */ +struct bfa_rport_info_s { +	u16        max_frmsz;	/*  max rcv pdu size               */ +	u32        pid : 24,	/*  remote port ID                 */ +			lp_tag : 8; +	u32        local_pid : 24,	/*  local port ID		    */ +			cisc : 8;	/*  CIRO supported		    */ +	u8         fc_class;	/*  supported FC classes. enum fc_cos */ +	u8         vf_en;		/*  virtual fabric enable          */ +	u16        vf_id;		/*  virtual fabric ID              */ +	enum bfa_pport_speed speed;	/*  Rport's current speed	    */ +}; + +/** + * BFA rport data structure + */ +struct bfa_rport_s { +	struct list_head        qe;	  /*  queue element */ +	bfa_sm_t	      sm; 	  /*  state machine */ +	struct bfa_s          *bfa;	  /*  backpointer to BFA */ +	void                  *rport_drv; /*  fcs/driver rport object */ +	u16              fw_handle; /*  firmware rport handle */ +	u16              rport_tag; /*  BFA rport tag */ +	struct bfa_rport_info_s rport_info; /*  rport info from *fcs/driver */ +	struct bfa_reqq_wait_s reqq_wait; /*  to wait for room in reqq */ +	struct bfa_cb_qe_s    hcb_qe;	 /*  BFA callback qelem */ +	struct bfa_rport_hal_stats_s stats; /*  BFA rport statistics  */ +	struct bfa_rport_qos_attr_s  qos_attr; +	union a { +		bfa_status_t    status;	 /*  f/w status */ +		void            *fw_msg; /*  QoS scn event */ +	} event_arg; +}; +#define BFA_RPORT_FC_COS(_rport)	((_rport)->rport_info.fc_class) + +/** + * Send completion callback. + */ +typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp, +			void *cbarg, enum bfa_status req_status, +			u32 rsp_len, u32 resid_len, +			struct fchs_s *rsp_fchs); + +/** + * BFA fcxp allocation (asynchronous) + */ +typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp); + +struct bfa_fcxp_wqe_s { +	struct list_head         qe; +	bfa_fcxp_alloc_cbfn_t  alloc_cbfn; +	void           *alloc_cbarg; +}; + +typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid); +typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid); + +#define BFA_UF_BUFSZ	(2 * 1024 + 256) + +/** + * @todo private + */ +struct bfa_uf_buf_s { +	u8         d[BFA_UF_BUFSZ]; +}; + + +struct bfa_uf_s { +	struct list_head	qe;		/*  queue element	  */ +	struct bfa_s	*bfa;		/*  bfa instance	  */ +	u16        uf_tag;		/*  identifying tag f/w messages */ +	u16        vf_id; +	u16        src_rport_handle; +	u16        rsvd; +	u8        	*data_ptr; +	u16        data_len;	/*  actual receive length	  */ +	u16        pb_len;		/*  posted buffer length	  */ +	void           	*buf_kva;	/*  buffer virtual address	  */ +	u64        buf_pa;		/*  buffer physical address	  */ +	struct bfa_cb_qe_s    hcb_qe;	/*  comp: BFA comp qelem	  */ +	struct bfa_sge_s   	sges[BFI_SGE_INLINE_MAX]; +}; + +typedef void (*bfa_cb_pport_t) (void *cbarg, enum bfa_status status); + +/** + * bfa lport login/logout service interface + */ +struct bfa_lps_s { +	struct list_head	qe;		/*  queue element */ +	struct bfa_s	*bfa;		/*  parent bfa instance	*/ +	bfa_sm_t	sm;		/*  finite state machine	*/ +	u8		lp_tag;		/*  lport tag			*/ +	u8		reqq;		/*  lport request queue	*/ +	u8		alpa;		/*  ALPA for loop topologies	*/ +	u32	lp_pid;		/*  lport port ID		*/ +	bfa_boolean_t	fdisc;		/*  send FDISC instead of FLOGI*/ +	bfa_boolean_t	auth_en;	/*  enable authentication	*/ +	bfa_boolean_t	auth_req;	/*  authentication required	*/ +	bfa_boolean_t	npiv_en;	/*  NPIV is allowed by peer	*/ +	bfa_boolean_t	fport;		/*  attached peer is F_PORT	*/ +	bfa_boolean_t	brcd_switch;/*  attached peer is brcd switch	*/ +	bfa_status_t	status;		/*  login status		*/ +	u16	pdusz;		/*  max receive PDU size 	*/ +	u16	pr_bbcred;	/*  BB_CREDIT from peer 	*/ +	u8		lsrjt_rsn;	/*  LSRJT reason		*/ +	u8		lsrjt_expl;	/*  LSRJT explanation		*/ +	wwn_t		pwwn;		/*  port wwn of lport		*/ +	wwn_t		nwwn;		/*  node wwn of lport		*/ +	wwn_t		pr_pwwn;	/*  port wwn of lport peer	*/ +	wwn_t		pr_nwwn;	/*  node wwn of lport peer	*/ +	mac_t		lp_mac;		/*  fpma/spma MAC for lport	*/ +	mac_t		fcf_mac;	/*  FCF MAC of lport		*/ +	struct bfa_reqq_wait_s	wqe;	/*  request wait queue element	*/ +	void		*uarg;		/*  user callback arg		*/ +	struct bfa_cb_qe_s hcb_qe;	/*  comp: callback qelem	*/ +	struct bfi_lps_login_rsp_s *loginrsp; +	bfa_eproto_status_t	ext_status; +}; + +/* + * bfa pport API functions + */ +bfa_status_t bfa_pport_enable(struct bfa_s *bfa); +bfa_status_t bfa_pport_disable(struct bfa_s *bfa); +bfa_status_t bfa_pport_cfg_speed(struct bfa_s *bfa, +			enum bfa_pport_speed speed); +enum bfa_pport_speed bfa_pport_get_speed(struct bfa_s *bfa); +bfa_status_t bfa_pport_cfg_topology(struct bfa_s *bfa, +			enum bfa_pport_topology topo); +enum bfa_pport_topology bfa_pport_get_topology(struct bfa_s *bfa); +bfa_status_t bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); +bfa_boolean_t bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); +u8 bfa_pport_get_myalpa(struct bfa_s *bfa); +bfa_status_t bfa_pport_clr_hardalpa(struct bfa_s *bfa); +bfa_status_t bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize); +u16 bfa_pport_get_maxfrsize(struct bfa_s *bfa); +u32 bfa_pport_mypid(struct bfa_s *bfa); +u8 bfa_pport_get_rx_bbcredit(struct bfa_s *bfa); +bfa_status_t bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap); +bfa_status_t bfa_pport_trunk_disable(struct bfa_s *bfa); +bfa_boolean_t bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap); +void bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr); +wwn_t bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node); +bfa_status_t bfa_pport_get_stats(struct bfa_s *bfa, +			union bfa_pport_stats_u *stats, +			bfa_cb_pport_t cbfn, void *cbarg); +bfa_status_t bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, +			void *cbarg); +void bfa_pport_event_register(struct bfa_s *bfa, +			void (*event_cbfn) (void *cbarg, +			bfa_pport_event_t event), void *event_cbarg); +bfa_boolean_t bfa_pport_is_disabled(struct bfa_s *bfa); +void bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off); +void bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off); +bfa_status_t bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, +			enum bfa_pport_speed speed); +enum bfa_pport_speed bfa_pport_get_ratelim_speed(struct bfa_s *bfa); + +void bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit); +void bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status); +void bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon, +			bfa_boolean_t link_e2e_beacon); +void bfa_cb_pport_event(void *cbarg, bfa_pport_event_t event); +void bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr); +void bfa_pport_qos_get_vc_attr(struct bfa_s *bfa, +			struct bfa_qos_vc_attr_s *qos_vc_attr); +bfa_status_t bfa_pport_get_qos_stats(struct bfa_s *bfa, +			union bfa_pport_stats_u *stats, +			bfa_cb_pport_t cbfn, void *cbarg); +bfa_status_t bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, +			void *cbarg); +bfa_boolean_t     bfa_pport_is_ratelim(struct bfa_s *bfa); +bfa_boolean_t	bfa_pport_is_linkup(struct bfa_s *bfa); + +/* + * bfa rport API functions + */ +struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv); +void bfa_rport_delete(struct bfa_rport_s *rport); +void bfa_rport_online(struct bfa_rport_s *rport, +			struct bfa_rport_info_s *rport_info); +void bfa_rport_offline(struct bfa_rport_s *rport); +void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed); +void bfa_rport_get_stats(struct bfa_rport_s *rport, +			struct bfa_rport_hal_stats_s *stats); +void bfa_rport_clear_stats(struct bfa_rport_s *rport); +void bfa_cb_rport_online(void *rport); +void bfa_cb_rport_offline(void *rport); +void bfa_cb_rport_qos_scn_flowid(void *rport, +			struct bfa_rport_qos_attr_s old_qos_attr, +			struct bfa_rport_qos_attr_s new_qos_attr); +void bfa_cb_rport_qos_scn_prio(void *rport, +			struct bfa_rport_qos_attr_s old_qos_attr, +			struct bfa_rport_qos_attr_s new_qos_attr); +void bfa_rport_get_qos_attr(struct bfa_rport_s *rport, +			struct bfa_rport_qos_attr_s *qos_attr); + +/* + * bfa fcxp API functions + */ +struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa, +			int nreq_sgles, int nrsp_sgles, +			bfa_fcxp_get_sgaddr_t get_req_sga, +			bfa_fcxp_get_sglen_t get_req_sglen, +			bfa_fcxp_get_sgaddr_t get_rsp_sga, +			bfa_fcxp_get_sglen_t get_rsp_sglen); +void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, +			bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *cbarg); +void bfa_fcxp_walloc_cancel(struct bfa_s *bfa, +			struct bfa_fcxp_wqe_s *wqe); +void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp); + +void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp); +void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp); + +void bfa_fcxp_free(struct bfa_fcxp_s *fcxp); + +void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, +			struct bfa_rport_s *rport, u16 vf_id, u8 lp_tag, +			bfa_boolean_t cts, enum fc_cos cos, +			u32 reqlen, struct fchs_s *fchs, +			bfa_cb_fcxp_send_t cbfn, +			void *cbarg, +			u32 rsp_maxlen, u8 rsp_timeout); +bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); +u32        bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); +u32	bfa_fcxp_get_maxrsp(struct bfa_s *bfa); + +static inline void * +bfa_uf_get_frmbuf(struct bfa_uf_s *uf) +{ +	return uf->data_ptr; +} + +static inline   u16 +bfa_uf_get_frmlen(struct bfa_uf_s *uf) +{ +	return uf->data_len; +} + +/** + *      Callback prototype for unsolicited frame receive handler. + * + * @param[in]           cbarg           callback arg for receive handler + * @param[in]           uf              unsolicited frame descriptor + * + * @return None + */ +typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); + +/* + * bfa uf API functions + */ +void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, +			void *cbarg); +void bfa_uf_free(struct bfa_uf_s *uf); + +/** + * bfa lport service api + */ + +struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); +void bfa_lps_delete(struct bfa_lps_s *lps); +void bfa_lps_discard(struct bfa_lps_s *lps); +void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, +		   wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en); +void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, +		   wwn_t nwwn); +void bfa_lps_flogo(struct bfa_lps_s *lps); +void bfa_lps_fdisclogo(struct bfa_lps_s *lps); +u8 bfa_lps_get_tag(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps); +bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps); +bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps); +u32 bfa_lps_get_pid(struct bfa_lps_s *lps); +u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); +u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps); +wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps); +wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps); +u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps); +u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps); +void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); +void bfa_cb_lps_flogo_comp(void *bfad, void *uarg); +void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); +void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); + +#endif /* __BFA_SVC_H__ */ + diff --git a/drivers/scsi/bfa/include/bfa_timer.h b/drivers/scsi/bfa/include/bfa_timer.h new file mode 100644 index 00000000000..e407103fa56 --- /dev/null +++ b/drivers/scsi/bfa/include/bfa_timer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_TIMER_H__ +#define __BFA_TIMER_H__ + +#include <bfa_os_inc.h> +#include <cs/bfa_q.h> + +struct bfa_s; + +typedef void (*bfa_timer_cbfn_t)(void *); + +/** + * BFA timer data structure + */ +struct bfa_timer_s { +	struct list_head	qe; +	bfa_timer_cbfn_t timercb; +	void            *arg; +	int             timeout;	/**< in millisecs. */ +}; + +/** + * Timer module structure + */ +struct bfa_timer_mod_s { +	struct list_head timer_q; +}; + +#define BFA_TIMER_FREQ 500 /**< specified in millisecs */ + +void bfa_timer_beat(struct bfa_timer_mod_s *mod); +void bfa_timer_init(struct bfa_timer_mod_s *mod); +void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, +			bfa_timer_cbfn_t timercb, void *arg, +			unsigned int timeout); +void bfa_timer_stop(struct bfa_timer_s *timer); + +#endif /* __BFA_TIMER_H__ */ diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h new file mode 100644 index 00000000000..6cadfe0d4ba --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_H__ +#define __BFI_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_status.h> + +#pragma pack(1) + +/** + * Msg header common to all msgs + */ +struct bfi_mhdr_s { +	u8         msg_class;	/*  @ref bfi_mclass_t	    */ +	u8         msg_id;		/*  msg opcode with in the class   */ +	union { +		struct { +			u8         rsvd; +			u8         lpu_id;	/*  msg destination	    */ +		} h2i; +		u16        i2htok;	/*  token in msgs to host	    */ +	} mtag; +}; + +#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do {		\ +	(_mh).msg_class 		= (_mc);      \ +	(_mh).msg_id			= (_op);      \ +	(_mh).mtag.h2i.lpu_id	= (_lpuid);      \ +} while (0) + +#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do {		\ +	(_mh).msg_class 		= (_mc);      \ +	(_mh).msg_id			= (_op);      \ +	(_mh).mtag.i2htok		= (_i2htok);      \ +} while (0) + +/* + * Message opcodes: 0-127 to firmware, 128-255 to host + */ +#define BFI_I2H_OPCODE_BASE	128 +#define BFA_I2HM(_x) 			((_x) + BFI_I2H_OPCODE_BASE) + +/** + **************************************************************************** + * + * Scatter Gather Element and Page definition + * + **************************************************************************** + */ + +#define BFI_SGE_INLINE	1 +#define BFI_SGE_INLINE_MAX	(BFI_SGE_INLINE + 1) + +/** + * SG Flags + */ +enum { +	BFI_SGE_DATA	= 0,	/*  data address, not last	     */ +	BFI_SGE_DATA_CPL	= 1,	/*  data addr, last in current page */ +	BFI_SGE_DATA_LAST	= 3,	/*  data address, last		     */ +	BFI_SGE_LINK	= 2,	/*  link address		     */ +	BFI_SGE_PGDLEN	= 2,	/*  cumulative data length for page */ +}; + +/** + * DMA addresses + */ +union bfi_addr_u { +	struct { +		u32        addr_lo; +		u32        addr_hi; +	} a32; +}; + +/** + * Scatter Gather Element + */ +struct bfi_sge_s { +#ifdef __BIGENDIAN +	u32        flags	: 2, +			rsvd	: 2, +			sg_len	: 28; +#else +	u32        sg_len	: 28, +			rsvd	: 2, +			flags	: 2; +#endif +	union bfi_addr_u sga; +}; + +/** + * Scatter Gather Page + */ +#define BFI_SGPG_DATA_SGES		7 +#define BFI_SGPG_SGES_MAX		(BFI_SGPG_DATA_SGES + 1) +#define BFI_SGPG_RSVD_WD_LEN	8 +struct bfi_sgpg_s { +	struct bfi_sge_s sges[BFI_SGPG_SGES_MAX]; +	u32	rsvd[BFI_SGPG_RSVD_WD_LEN]; +}; + +/* + * Large Message structure - 128 Bytes size Msgs + */ +#define BFI_LMSG_SZ		128 +#define BFI_LMSG_PL_WSZ	\ +			((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4) + +struct bfi_msg_s { +	struct bfi_mhdr_s mhdr; +	u32	pl[BFI_LMSG_PL_WSZ]; +}; + +/** + * Mailbox message structure + */ +#define BFI_MBMSG_SZ		7 +struct bfi_mbmsg_s { +	struct bfi_mhdr_s	mh; +	u32		pl[BFI_MBMSG_SZ]; +}; + +/** + * Message Classes + */ +enum bfi_mclass { +	BFI_MC_IOC		= 1,	/*  IO Controller (IOC)	    */ +	BFI_MC_DIAG		= 2,	/*  Diagnostic Msgs		    */ +	BFI_MC_FLASH		= 3,	/*  Flash message class	    */ +	BFI_MC_CEE		= 4, +	BFI_MC_FC_PORT		= 5,	/*  FC port		   	    */ +	BFI_MC_IOCFC		= 6,	/*  FC - IO Controller (IOC)	    */ +	BFI_MC_LL		= 7,	/*  Link Layer		 	    */ +	BFI_MC_UF		= 8,	/*  Unsolicited frame receive	    */ +	BFI_MC_FCXP		= 9,	/*  FC Transport		    */ +	BFI_MC_LPS		= 10,	/*  lport fc login services	    */ +	BFI_MC_RPORT		= 11,	/*  Remote port		    */ +	BFI_MC_ITNIM		= 12,	/*  I-T nexus (Initiator mode)	    */ +	BFI_MC_IOIM_READ	= 13,	/*  read IO (Initiator mode)	    */ +	BFI_MC_IOIM_WRITE	= 14,	/*  write IO (Initiator mode)	    */ +	BFI_MC_IOIM_IO		= 15,	/*  IO (Initiator mode)	    */ +	BFI_MC_IOIM		= 16,	/*  IO (Initiator mode)	    */ +	BFI_MC_IOIM_IOCOM	= 17,	/*  good IO completion		    */ +	BFI_MC_TSKIM		= 18,	/*  Initiator Task management	    */ +	BFI_MC_SBOOT		= 19,	/*  SAN boot services		    */ +	BFI_MC_IPFC		= 20,	/*  IP over FC Msgs		    */ +	BFI_MC_PORT		= 21,	/*  Physical port		    */ +	BFI_MC_MAX		= 32 +}; + +#define BFI_IOC_MAX_CQS		4 +#define BFI_IOC_MAX_CQS_ASIC	8 +#define BFI_IOC_MSGLEN_MAX	32	/* 32 bytes */ + +#pragma pack() + +#endif /* __BFI_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_boot.h b/drivers/scsi/bfa/include/bfi/bfi_boot.h new file mode 100644 index 00000000000..5955afe7d10 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_boot.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +/* + * bfi_boot.h + */ + +#ifndef __BFI_BOOT_H__ +#define __BFI_BOOT_H__ + +#define BFI_BOOT_TYPE_OFF		8 +#define BFI_BOOT_PARAM_OFF		12 + +#define BFI_BOOT_TYPE_NORMAL 		0	/* param is device id */ +#define	BFI_BOOT_TYPE_FLASH		1 +#define	BFI_BOOT_TYPE_MEMTEST		2 + +#define BFI_BOOT_MEMTEST_RES_ADDR   0x900 +#define BFI_BOOT_MEMTEST_RES_SIG    0xA0A1A2A3 + +#endif diff --git a/drivers/scsi/bfa/include/bfi/bfi_cbreg.h b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h new file mode 100644 index 00000000000..b3bb52b565b --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* + * bfi_cbreg.h crossbow host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CBREG_H__ +#define __BFI_CBREG_H__ + + +#define HOSTFN0_INT_STATUS               0x00014000 +#define __HOSTFN0_INT_STATUS_LVL_MK      0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH      20 +#define __HOSTFN0_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P           0x000fffff +#define HOSTFN0_INT_MSK                  0x00014004 +#define HOST_PAGE_NUM_FN0                0x00014008 +#define __HOST_PAGE_NUM_FN               0x000001ff +#define HOSTFN1_INT_STATUS               0x00014100 +#define __HOSTFN1_INT_STAT_LVL_MK        0x00f00000 +#define __HOSTFN1_INT_STAT_LVL_SH        20 +#define __HOSTFN1_INT_STAT_LVL(_v)       ((_v) << __HOSTFN1_INT_STAT_LVL_SH) +#define __HOSTFN1_INT_STAT_P             0x000fffff +#define HOSTFN1_INT_MSK                  0x00014104 +#define HOST_PAGE_NUM_FN1                0x00014108 +#define APP_PLL_400_CTL_REG              0x00014204 +#define __P_400_PLL_LOCK                 0x80000000 +#define __APP_PLL_400_SRAM_USE_100MHZ    0x00100000 +#define __APP_PLL_400_RESET_TIMER_MK     0x000e0000 +#define __APP_PLL_400_RESET_TIMER_SH     17 +#define __APP_PLL_400_RESET_TIMER(_v)    ((_v) << __APP_PLL_400_RESET_TIMER_SH) +#define __APP_PLL_400_LOGIC_SOFT_RESET   0x00010000 +#define __APP_PLL_400_CNTLMT0_1_MK       0x0000c000 +#define __APP_PLL_400_CNTLMT0_1_SH       14 +#define __APP_PLL_400_CNTLMT0_1(_v)      ((_v) << __APP_PLL_400_CNTLMT0_1_SH) +#define __APP_PLL_400_JITLMT0_1_MK       0x00003000 +#define __APP_PLL_400_JITLMT0_1_SH       12 +#define __APP_PLL_400_JITLMT0_1(_v)      ((_v) << __APP_PLL_400_JITLMT0_1_SH) +#define __APP_PLL_400_HREF               0x00000800 +#define __APP_PLL_400_HDIV               0x00000400 +#define __APP_PLL_400_P0_1_MK            0x00000300 +#define __APP_PLL_400_P0_1_SH            8 +#define __APP_PLL_400_P0_1(_v)           ((_v) << __APP_PLL_400_P0_1_SH) +#define __APP_PLL_400_Z0_2_MK            0x000000e0 +#define __APP_PLL_400_Z0_2_SH            5 +#define __APP_PLL_400_Z0_2(_v)           ((_v) << __APP_PLL_400_Z0_2_SH) +#define __APP_PLL_400_RSEL200500         0x00000010 +#define __APP_PLL_400_ENARST             0x00000008 +#define __APP_PLL_400_BYPASS             0x00000004 +#define __APP_PLL_400_LRESETN            0x00000002 +#define __APP_PLL_400_ENABLE             0x00000001 +#define APP_PLL_212_CTL_REG              0x00014208 +#define __P_212_PLL_LOCK                 0x80000000 +#define __APP_PLL_212_RESET_TIMER_MK     0x000e0000 +#define __APP_PLL_212_RESET_TIMER_SH     17 +#define __APP_PLL_212_RESET_TIMER(_v)    ((_v) << __APP_PLL_212_RESET_TIMER_SH) +#define __APP_PLL_212_LOGIC_SOFT_RESET   0x00010000 +#define __APP_PLL_212_CNTLMT0_1_MK       0x0000c000 +#define __APP_PLL_212_CNTLMT0_1_SH       14 +#define __APP_PLL_212_CNTLMT0_1(_v)      ((_v) << __APP_PLL_212_CNTLMT0_1_SH) +#define __APP_PLL_212_JITLMT0_1_MK       0x00003000 +#define __APP_PLL_212_JITLMT0_1_SH       12 +#define __APP_PLL_212_JITLMT0_1(_v)      ((_v) << __APP_PLL_212_JITLMT0_1_SH) +#define __APP_PLL_212_HREF               0x00000800 +#define __APP_PLL_212_HDIV               0x00000400 +#define __APP_PLL_212_P0_1_MK            0x00000300 +#define __APP_PLL_212_P0_1_SH            8 +#define __APP_PLL_212_P0_1(_v)           ((_v) << __APP_PLL_212_P0_1_SH) +#define __APP_PLL_212_Z0_2_MK            0x000000e0 +#define __APP_PLL_212_Z0_2_SH            5 +#define __APP_PLL_212_Z0_2(_v)           ((_v) << __APP_PLL_212_Z0_2_SH) +#define __APP_PLL_212_RSEL200500         0x00000010 +#define __APP_PLL_212_ENARST             0x00000008 +#define __APP_PLL_212_BYPASS             0x00000004 +#define __APP_PLL_212_LRESETN            0x00000002 +#define __APP_PLL_212_ENABLE             0x00000001 +#define HOST_SEM0_REG                    0x00014230 +#define __HOST_SEMAPHORE                 0x00000001 +#define HOST_SEM1_REG                    0x00014234 +#define HOST_SEM2_REG                    0x00014238 +#define HOST_SEM3_REG                    0x0001423c +#define HOST_SEM0_INFO_REG               0x00014240 +#define HOST_SEM1_INFO_REG               0x00014244 +#define HOST_SEM2_INFO_REG               0x00014248 +#define HOST_SEM3_INFO_REG               0x0001424c +#define HOSTFN0_LPU0_CMD_STAT            0x00019000 +#define __HOSTFN0_LPU0_MBOX_INFO_MK      0xfffffffe +#define __HOSTFN0_LPU0_MBOX_INFO_SH      1 +#define __HOSTFN0_LPU0_MBOX_INFO(_v)     ((_v) << __HOSTFN0_LPU0_MBOX_INFO_SH) +#define __HOSTFN0_LPU0_MBOX_CMD_STATUS   0x00000001 +#define LPU0_HOSTFN0_CMD_STAT            0x00019008 +#define __LPU0_HOSTFN0_MBOX_INFO_MK      0xfffffffe +#define __LPU0_HOSTFN0_MBOX_INFO_SH      1 +#define __LPU0_HOSTFN0_MBOX_INFO(_v)     ((_v) << __LPU0_HOSTFN0_MBOX_INFO_SH) +#define __LPU0_HOSTFN0_MBOX_CMD_STATUS   0x00000001 +#define HOSTFN1_LPU1_CMD_STAT            0x00019014 +#define __HOSTFN1_LPU1_MBOX_INFO_MK      0xfffffffe +#define __HOSTFN1_LPU1_MBOX_INFO_SH      1 +#define __HOSTFN1_LPU1_MBOX_INFO(_v)     ((_v) << __HOSTFN1_LPU1_MBOX_INFO_SH) +#define __HOSTFN1_LPU1_MBOX_CMD_STATUS   0x00000001 +#define LPU1_HOSTFN1_CMD_STAT            0x0001901c +#define __LPU1_HOSTFN1_MBOX_INFO_MK      0xfffffffe +#define __LPU1_HOSTFN1_MBOX_INFO_SH      1 +#define __LPU1_HOSTFN1_MBOX_INFO(_v)     ((_v) << __LPU1_HOSTFN1_MBOX_INFO_SH) +#define __LPU1_HOSTFN1_MBOX_CMD_STATUS   0x00000001 +#define CPE_Q0_DEPTH                     0x00010014 +#define CPE_Q0_PI                        0x0001001c +#define CPE_Q0_CI                        0x00010020 +#define CPE_Q1_DEPTH                     0x00010034 +#define CPE_Q1_PI                        0x0001003c +#define CPE_Q1_CI                        0x00010040 +#define CPE_Q2_DEPTH                     0x00010054 +#define CPE_Q2_PI                        0x0001005c +#define CPE_Q2_CI                        0x00010060 +#define CPE_Q3_DEPTH                     0x00010074 +#define CPE_Q3_PI                        0x0001007c +#define CPE_Q3_CI                        0x00010080 +#define CPE_Q4_DEPTH                     0x00010094 +#define CPE_Q4_PI                        0x0001009c +#define CPE_Q4_CI                        0x000100a0 +#define CPE_Q5_DEPTH                     0x000100b4 +#define CPE_Q5_PI                        0x000100bc +#define CPE_Q5_CI                        0x000100c0 +#define CPE_Q6_DEPTH                     0x000100d4 +#define CPE_Q6_PI                        0x000100dc +#define CPE_Q6_CI                        0x000100e0 +#define CPE_Q7_DEPTH                     0x000100f4 +#define CPE_Q7_PI                        0x000100fc +#define CPE_Q7_CI                        0x00010100 +#define RME_Q0_DEPTH                     0x00011014 +#define RME_Q0_PI                        0x0001101c +#define RME_Q0_CI                        0x00011020 +#define RME_Q1_DEPTH                     0x00011034 +#define RME_Q1_PI                        0x0001103c +#define RME_Q1_CI                        0x00011040 +#define RME_Q2_DEPTH                     0x00011054 +#define RME_Q2_PI                        0x0001105c +#define RME_Q2_CI                        0x00011060 +#define RME_Q3_DEPTH                     0x00011074 +#define RME_Q3_PI                        0x0001107c +#define RME_Q3_CI                        0x00011080 +#define RME_Q4_DEPTH                     0x00011094 +#define RME_Q4_PI                        0x0001109c +#define RME_Q4_CI                        0x000110a0 +#define RME_Q5_DEPTH                     0x000110b4 +#define RME_Q5_PI                        0x000110bc +#define RME_Q5_CI                        0x000110c0 +#define RME_Q6_DEPTH                     0x000110d4 +#define RME_Q6_PI                        0x000110dc +#define RME_Q6_CI                        0x000110e0 +#define RME_Q7_DEPTH                     0x000110f4 +#define RME_Q7_PI                        0x000110fc +#define RME_Q7_CI                        0x00011100 +#define PSS_CTL_REG                      0x00018800 +#define __PSS_I2C_CLK_DIV_MK             0x00030000 +#define __PSS_I2C_CLK_DIV_SH             16 +#define __PSS_I2C_CLK_DIV(_v)            ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE             0x00001000 +#define __PSS_LMEM_RESET                 0x00000200 +#define __PSS_LMEM_INIT_EN               0x00000100 +#define __PSS_LPU1_RESET                 0x00000002 +#define __PSS_LPU0_RESET                 0x00000001 + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX          0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX          0x00000002 +#define __EMPHPRE_AT_4G_FIX              0x00000003 +#define __SFP_TXRATE_EN_FIX              0x00000100 +#define __SFP_RXRATE_EN_FIX              0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ +#define HOSTFN0_LPU_MBOX0_0              0x00019200 +#define HOSTFN1_LPU_MBOX0_8              0x00019260 +#define LPU_HOSTFN0_MBOX0_0              0x00019280 +#define LPU_HOSTFN1_MBOX0_8              0x000192e0 + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG               HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG               HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG               HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG               HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT                 HOST_SEM4_INFO_REG + +#define CPE_Q_DEPTH(__n) \ +	(CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH)) +#define CPE_Q_PI(__n) \ +	(CPE_Q0_PI + (__n) * (CPE_Q1_PI - CPE_Q0_PI)) +#define CPE_Q_CI(__n) \ +	(CPE_Q0_CI + (__n) * (CPE_Q1_CI - CPE_Q0_CI)) +#define RME_Q_DEPTH(__n) \ +	(RME_Q0_DEPTH + (__n) * (RME_Q1_DEPTH - RME_Q0_DEPTH)) +#define RME_Q_PI(__n) \ +	(RME_Q0_PI + (__n) * (RME_Q1_PI - RME_Q0_PI)) +#define RME_Q_CI(__n) \ +	(RME_Q0_CI + (__n) * (RME_Q1_CI - RME_Q0_CI)) + +#define CPE_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q)  ((__q) & 0x3) +#define RME_Q_MASK(__q)  ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { +    BFA_MSIX_CPE_Q0 = 0, +    BFA_MSIX_CPE_Q1 = 1, +    BFA_MSIX_CPE_Q2 = 2, +    BFA_MSIX_CPE_Q3 = 3, +    BFA_MSIX_CPE_Q4 = 4, +    BFA_MSIX_CPE_Q5 = 5, +    BFA_MSIX_CPE_Q6 = 6, +    BFA_MSIX_CPE_Q7 = 7, +    BFA_MSIX_RME_Q0 = 8, +    BFA_MSIX_RME_Q1 = 9, +    BFA_MSIX_RME_Q2 = 10, +    BFA_MSIX_RME_Q3 = 11, +    BFA_MSIX_RME_Q4 = 12, +    BFA_MSIX_RME_Q5 = 13, +    BFA_MSIX_RME_Q6 = 14, +    BFA_MSIX_RME_Q7 = 15, +    BFA_MSIX_ERR_EMC = 16, +    BFA_MSIX_ERR_LPU0 = 17, +    BFA_MSIX_ERR_LPU1 = 18, +    BFA_MSIX_ERR_PSS = 19, +    BFA_MSIX_MBOX_LPU0 = 20, +    BFA_MSIX_MBOX_LPU1 = 21, +    BFA_MSIX_CB_MAX = 22, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0                   0x00000001U +#define __HFN_INT_CPE_Q1                   0x00000002U +#define __HFN_INT_CPE_Q2                   0x00000004U +#define __HFN_INT_CPE_Q3                   0x00000008U +#define __HFN_INT_CPE_Q4                   0x00000010U +#define __HFN_INT_CPE_Q5                   0x00000020U +#define __HFN_INT_CPE_Q6                   0x00000040U +#define __HFN_INT_CPE_Q7                   0x00000080U +#define __HFN_INT_RME_Q0                   0x00000100U +#define __HFN_INT_RME_Q1                   0x00000200U +#define __HFN_INT_RME_Q2                   0x00000400U +#define __HFN_INT_RME_Q3                   0x00000800U +#define __HFN_INT_RME_Q4                   0x00001000U +#define __HFN_INT_RME_Q5                   0x00002000U +#define __HFN_INT_RME_Q6                   0x00004000U +#define __HFN_INT_RME_Q7                   0x00008000U +#define __HFN_INT_ERR_EMC                  0x00010000U +#define __HFN_INT_ERR_LPU0                 0x00020000U +#define __HFN_INT_ERR_LPU1                 0x00040000U +#define __HFN_INT_ERR_PSS                  0x00080000U +#define __HFN_INT_MBOX_LPU0                0x00100000U +#define __HFN_INT_MBOX_LPU1                0x00200000U +#define __HFN_INT_MBOX1_LPU0               0x00400000U +#define __HFN_INT_MBOX1_LPU1               0x00800000U +#define __HFN_INT_CPE_MASK                 0x000000ffU +#define __HFN_INT_RME_MASK                 0x0000ff00U + + +/* + * crossbow memory map. + */ +#define PSS_SMEM_PAGE_START	0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma)	((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma)	((_ma) & 0x7fff) + +/* + * End of crossbow memory map + */ + + +#endif /* __BFI_CBREG_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_cee.h b/drivers/scsi/bfa/include/bfi/bfi_cee.h new file mode 100644 index 00000000000..0970596583e --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_cee.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +/** + *  Copyright (c) 2006-2009 Brocade Communications Systems, Inc. + *  All rights reserved. + * + *  bfi_dcbx.h BFI Interface (Mailbox commands and related structures) + * between host driver and DCBX/LLDP firmware module. + * +**/ + +#ifndef __BFI_CEE_H__ +#define __BFI_CEE_H__ + +#include <bfi/bfi.h> + +#pragma pack(1) + + +enum bfi_cee_h2i_msgs_e { +	BFI_CEE_H2I_GET_CFG_REQ = 1, +	BFI_CEE_H2I_RESET_STATS = 2, +	BFI_CEE_H2I_GET_STATS_REQ = 3, +}; + + +enum bfi_cee_i2h_msgs_e { +	BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1), +	BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2), +	BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3), +}; + + +/* Data structures */ + +/* + * BFI_CEE_H2I_RESET_STATS + */ +struct bfi_lldp_reset_stats_s { +	struct bfi_mhdr_s  mh; +}; + +/* + * BFI_CEE_H2I_RESET_STATS + */ +struct bfi_cee_reset_stats_s { +	struct bfi_mhdr_s  mh; +}; + +/* + * BFI_CEE_H2I_GET_CFG_REQ + */ +struct bfi_cee_get_req_s { +	struct bfi_mhdr_s  mh; +	union bfi_addr_u   dma_addr; +}; + + +/* + * BFI_CEE_I2H_GET_CFG_RSP + */ +struct bfi_cee_get_rsp_s { +	struct bfi_mhdr_s  mh; +	u8            cmd_status; +	u8            rsvd[3]; +}; + +/* + * BFI_CEE_H2I_GET_STATS_REQ + */ +struct bfi_cee_stats_req_s { +	struct bfi_mhdr_s  mh; +	union bfi_addr_u   dma_addr; +}; + + +/* + * BFI_CEE_I2H_GET_STATS_RSP + */ +struct bfi_cee_stats_rsp_s { +	struct bfi_mhdr_s  mh; +	u8 		   cmd_status; +	u8 		   rsvd[3]; +}; + + + +union bfi_cee_h2i_msg_u { +	struct bfi_mhdr_s           mh; +	struct bfi_cee_get_req_s   get_req; +	struct bfi_cee_stats_req_s stats_req; +}; + + +union bfi_cee_i2h_msg_u { +	struct bfi_mhdr_s         mh; +	struct bfi_cee_get_rsp_s  get_rsp; +	struct bfi_cee_stats_rsp_s stats_rsp; +}; + +#pragma pack() + + +#endif /* __BFI_CEE_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h new file mode 100644 index 00000000000..d3caa58c0a0 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* + * bfi_ctreg.h catapult host block register definitions + * + * !!! Do not edit. Auto generated. !!! + */ + +#ifndef __BFI_CTREG_H__ +#define __BFI_CTREG_H__ + + +#define HOSTFN0_LPU_MBOX0_0              0x00019200 +#define HOSTFN1_LPU_MBOX0_8              0x00019260 +#define LPU_HOSTFN0_MBOX0_0              0x00019280 +#define LPU_HOSTFN1_MBOX0_8              0x000192e0 +#define HOSTFN2_LPU_MBOX0_0              0x00019400 +#define HOSTFN3_LPU_MBOX0_8              0x00019460 +#define LPU_HOSTFN2_MBOX0_0              0x00019480 +#define LPU_HOSTFN3_MBOX0_8              0x000194e0 +#define HOSTFN0_INT_STATUS               0x00014000 +#define __HOSTFN0_HALT_OCCURRED          0x01000000 +#define __HOSTFN0_INT_STATUS_LVL_MK      0x00f00000 +#define __HOSTFN0_INT_STATUS_LVL_SH      20 +#define __HOSTFN0_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN0_INT_STATUS_LVL_SH) +#define __HOSTFN0_INT_STATUS_P_MK        0x000f0000 +#define __HOSTFN0_INT_STATUS_P_SH        16 +#define __HOSTFN0_INT_STATUS_P(_v)       ((_v) << __HOSTFN0_INT_STATUS_P_SH) +#define __HOSTFN0_INT_STATUS_F           0x0000ffff +#define HOSTFN0_INT_MSK                  0x00014004 +#define HOST_PAGE_NUM_FN0                0x00014008 +#define __HOST_PAGE_NUM_FN               0x000001ff +#define HOST_MSIX_ERR_INDEX_FN0          0x0001400c +#define __MSIX_ERR_INDEX_FN              0x000001ff +#define HOSTFN1_INT_STATUS               0x00014100 +#define __HOSTFN1_HALT_OCCURRED          0x01000000 +#define __HOSTFN1_INT_STATUS_LVL_MK      0x00f00000 +#define __HOSTFN1_INT_STATUS_LVL_SH      20 +#define __HOSTFN1_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN1_INT_STATUS_LVL_SH) +#define __HOSTFN1_INT_STATUS_P_MK        0x000f0000 +#define __HOSTFN1_INT_STATUS_P_SH        16 +#define __HOSTFN1_INT_STATUS_P(_v)       ((_v) << __HOSTFN1_INT_STATUS_P_SH) +#define __HOSTFN1_INT_STATUS_F           0x0000ffff +#define HOSTFN1_INT_MSK                  0x00014104 +#define HOST_PAGE_NUM_FN1                0x00014108 +#define HOST_MSIX_ERR_INDEX_FN1          0x0001410c +#define APP_PLL_425_CTL_REG              0x00014204 +#define __P_425_PLL_LOCK                 0x80000000 +#define __APP_PLL_425_SRAM_USE_100MHZ    0x00100000 +#define __APP_PLL_425_RESET_TIMER_MK     0x000e0000 +#define __APP_PLL_425_RESET_TIMER_SH     17 +#define __APP_PLL_425_RESET_TIMER(_v)    ((_v) << __APP_PLL_425_RESET_TIMER_SH) +#define __APP_PLL_425_LOGIC_SOFT_RESET   0x00010000 +#define __APP_PLL_425_CNTLMT0_1_MK       0x0000c000 +#define __APP_PLL_425_CNTLMT0_1_SH       14 +#define __APP_PLL_425_CNTLMT0_1(_v)      ((_v) << __APP_PLL_425_CNTLMT0_1_SH) +#define __APP_PLL_425_JITLMT0_1_MK       0x00003000 +#define __APP_PLL_425_JITLMT0_1_SH       12 +#define __APP_PLL_425_JITLMT0_1(_v)      ((_v) << __APP_PLL_425_JITLMT0_1_SH) +#define __APP_PLL_425_HREF               0x00000800 +#define __APP_PLL_425_HDIV               0x00000400 +#define __APP_PLL_425_P0_1_MK            0x00000300 +#define __APP_PLL_425_P0_1_SH            8 +#define __APP_PLL_425_P0_1(_v)           ((_v) << __APP_PLL_425_P0_1_SH) +#define __APP_PLL_425_Z0_2_MK            0x000000e0 +#define __APP_PLL_425_Z0_2_SH            5 +#define __APP_PLL_425_Z0_2(_v)           ((_v) << __APP_PLL_425_Z0_2_SH) +#define __APP_PLL_425_RSEL200500         0x00000010 +#define __APP_PLL_425_ENARST             0x00000008 +#define __APP_PLL_425_BYPASS             0x00000004 +#define __APP_PLL_425_LRESETN            0x00000002 +#define __APP_PLL_425_ENABLE             0x00000001 +#define APP_PLL_312_CTL_REG              0x00014208 +#define __P_312_PLL_LOCK                 0x80000000 +#define __ENABLE_MAC_AHB_1               0x00800000 +#define __ENABLE_MAC_AHB_0               0x00400000 +#define __ENABLE_MAC_1                   0x00200000 +#define __ENABLE_MAC_0                   0x00100000 +#define __APP_PLL_312_RESET_TIMER_MK     0x000e0000 +#define __APP_PLL_312_RESET_TIMER_SH     17 +#define __APP_PLL_312_RESET_TIMER(_v)    ((_v) << __APP_PLL_312_RESET_TIMER_SH) +#define __APP_PLL_312_LOGIC_SOFT_RESET   0x00010000 +#define __APP_PLL_312_CNTLMT0_1_MK       0x0000c000 +#define __APP_PLL_312_CNTLMT0_1_SH       14 +#define __APP_PLL_312_CNTLMT0_1(_v)      ((_v) << __APP_PLL_312_CNTLMT0_1_SH) +#define __APP_PLL_312_JITLMT0_1_MK       0x00003000 +#define __APP_PLL_312_JITLMT0_1_SH       12 +#define __APP_PLL_312_JITLMT0_1(_v)      ((_v) << __APP_PLL_312_JITLMT0_1_SH) +#define __APP_PLL_312_HREF               0x00000800 +#define __APP_PLL_312_HDIV               0x00000400 +#define __APP_PLL_312_P0_1_MK            0x00000300 +#define __APP_PLL_312_P0_1_SH            8 +#define __APP_PLL_312_P0_1(_v)           ((_v) << __APP_PLL_312_P0_1_SH) +#define __APP_PLL_312_Z0_2_MK            0x000000e0 +#define __APP_PLL_312_Z0_2_SH            5 +#define __APP_PLL_312_Z0_2(_v)           ((_v) << __APP_PLL_312_Z0_2_SH) +#define __APP_PLL_312_RSEL200500         0x00000010 +#define __APP_PLL_312_ENARST             0x00000008 +#define __APP_PLL_312_BYPASS             0x00000004 +#define __APP_PLL_312_LRESETN            0x00000002 +#define __APP_PLL_312_ENABLE             0x00000001 +#define MBIST_CTL_REG                    0x00014220 +#define __EDRAM_BISTR_START              0x00000004 +#define __MBIST_RESET                    0x00000002 +#define __MBIST_START                    0x00000001 +#define MBIST_STAT_REG                   0x00014224 +#define __EDRAM_BISTR_STATUS             0x00000008 +#define __EDRAM_BISTR_DONE               0x00000004 +#define __MEM_BIT_STATUS                 0x00000002 +#define __MBIST_DONE                     0x00000001 +#define HOST_SEM0_REG                    0x00014230 +#define __HOST_SEMAPHORE                 0x00000001 +#define HOST_SEM1_REG                    0x00014234 +#define HOST_SEM2_REG                    0x00014238 +#define HOST_SEM3_REG                    0x0001423c +#define HOST_SEM0_INFO_REG               0x00014240 +#define HOST_SEM1_INFO_REG               0x00014244 +#define HOST_SEM2_INFO_REG               0x00014248 +#define HOST_SEM3_INFO_REG               0x0001424c +#define ETH_MAC_SER_REG                  0x00014288 +#define __APP_EMS_CKBUFAMPIN             0x00000020 +#define __APP_EMS_REFCLKSEL              0x00000010 +#define __APP_EMS_CMLCKSEL               0x00000008 +#define __APP_EMS_REFCKBUFEN2            0x00000004 +#define __APP_EMS_REFCKBUFEN1            0x00000002 +#define __APP_EMS_CHANNEL_SEL            0x00000001 +#define HOSTFN2_INT_STATUS               0x00014300 +#define __HOSTFN2_HALT_OCCURRED          0x01000000 +#define __HOSTFN2_INT_STATUS_LVL_MK      0x00f00000 +#define __HOSTFN2_INT_STATUS_LVL_SH      20 +#define __HOSTFN2_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN2_INT_STATUS_LVL_SH) +#define __HOSTFN2_INT_STATUS_P_MK        0x000f0000 +#define __HOSTFN2_INT_STATUS_P_SH        16 +#define __HOSTFN2_INT_STATUS_P(_v)       ((_v) << __HOSTFN2_INT_STATUS_P_SH) +#define __HOSTFN2_INT_STATUS_F           0x0000ffff +#define HOSTFN2_INT_MSK                  0x00014304 +#define HOST_PAGE_NUM_FN2                0x00014308 +#define HOST_MSIX_ERR_INDEX_FN2          0x0001430c +#define HOSTFN3_INT_STATUS               0x00014400 +#define __HALT_OCCURRED                  0x01000000 +#define __HOSTFN3_INT_STATUS_LVL_MK      0x00f00000 +#define __HOSTFN3_INT_STATUS_LVL_SH      20 +#define __HOSTFN3_INT_STATUS_LVL(_v)     ((_v) << __HOSTFN3_INT_STATUS_LVL_SH) +#define __HOSTFN3_INT_STATUS_P_MK        0x000f0000 +#define __HOSTFN3_INT_STATUS_P_SH        16 +#define __HOSTFN3_INT_STATUS_P(_v)       ((_v) << __HOSTFN3_INT_STATUS_P_SH) +#define __HOSTFN3_INT_STATUS_F           0x0000ffff +#define HOSTFN3_INT_MSK                  0x00014404 +#define HOST_PAGE_NUM_FN3                0x00014408 +#define HOST_MSIX_ERR_INDEX_FN3          0x0001440c +#define FNC_ID_REG                       0x00014600 +#define __FUNCTION_NUMBER                0x00000007 +#define FNC_PERS_REG                     0x00014604 +#define __F3_FUNCTION_ACTIVE             0x80000000 +#define __F3_FUNCTION_MODE               0x40000000 +#define __F3_PORT_MAP_MK                 0x30000000 +#define __F3_PORT_MAP_SH                 28 +#define __F3_PORT_MAP(_v)                ((_v) << __F3_PORT_MAP_SH) +#define __F3_VM_MODE                     0x08000000 +#define __F3_INTX_STATUS_MK              0x07000000 +#define __F3_INTX_STATUS_SH              24 +#define __F3_INTX_STATUS(_v)             ((_v) << __F3_INTX_STATUS_SH) +#define __F2_FUNCTION_ACTIVE             0x00800000 +#define __F2_FUNCTION_MODE               0x00400000 +#define __F2_PORT_MAP_MK                 0x00300000 +#define __F2_PORT_MAP_SH                 20 +#define __F2_PORT_MAP(_v)                ((_v) << __F2_PORT_MAP_SH) +#define __F2_VM_MODE                     0x00080000 +#define __F2_INTX_STATUS_MK              0x00070000 +#define __F2_INTX_STATUS_SH              16 +#define __F2_INTX_STATUS(_v)             ((_v) << __F2_INTX_STATUS_SH) +#define __F1_FUNCTION_ACTIVE             0x00008000 +#define __F1_FUNCTION_MODE               0x00004000 +#define __F1_PORT_MAP_MK                 0x00003000 +#define __F1_PORT_MAP_SH                 12 +#define __F1_PORT_MAP(_v)                ((_v) << __F1_PORT_MAP_SH) +#define __F1_VM_MODE                     0x00000800 +#define __F1_INTX_STATUS_MK              0x00000700 +#define __F1_INTX_STATUS_SH              8 +#define __F1_INTX_STATUS(_v)             ((_v) << __F1_INTX_STATUS_SH) +#define __F0_FUNCTION_ACTIVE             0x00000080 +#define __F0_FUNCTION_MODE               0x00000040 +#define __F0_PORT_MAP_MK                 0x00000030 +#define __F0_PORT_MAP_SH                 4 +#define __F0_PORT_MAP(_v)                ((_v) << __F0_PORT_MAP_SH) +#define __F0_VM_MODE                     0x00000008 +#define __F0_INTX_STATUS                 0x00000007 +enum { +    __F0_INTX_STATUS_MSIX            = 0x0, +    __F0_INTX_STATUS_INTA            = 0x1, +    __F0_INTX_STATUS_INTB            = 0x2, +    __F0_INTX_STATUS_INTC            = 0x3, +    __F0_INTX_STATUS_INTD            = 0x4, +}; +#define OP_MODE                          0x0001460c +#define __APP_ETH_CLK_LOWSPEED           0x00000004 +#define __GLOBAL_CORECLK_HALFSPEED       0x00000002 +#define __GLOBAL_FCOE_MODE               0x00000001 +#define HOST_SEM4_REG                    0x00014610 +#define HOST_SEM5_REG                    0x00014614 +#define HOST_SEM6_REG                    0x00014618 +#define HOST_SEM7_REG                    0x0001461c +#define HOST_SEM4_INFO_REG               0x00014620 +#define HOST_SEM5_INFO_REG               0x00014624 +#define HOST_SEM6_INFO_REG               0x00014628 +#define HOST_SEM7_INFO_REG               0x0001462c +#define HOSTFN0_LPU0_MBOX0_CMD_STAT      0x00019000 +#define __HOSTFN0_LPU0_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN0_LPU0_MBOX0_INFO_SH     1 +#define __HOSTFN0_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH) +#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN0_LPU1_MBOX0_CMD_STAT      0x00019004 +#define __HOSTFN0_LPU1_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN0_LPU1_MBOX0_INFO_SH     1 +#define __HOSTFN0_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH) +#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS  0x00000001 +#define LPU0_HOSTFN0_MBOX0_CMD_STAT      0x00019008 +#define __LPU0_HOSTFN0_MBOX0_INFO_MK     0xfffffffe +#define __LPU0_HOSTFN0_MBOX0_INFO_SH     1 +#define __LPU0_HOSTFN0_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH) +#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS  0x00000001 +#define LPU1_HOSTFN0_MBOX0_CMD_STAT      0x0001900c +#define __LPU1_HOSTFN0_MBOX0_INFO_MK     0xfffffffe +#define __LPU1_HOSTFN0_MBOX0_INFO_SH     1 +#define __LPU1_HOSTFN0_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH) +#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN1_LPU0_MBOX0_CMD_STAT      0x00019010 +#define __HOSTFN1_LPU0_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN1_LPU0_MBOX0_INFO_SH     1 +#define __HOSTFN1_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH) +#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN1_LPU1_MBOX0_CMD_STAT      0x00019014 +#define __HOSTFN1_LPU1_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN1_LPU1_MBOX0_INFO_SH     1 +#define __HOSTFN1_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH) +#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS  0x00000001 +#define LPU0_HOSTFN1_MBOX0_CMD_STAT      0x00019018 +#define __LPU0_HOSTFN1_MBOX0_INFO_MK     0xfffffffe +#define __LPU0_HOSTFN1_MBOX0_INFO_SH     1 +#define __LPU0_HOSTFN1_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH) +#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS  0x00000001 +#define LPU1_HOSTFN1_MBOX0_CMD_STAT      0x0001901c +#define __LPU1_HOSTFN1_MBOX0_INFO_MK     0xfffffffe +#define __LPU1_HOSTFN1_MBOX0_INFO_SH     1 +#define __LPU1_HOSTFN1_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH) +#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN2_LPU0_MBOX0_CMD_STAT      0x00019150 +#define __HOSTFN2_LPU0_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN2_LPU0_MBOX0_INFO_SH     1 +#define __HOSTFN2_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH) +#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN2_LPU1_MBOX0_CMD_STAT      0x00019154 +#define __HOSTFN2_LPU1_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN2_LPU1_MBOX0_INFO_SH     1 +#define __HOSTFN2_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH) +#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001 +#define LPU0_HOSTFN2_MBOX0_CMD_STAT      0x00019158 +#define __LPU0_HOSTFN2_MBOX0_INFO_MK     0xfffffffe +#define __LPU0_HOSTFN2_MBOX0_INFO_SH     1 +#define __LPU0_HOSTFN2_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH) +#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS  0x00000001 +#define LPU1_HOSTFN2_MBOX0_CMD_STAT      0x0001915c +#define __LPU1_HOSTFN2_MBOX0_INFO_MK     0xfffffffe +#define __LPU1_HOSTFN2_MBOX0_INFO_SH     1 +#define __LPU1_HOSTFN2_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH) +#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN3_LPU0_MBOX0_CMD_STAT      0x00019160 +#define __HOSTFN3_LPU0_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN3_LPU0_MBOX0_INFO_SH     1 +#define __HOSTFN3_LPU0_MBOX0_INFO(_v)    ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH) +#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS  0x00000001 +#define HOSTFN3_LPU1_MBOX0_CMD_STAT      0x00019164 +#define __HOSTFN3_LPU1_MBOX0_INFO_MK     0xfffffffe +#define __HOSTFN3_LPU1_MBOX0_INFO_SH     1 +#define __HOSTFN3_LPU1_MBOX0_INFO(_v)    ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH) +#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS  0x00000001 +#define LPU0_HOSTFN3_MBOX0_CMD_STAT      0x00019168 +#define __LPU0_HOSTFN3_MBOX0_INFO_MK     0xfffffffe +#define __LPU0_HOSTFN3_MBOX0_INFO_SH     1 +#define __LPU0_HOSTFN3_MBOX0_INFO(_v)    ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH) +#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS  0x00000001 +#define LPU1_HOSTFN3_MBOX0_CMD_STAT      0x0001916c +#define __LPU1_HOSTFN3_MBOX0_INFO_MK     0xfffffffe +#define __LPU1_HOSTFN3_MBOX0_INFO_SH     1 +#define __LPU1_HOSTFN3_MBOX0_INFO(_v)    ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH) +#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS  0x00000001 +#define FW_INIT_HALT_P0                  0x000191ac +#define __FW_INIT_HALT_P                 0x00000001 +#define FW_INIT_HALT_P1                  0x000191bc +#define CPE_PI_PTR_Q0                    0x00038000 +#define __CPE_PI_UNUSED_MK               0xffff0000 +#define __CPE_PI_UNUSED_SH               16 +#define __CPE_PI_UNUSED(_v)              ((_v) << __CPE_PI_UNUSED_SH) +#define __CPE_PI_PTR                     0x0000ffff +#define CPE_PI_PTR_Q1                    0x00038040 +#define CPE_CI_PTR_Q0                    0x00038004 +#define __CPE_CI_UNUSED_MK               0xffff0000 +#define __CPE_CI_UNUSED_SH               16 +#define __CPE_CI_UNUSED(_v)              ((_v) << __CPE_CI_UNUSED_SH) +#define __CPE_CI_PTR                     0x0000ffff +#define CPE_CI_PTR_Q1                    0x00038044 +#define CPE_DEPTH_Q0                     0x00038008 +#define __CPE_DEPTH_UNUSED_MK            0xf8000000 +#define __CPE_DEPTH_UNUSED_SH            27 +#define __CPE_DEPTH_UNUSED(_v)           ((_v) << __CPE_DEPTH_UNUSED_SH) +#define __CPE_MSIX_VEC_INDEX_MK          0x07ff0000 +#define __CPE_MSIX_VEC_INDEX_SH          16 +#define __CPE_MSIX_VEC_INDEX(_v)         ((_v) << __CPE_MSIX_VEC_INDEX_SH) +#define __CPE_DEPTH                      0x0000ffff +#define CPE_DEPTH_Q1                     0x00038048 +#define CPE_QCTRL_Q0                     0x0003800c +#define __CPE_CTRL_UNUSED30_MK           0xfc000000 +#define __CPE_CTRL_UNUSED30_SH           26 +#define __CPE_CTRL_UNUSED30(_v)          ((_v) << __CPE_CTRL_UNUSED30_SH) +#define __CPE_FUNC_INT_CTRL_MK           0x03000000 +#define __CPE_FUNC_INT_CTRL_SH           24 +#define __CPE_FUNC_INT_CTRL(_v)          ((_v) << __CPE_FUNC_INT_CTRL_SH) +enum { +    __CPE_FUNC_INT_CTRL_DISABLE      = 0x0, +    __CPE_FUNC_INT_CTRL_F2NF         = 0x1, +    __CPE_FUNC_INT_CTRL_3QUART       = 0x2, +    __CPE_FUNC_INT_CTRL_HALF         = 0x3, +}; +#define __CPE_CTRL_UNUSED20_MK           0x00f00000 +#define __CPE_CTRL_UNUSED20_SH           20 +#define __CPE_CTRL_UNUSED20(_v)          ((_v) << __CPE_CTRL_UNUSED20_SH) +#define __CPE_SCI_TH_MK                  0x000f0000 +#define __CPE_SCI_TH_SH                  16 +#define __CPE_SCI_TH(_v)                 ((_v) << __CPE_SCI_TH_SH) +#define __CPE_CTRL_UNUSED10_MK           0x0000c000 +#define __CPE_CTRL_UNUSED10_SH           14 +#define __CPE_CTRL_UNUSED10(_v)          ((_v) << __CPE_CTRL_UNUSED10_SH) +#define __CPE_ACK_PENDING                0x00002000 +#define __CPE_CTRL_UNUSED40_MK           0x00001c00 +#define __CPE_CTRL_UNUSED40_SH           10 +#define __CPE_CTRL_UNUSED40(_v)          ((_v) << __CPE_CTRL_UNUSED40_SH) +#define __CPE_PCIEID_MK                  0x00000300 +#define __CPE_PCIEID_SH                  8 +#define __CPE_PCIEID(_v)                 ((_v) << __CPE_PCIEID_SH) +#define __CPE_CTRL_UNUSED00_MK           0x000000fe +#define __CPE_CTRL_UNUSED00_SH           1 +#define __CPE_CTRL_UNUSED00(_v)          ((_v) << __CPE_CTRL_UNUSED00_SH) +#define __CPE_ESIZE                      0x00000001 +#define CPE_QCTRL_Q1                     0x0003804c +#define __CPE_CTRL_UNUSED31_MK           0xfc000000 +#define __CPE_CTRL_UNUSED31_SH           26 +#define __CPE_CTRL_UNUSED31(_v)          ((_v) << __CPE_CTRL_UNUSED31_SH) +#define __CPE_CTRL_UNUSED21_MK           0x00f00000 +#define __CPE_CTRL_UNUSED21_SH           20 +#define __CPE_CTRL_UNUSED21(_v)          ((_v) << __CPE_CTRL_UNUSED21_SH) +#define __CPE_CTRL_UNUSED11_MK           0x0000c000 +#define __CPE_CTRL_UNUSED11_SH           14 +#define __CPE_CTRL_UNUSED11(_v)          ((_v) << __CPE_CTRL_UNUSED11_SH) +#define __CPE_CTRL_UNUSED41_MK           0x00001c00 +#define __CPE_CTRL_UNUSED41_SH           10 +#define __CPE_CTRL_UNUSED41(_v)          ((_v) << __CPE_CTRL_UNUSED41_SH) +#define __CPE_CTRL_UNUSED01_MK           0x000000fe +#define __CPE_CTRL_UNUSED01_SH           1 +#define __CPE_CTRL_UNUSED01(_v)          ((_v) << __CPE_CTRL_UNUSED01_SH) +#define RME_PI_PTR_Q0                    0x00038020 +#define __LATENCY_TIME_STAMP_MK          0xffff0000 +#define __LATENCY_TIME_STAMP_SH          16 +#define __LATENCY_TIME_STAMP(_v)         ((_v) << __LATENCY_TIME_STAMP_SH) +#define __RME_PI_PTR                     0x0000ffff +#define RME_PI_PTR_Q1                    0x00038060 +#define RME_CI_PTR_Q0                    0x00038024 +#define __DELAY_TIME_STAMP_MK            0xffff0000 +#define __DELAY_TIME_STAMP_SH            16 +#define __DELAY_TIME_STAMP(_v)           ((_v) << __DELAY_TIME_STAMP_SH) +#define __RME_CI_PTR                     0x0000ffff +#define RME_CI_PTR_Q1                    0x00038064 +#define RME_DEPTH_Q0                     0x00038028 +#define __RME_DEPTH_UNUSED_MK            0xf8000000 +#define __RME_DEPTH_UNUSED_SH            27 +#define __RME_DEPTH_UNUSED(_v)           ((_v) << __RME_DEPTH_UNUSED_SH) +#define __RME_MSIX_VEC_INDEX_MK          0x07ff0000 +#define __RME_MSIX_VEC_INDEX_SH          16 +#define __RME_MSIX_VEC_INDEX(_v)         ((_v) << __RME_MSIX_VEC_INDEX_SH) +#define __RME_DEPTH                      0x0000ffff +#define RME_DEPTH_Q1                     0x00038068 +#define RME_QCTRL_Q0                     0x0003802c +#define __RME_INT_LATENCY_TIMER_MK       0xff000000 +#define __RME_INT_LATENCY_TIMER_SH       24 +#define __RME_INT_LATENCY_TIMER(_v)      ((_v) << __RME_INT_LATENCY_TIMER_SH) +#define __RME_INT_DELAY_TIMER_MK         0x00ff0000 +#define __RME_INT_DELAY_TIMER_SH         16 +#define __RME_INT_DELAY_TIMER(_v)        ((_v) << __RME_INT_DELAY_TIMER_SH) +#define __RME_INT_DELAY_DISABLE          0x00008000 +#define __RME_DLY_DELAY_DISABLE          0x00004000 +#define __RME_ACK_PENDING                0x00002000 +#define __RME_FULL_INTERRUPT_DISABLE     0x00001000 +#define __RME_CTRL_UNUSED10_MK           0x00000c00 +#define __RME_CTRL_UNUSED10_SH           10 +#define __RME_CTRL_UNUSED10(_v)          ((_v) << __RME_CTRL_UNUSED10_SH) +#define __RME_PCIEID_MK                  0x00000300 +#define __RME_PCIEID_SH                  8 +#define __RME_PCIEID(_v)                 ((_v) << __RME_PCIEID_SH) +#define __RME_CTRL_UNUSED00_MK           0x000000fe +#define __RME_CTRL_UNUSED00_SH           1 +#define __RME_CTRL_UNUSED00(_v)          ((_v) << __RME_CTRL_UNUSED00_SH) +#define __RME_ESIZE                      0x00000001 +#define RME_QCTRL_Q1                     0x0003806c +#define __RME_CTRL_UNUSED11_MK           0x00000c00 +#define __RME_CTRL_UNUSED11_SH           10 +#define __RME_CTRL_UNUSED11(_v)          ((_v) << __RME_CTRL_UNUSED11_SH) +#define __RME_CTRL_UNUSED01_MK           0x000000fe +#define __RME_CTRL_UNUSED01_SH           1 +#define __RME_CTRL_UNUSED01(_v)          ((_v) << __RME_CTRL_UNUSED01_SH) +#define PSS_CTL_REG                      0x00018800 +#define __PSS_I2C_CLK_DIV_MK             0x007f0000 +#define __PSS_I2C_CLK_DIV_SH             16 +#define __PSS_I2C_CLK_DIV(_v)            ((_v) << __PSS_I2C_CLK_DIV_SH) +#define __PSS_LMEM_INIT_DONE             0x00001000 +#define __PSS_LMEM_RESET                 0x00000200 +#define __PSS_LMEM_INIT_EN               0x00000100 +#define __PSS_LPU1_RESET                 0x00000002 +#define __PSS_LPU0_RESET                 0x00000001 +#define HQM_QSET0_RXQ_DRBL_P0            0x00038000 +#define __RXQ0_ADD_VECTORS_P             0x80000000 +#define __RXQ0_STOP_P                    0x40000000 +#define __RXQ0_PRD_PTR_P                 0x0000ffff +#define HQM_QSET1_RXQ_DRBL_P0            0x00038080 +#define __RXQ1_ADD_VECTORS_P             0x80000000 +#define __RXQ1_STOP_P                    0x40000000 +#define __RXQ1_PRD_PTR_P                 0x0000ffff +#define HQM_QSET0_RXQ_DRBL_P1            0x0003c000 +#define HQM_QSET1_RXQ_DRBL_P1            0x0003c080 +#define HQM_QSET0_TXQ_DRBL_P0            0x00038020 +#define __TXQ0_ADD_VECTORS_P             0x80000000 +#define __TXQ0_STOP_P                    0x40000000 +#define __TXQ0_PRD_PTR_P                 0x0000ffff +#define HQM_QSET1_TXQ_DRBL_P0            0x000380a0 +#define __TXQ1_ADD_VECTORS_P             0x80000000 +#define __TXQ1_STOP_P                    0x40000000 +#define __TXQ1_PRD_PTR_P                 0x0000ffff +#define HQM_QSET0_TXQ_DRBL_P1            0x0003c020 +#define HQM_QSET1_TXQ_DRBL_P1            0x0003c0a0 +#define HQM_QSET0_IB_DRBL_1_P0           0x00038040 +#define __IB1_0_ACK_P                    0x80000000 +#define __IB1_0_DISABLE_P                0x40000000 +#define __IB1_0_NUM_OF_ACKED_EVENTS_P    0x0000ffff +#define HQM_QSET1_IB_DRBL_1_P0           0x000380c0 +#define __IB1_1_ACK_P                    0x80000000 +#define __IB1_1_DISABLE_P                0x40000000 +#define __IB1_1_NUM_OF_ACKED_EVENTS_P    0x0000ffff +#define HQM_QSET0_IB_DRBL_1_P1           0x0003c040 +#define HQM_QSET1_IB_DRBL_1_P1           0x0003c0c0 +#define HQM_QSET0_IB_DRBL_2_P0           0x00038060 +#define __IB2_0_ACK_P                    0x80000000 +#define __IB2_0_DISABLE_P                0x40000000 +#define __IB2_0_NUM_OF_ACKED_EVENTS_P    0x0000ffff +#define HQM_QSET1_IB_DRBL_2_P0           0x000380e0 +#define __IB2_1_ACK_P                    0x80000000 +#define __IB2_1_DISABLE_P                0x40000000 +#define __IB2_1_NUM_OF_ACKED_EVENTS_P    0x0000ffff +#define HQM_QSET0_IB_DRBL_2_P1           0x0003c060 +#define HQM_QSET1_IB_DRBL_2_P1           0x0003c0e0 + + +/* + * These definitions are either in error/missing in spec. Its auto-generated + * from hard coded values in regparse.pl. + */ +#define __EMPHPOST_AT_4G_MK_FIX          0x0000001c +#define __EMPHPOST_AT_4G_SH_FIX          0x00000002 +#define __EMPHPRE_AT_4G_FIX              0x00000003 +#define __SFP_TXRATE_EN_FIX              0x00000100 +#define __SFP_RXRATE_EN_FIX              0x00000080 + + +/* + * These register definitions are auto-generated from hard coded values + * in regparse.pl. + */ + + +/* + * These register mapping definitions are auto-generated from mapping tables + * in regparse.pl. + */ +#define BFA_IOC0_HBEAT_REG               HOST_SEM0_INFO_REG +#define BFA_IOC0_STATE_REG               HOST_SEM1_INFO_REG +#define BFA_IOC1_HBEAT_REG               HOST_SEM2_INFO_REG +#define BFA_IOC1_STATE_REG               HOST_SEM3_INFO_REG +#define BFA_FW_USE_COUNT                 HOST_SEM4_INFO_REG + +#define CPE_DEPTH_Q(__n) \ +	(CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0)) +#define CPE_QCTRL_Q(__n) \ +	(CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0)) +#define CPE_PI_PTR_Q(__n) \ +	(CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0)) +#define CPE_CI_PTR_Q(__n) \ +	(CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0)) +#define RME_DEPTH_Q(__n) \ +	(RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0)) +#define RME_QCTRL_Q(__n) \ +	(RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0)) +#define RME_PI_PTR_Q(__n) \ +	(RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0)) +#define RME_CI_PTR_Q(__n) \ +	(RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0)) +#define HQM_QSET_RXQ_DRBL_P0(__n) \ +	(HQM_QSET0_RXQ_DRBL_P0 + (__n) * (HQM_QSET1_RXQ_DRBL_P0 - \ +	HQM_QSET0_RXQ_DRBL_P0)) +#define HQM_QSET_TXQ_DRBL_P0(__n) \ +	(HQM_QSET0_TXQ_DRBL_P0 + (__n) * (HQM_QSET1_TXQ_DRBL_P0 - \ +	HQM_QSET0_TXQ_DRBL_P0)) +#define HQM_QSET_IB_DRBL_1_P0(__n) \ +	(HQM_QSET0_IB_DRBL_1_P0 + (__n) * (HQM_QSET1_IB_DRBL_1_P0 - \ +	HQM_QSET0_IB_DRBL_1_P0)) +#define HQM_QSET_IB_DRBL_2_P0(__n) \ +	(HQM_QSET0_IB_DRBL_2_P0 + (__n) * (HQM_QSET1_IB_DRBL_2_P0 - \ +	HQM_QSET0_IB_DRBL_2_P0)) +#define HQM_QSET_RXQ_DRBL_P1(__n) \ +	(HQM_QSET0_RXQ_DRBL_P1 + (__n) * (HQM_QSET1_RXQ_DRBL_P1 - \ +	HQM_QSET0_RXQ_DRBL_P1)) +#define HQM_QSET_TXQ_DRBL_P1(__n) \ +	(HQM_QSET0_TXQ_DRBL_P1 + (__n) * (HQM_QSET1_TXQ_DRBL_P1 - \ +	HQM_QSET0_TXQ_DRBL_P1)) +#define HQM_QSET_IB_DRBL_1_P1(__n) \ +	(HQM_QSET0_IB_DRBL_1_P1 + (__n) * (HQM_QSET1_IB_DRBL_1_P1 - \ +	HQM_QSET0_IB_DRBL_1_P1)) +#define HQM_QSET_IB_DRBL_2_P1(__n) \ +	(HQM_QSET0_IB_DRBL_2_P1 + (__n) * (HQM_QSET1_IB_DRBL_2_P1 - \ +	HQM_QSET0_IB_DRBL_2_P1)) + +#define CPE_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q)) +#define RME_Q_NUM(__fn, __q)  (((__fn) << 2) + (__q)) +#define CPE_Q_MASK(__q)  ((__q) & 0x3) +#define RME_Q_MASK(__q)  ((__q) & 0x3) + + +/* + * PCI MSI-X vector defines + */ +enum { +    BFA_MSIX_CPE_Q0 = 0, +    BFA_MSIX_CPE_Q1 = 1, +    BFA_MSIX_CPE_Q2 = 2, +    BFA_MSIX_CPE_Q3 = 3, +    BFA_MSIX_RME_Q0 = 4, +    BFA_MSIX_RME_Q1 = 5, +    BFA_MSIX_RME_Q2 = 6, +    BFA_MSIX_RME_Q3 = 7, +    BFA_MSIX_LPU_ERR = 8, +    BFA_MSIX_CT_MAX = 9, +}; + +/* + * And corresponding host interrupt status bit field defines + */ +#define __HFN_INT_CPE_Q0                   0x00000001U +#define __HFN_INT_CPE_Q1                   0x00000002U +#define __HFN_INT_CPE_Q2                   0x00000004U +#define __HFN_INT_CPE_Q3                   0x00000008U +#define __HFN_INT_CPE_Q4                   0x00000010U +#define __HFN_INT_CPE_Q5                   0x00000020U +#define __HFN_INT_CPE_Q6                   0x00000040U +#define __HFN_INT_CPE_Q7                   0x00000080U +#define __HFN_INT_RME_Q0                   0x00000100U +#define __HFN_INT_RME_Q1                   0x00000200U +#define __HFN_INT_RME_Q2                   0x00000400U +#define __HFN_INT_RME_Q3                   0x00000800U +#define __HFN_INT_RME_Q4                   0x00001000U +#define __HFN_INT_RME_Q5                   0x00002000U +#define __HFN_INT_RME_Q6                   0x00004000U +#define __HFN_INT_RME_Q7                   0x00008000U +#define __HFN_INT_ERR_EMC                  0x00010000U +#define __HFN_INT_ERR_LPU0                 0x00020000U +#define __HFN_INT_ERR_LPU1                 0x00040000U +#define __HFN_INT_ERR_PSS                  0x00080000U +#define __HFN_INT_MBOX_LPU0                0x00100000U +#define __HFN_INT_MBOX_LPU1                0x00200000U +#define __HFN_INT_MBOX1_LPU0               0x00400000U +#define __HFN_INT_MBOX1_LPU1               0x00800000U +#define __HFN_INT_CPE_MASK                 0x000000ffU +#define __HFN_INT_RME_MASK                 0x0000ff00U + + +/* + * catapult memory map. + */ +#define LL_PGN_HQM0                      0x0096 +#define LL_PGN_HQM1                      0x0097 +#define PSS_SMEM_PAGE_START	0x8000 +#define PSS_SMEM_PGNUM(_pg0, _ma)	((_pg0) + ((_ma) >> 15)) +#define PSS_SMEM_PGOFF(_ma)	((_ma) & 0x7fff) + +/* + * End of catapult memory map + */ + + +#endif /* __BFI_CTREG_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_fabric.h b/drivers/scsi/bfa/include/bfi/bfi_fabric.h new file mode 100644 index 00000000000..c0669ed4107 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_fabric.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_FABRIC_H__ +#define __BFI_FABRIC_H__ + +#include <bfi/bfi.h> + +#pragma pack(1) + +enum bfi_fabric_h2i_msgs { +	BFI_FABRIC_H2I_CREATE_REQ	= 1, +	BFI_FABRIC_H2I_DELETE_REQ	= 2, +	BFI_FABRIC_H2I_SETAUTH		= 3, +}; + +enum bfi_fabric_i2h_msgs { +	BFI_FABRIC_I2H_CREATE_RSP	= BFA_I2HM(1), +	BFI_FABRIC_I2H_DELETE_RSP	= BFA_I2HM(2), +	BFI_FABRIC_I2H_SETAUTH_RSP	= BFA_I2HM(3), +	BFI_FABRIC_I2H_ONLINE		= BFA_I2HM(4), +	BFI_FABRIC_I2H_OFFLINE		= BFA_I2HM(5), +}; + +struct bfi_fabric_create_req_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u8         vf_en;		/*  virtual fabric enable	*/ +	u8         rsvd; +	u16        vf_id;		/*  virtual fabric ID		*/ +	wwn_t		pwwn;		/*  port name			*/ +	wwn_t		nwwn;		/*  node name			*/ +}; + +struct bfi_fabric_create_rsp_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host fabric handle		*/ +	u8         status;		/*  fabric create status	*/ +	u8         rsvd; +}; + +struct bfi_fabric_delete_req_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        fw_handle;	/*  firmware fabric handle	*/ +	u16        rsvd; +}; + +struct bfi_fabric_delete_rsp_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host fabric handle		*/ +	u8         status;		/*  fabric deletion status	*/ +	u8         rsvd; +}; + +#define BFI_FABRIC_AUTHSECRET_LEN	64 +struct bfi_fabric_setauth_req_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        fw_handle;	/*  f/w handle of fabric	*/ +	u8		algorithm; +	u8		group; +	u8		secret[BFI_FABRIC_AUTHSECRET_LEN]; +}; + +union bfi_fabric_h2i_msg_u { +	bfi_msg_t		*msg; +	struct bfi_fabric_create_req_s	*create_req; +	struct bfi_fabric_delete_req_s	*delete_req; +}; + +union bfi_fabric_i2h_msg_u { +	bfi_msg_t		*msg; +	struct bfi_fabric_create_rsp_s	*create_rsp; +	struct bfi_fabric_delete_rsp_s	*delete_rsp; +}; + +#pragma pack() + +#endif /* __BFI_FABRIC_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcpim.h b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h new file mode 100644 index 00000000000..52c059fb4c3 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_FCPIM_H__ +#define __BFI_FCPIM_H__ + +#include "bfi.h" +#include <protocol/fcp.h> + +#pragma pack(1) + +/* + * Initiator mode I-T nexus interface defines. + */ + +enum bfi_itnim_h2i { +	BFI_ITNIM_H2I_CREATE_REQ = 1,	/*  i-t nexus creation */ +	BFI_ITNIM_H2I_DELETE_REQ = 2,	/*  i-t nexus deletion */ +}; + +enum bfi_itnim_i2h { +	BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1), +	BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2), +	BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3), +}; + +struct bfi_itnim_create_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		 */ +	u16        fw_handle;	/*  f/w handle for itnim	 */ +	u8         class;		/*  FC class for IO		 */ +	u8         seq_rec;	/*  sequence recovery support	 */ +	u8         msg_no;		/*  seq id of the msg		 */ +}; + +struct bfi_itnim_create_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		 */ +	u16        bfa_handle;	/*  bfa handle for itnim	 */ +	u8         status;		/*  fcp request status		 */ +	u8         seq_id;		/*  seq id of the msg		 */ +}; + +struct bfi_itnim_delete_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		 */ +	u16        fw_handle;	/*  f/w itnim handle		 */ +	u8         seq_id;		/*  seq id of the msg		 */ +	u8         rsvd; +}; + +struct bfi_itnim_delete_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		 */ +	u16        bfa_handle;	/*  bfa handle for itnim	 */ +	u8         status;		/*  fcp request status		 */ +	u8         seq_id;		/*  seq id of the msg		 */ +}; + +struct bfi_itnim_sler_event_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		 */ +	u16        bfa_handle;	/*  bfa handle for itnim	 */ +	u16        rsvd; +}; + +union bfi_itnim_h2i_msg_u { +	struct bfi_itnim_create_req_s *create_req; +	struct bfi_itnim_delete_req_s *delete_req; +	struct bfi_msg_s      *msg; +}; + +union bfi_itnim_i2h_msg_u { +	struct bfi_itnim_create_rsp_s *create_rsp; +	struct bfi_itnim_delete_rsp_s *delete_rsp; +	struct bfi_itnim_sler_event_s *sler_event; +	struct bfi_msg_s      *msg; +}; + +/* + * Initiator mode IO interface defines. + */ + +enum bfi_ioim_h2i { +	BFI_IOIM_H2I_IOABORT_REQ = 1,	/*  IO abort request	 */ +	BFI_IOIM_H2I_IOCLEANUP_REQ = 2,	/*  IO cleanup request	 */ +}; + +enum bfi_ioim_i2h { +	BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1),	/*  non-fp IO response	 */ +	BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2),/*  ABORT rsp	 */ +}; + +/** + * IO command DIF info + */ +struct bfi_ioim_dif_s { +	u32	dif_info[4]; +}; + +/** + * FCP IO messages overview + * + * @note + * - Max CDB length supported is 64 bytes. + * - SCSI Linked commands and SCSI bi-directional Commands not + * 	 supported. + * + */ +struct bfi_ioim_req_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		 */ +	u16        io_tag;		/*  I/O tag			 */ +	u16        rport_hdl;	/*  itnim/rport firmware handle */ +	struct fcp_cmnd_s cmnd;		/*  IO request info		 */ + +	/** +	 * SG elements array within the IO request must be double word +	 * aligned. This aligment is required to optimize SGM setup for the IO. +	 */ +	struct bfi_sge_s   sges[BFI_SGE_INLINE_MAX]; +	u8         io_timeout; +	u8         dif_en; +	u8         rsvd_a[2]; +	struct bfi_ioim_dif_s  dif; +}; + +/** + * 	This table shows various IO status codes from firmware and their + *	meaning. Host driver can use these status codes to further process + *	IO completions. + * + * 	BFI_IOIM_STS_OK		: IO completed with error free SCSI & + *					   transport status. + * 					   - io-tag can be reused. + * + * 	BFA_IOIM_STS_SCSI_ERR		: IO completed with scsi error. + * 					  - io-tag can be reused. + * + * 	BFI_IOIM_STS_HOST_ABORTED	: IO was aborted successfully due to + *					   host request. + * 					   - io-tag cannot be reused yet. + * + * 	BFI_IOIM_STS_ABORTED		: IO was aborted successfully + *					   internally by f/w. + * 					   - io-tag cannot be reused yet. + * + * 	BFI_IOIM_STS_TIMEDOUT	: IO timedout and ABTS/RRQ is happening + *					   in the firmware and + * 					   - io-tag cannot be reused yet. + * + * 	BFI_IOIM_STS_SQER_NEEDED	: Firmware could not recover the IO + *					  with sequence level error + * 					  logic and hence host needs to retry + *					  this IO with a different IO tag + * 					  - io-tag cannot be used yet. + * + * 	BFI_IOIM_STS_NEXUS_ABORT	: Second Level Error Recovery from host + *					  is required because 2 consecutive ABTS + *					  timedout and host needs logout and + *					  re-login with the target + * 					  - io-tag cannot be used yet. + * + * 	BFI_IOIM_STS_UNDERRUN	: IO completed with SCSI status good, + *					  but the data tranferred is less than + *					  the fcp data length in the command. + *					  ex. SCSI INQUIRY where transferred + *					  data length and residue count in FCP + *					  response accounts for total fcp-dl + * 					  - io-tag can be reused. + * + * 	BFI_IOIM_STS_OVERRUN	: IO completed with SCSI status good, + *					  but the data transerred is more than + *					  fcp data length in the command. ex. + *					  TAPE IOs where blocks can of unequal + *					  lengths. + * 					  - io-tag can be reused. + * + * 	BFI_IOIM_STS_RES_FREE	: Firmware has completed using io-tag + *					  during abort process + * 					  - io-tag can be reused. + * + * 	BFI_IOIM_STS_PROTO_ERR	: Firmware detected a protocol error. + *					  ex target sent more data than + *					  requested, or there was data frame + *					  loss and other reasons + * 					  - io-tag cannot be used yet. + * + * 	BFI_IOIM_STS_DIF_ERR	: Firwmare detected DIF error. ex: DIF + * 					  CRC err or Ref Tag err or App tag err. + * 					  - io-tag can be reused. + * + * 	BFA_IOIM_STS_TSK_MGT_ABORT	: IO was aborted because of Task + *					  Management command from the host + * 					  - io-tag can be reused. + * + * 	BFI_IOIM_STS_UTAG		: Firmware does not know about this + *					  io_tag. + * 					  - io-tag can be reused. + */ +enum bfi_ioim_status { +	BFI_IOIM_STS_OK = 0, +	BFI_IOIM_STS_HOST_ABORTED = 1, +	BFI_IOIM_STS_ABORTED = 2, +	BFI_IOIM_STS_TIMEDOUT = 3, +	BFI_IOIM_STS_RES_FREE = 4, +	BFI_IOIM_STS_SQER_NEEDED = 5, +	BFI_IOIM_STS_PROTO_ERR = 6, +	BFI_IOIM_STS_UTAG = 7, +	BFI_IOIM_STS_PATHTOV = 8, +}; + +#define BFI_IOIM_SNSLEN	(256) +/** + * I/O response message + */ +struct bfi_ioim_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header	 	 */ +	u16        io_tag;		/*  completed IO tag		 */ +	u16        bfa_rport_hndl;	/*  releated rport handle	 */ +	u8         io_status;	/*  IO completion status	 */ +	u8         reuse_io_tag;	/*  IO tag can be reused        */ +	u16	abort_tag;	/*  host abort request tag      */ +	u8		scsi_status;	/*  scsi status from target	 */ +	u8		sns_len;	/*  scsi sense length		 */ +	u8		resid_flags;	/*  IO residue flags		 */ +	u8		rsvd_a; +	u32	residue;	/*  IO residual length in bytes */ +	u32	rsvd_b[3]; +}; + +struct bfi_ioim_abort_req_s { +	struct bfi_mhdr_s  mh;          /*  Common msg header  */ +	u16        io_tag;         /*  I/O tag            */ +	u16        abort_tag;      /*  unique request tag */ +}; + +/* + * Initiator mode task management command interface defines. + */ + +enum bfi_tskim_h2i { +	BFI_TSKIM_H2I_TM_REQ    = 1, /*  task-mgmt command         */ +	BFI_TSKIM_H2I_ABORT_REQ = 2, /*  task-mgmt command         */ +}; + +enum bfi_tskim_i2h { +	BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1), +}; + +struct bfi_tskim_req_s { +	struct bfi_mhdr_s  mh;             /*  Common msg header          */ +	u16        tsk_tag;        /*  task management tag        */ +	u16        itn_fhdl;       /*  itn firmware handle        */ +	lun_t           lun;            /*  LU number                  */ +	u8         tm_flags;       /*  see fcp_tm_cmnd_t          */ +	u8         t_secs;         /*  Timeout value in seconds   */ +	u8         rsvd[2]; +}; + +struct bfi_tskim_abortreq_s { +	struct bfi_mhdr_s  mh;             /*  Common msg header          */ +	u16        tsk_tag;        /*  task management tag        */ +	u16        rsvd; +}; + +enum bfi_tskim_status { +	/* +	 * Following are FCP-4 spec defined status codes, +	 * **DO NOT CHANGE THEM ** +	 */ +	BFI_TSKIM_STS_OK       = 0, +	BFI_TSKIM_STS_NOT_SUPP = 4, +	BFI_TSKIM_STS_FAILED   = 5, + +	/** +	 * Defined by BFA +	 */ +	BFI_TSKIM_STS_TIMEOUT  = 10,    /*  TM request timedout     */ +	BFI_TSKIM_STS_ABORTED  = 11,    /*  Aborted on host request */ +}; + +struct bfi_tskim_rsp_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		 */ +	u16        tsk_tag;	/*  task mgmt cmnd tag		 */ +	u8         tsk_status;	/*  @ref bfi_tskim_status */ +	u8         rsvd; +}; + +#pragma pack() + +#endif /* __BFI_FCPIM_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcxp.h b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h new file mode 100644 index 00000000000..e0e995a3282 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_FCXP_H__ +#define __BFI_FCXP_H__ + +#include "bfi.h" + +#pragma pack(1) + +enum bfi_fcxp_h2i { +	BFI_FCXP_H2I_SEND_REQ = 1, +}; + +enum bfi_fcxp_i2h { +	BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1), +}; + +#define BFA_FCXP_MAX_SGES	2 + +/** + * FCXP send request structure + */ +struct bfi_fcxp_send_req_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		    */ +	u16        fcxp_tag;	/*  driver request tag		    */ +	u16        max_frmsz;	/*  max send frame size	    */ +	u16        vf_id;		/*  vsan tag if applicable	    */ +	u16        rport_fw_hndl;	/*  FW Handle for the remote port  */ +	u8         class;		/*  FC class used for req/rsp	    */ +	u8         rsp_timeout;	/*  timeout in secs, 0-no response */ +	u8         cts;		/*  continue sequence		    */ +	u8         lp_tag;		/*  lport tag			    */ +	struct fchs_s   fchs;		/*  request FC header structure    */ +	u32        req_len;	/*  request payload length	    */ +	u32        rsp_maxlen;	/*  max response length expected   */ +	struct bfi_sge_s   req_sge[BFA_FCXP_MAX_SGES];	/*  request buf    */ +	struct bfi_sge_s   rsp_sge[BFA_FCXP_MAX_SGES];	/*  response buf   */ +}; + +/** + * FCXP send response structure + */ +struct bfi_fcxp_send_rsp_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		    */ +	u16        fcxp_tag;	/*  send request tag		    */ +	u8         req_status;	/*  request status		    */ +	u8         rsvd; +	u32        rsp_len;	/*  actual response length	    */ +	u32        residue_len;	/*  residual response length	    */ +	struct fchs_s   fchs;		/*  response FC header structure   */ +}; + +#pragma pack() + +#endif /* __BFI_FCXP_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h new file mode 100644 index 00000000000..026e9c06ae9 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_IOC_H__ +#define __BFI_IOC_H__ + +#include "bfi.h" +#include <defs/bfa_defs_ioc.h> + +#pragma pack(1) + +enum bfi_ioc_h2i_msgs { +	BFI_IOC_H2I_ENABLE_REQ 		= 1, +	BFI_IOC_H2I_DISABLE_REQ 	= 2, +	BFI_IOC_H2I_GETATTR_REQ 	= 3, +	BFI_IOC_H2I_DBG_SYNC	 	= 4, +	BFI_IOC_H2I_DBG_DUMP	 	= 5, +}; + +enum bfi_ioc_i2h_msgs { +	BFI_IOC_I2H_ENABLE_REPLY	= BFA_I2HM(1), +	BFI_IOC_I2H_DISABLE_REPLY 	= BFA_I2HM(2), +	BFI_IOC_I2H_GETATTR_REPLY 	= BFA_I2HM(3), +	BFI_IOC_I2H_READY_EVENT 	= BFA_I2HM(4), +	BFI_IOC_I2H_HBEAT		= BFA_I2HM(5), +}; + +/** + * BFI_IOC_H2I_GETATTR_REQ message + */ +struct bfi_ioc_getattr_req_s { +	struct bfi_mhdr_s	mh; +	union bfi_addr_u	attr_addr; +}; + +struct bfi_ioc_attr_s { +	wwn_t           mfg_wwn; +	mac_t		mfg_mac; +	u16	rsvd_a; +	char            brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; +	u8         pcie_gen; +	u8         pcie_lanes_orig; +	u8         pcie_lanes; +	u8         rx_bbcredit;	/*  receive buffer credits */ +	u32        adapter_prop;	/*  adapter properties     */ +	u16        maxfrsize;	/*  max receive frame size */ +	char         	asic_rev; +	u8         rsvd_b; +	char            fw_version[BFA_VERSION_LEN]; +	char            optrom_version[BFA_VERSION_LEN]; +	struct bfa_mfg_vpd_s	vpd; +}; + +/** + * BFI_IOC_I2H_GETATTR_REPLY message + */ +struct bfi_ioc_getattr_reply_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header          */ +	u8		status;	/*  cfg reply status           */ +	u8		rsvd[3]; +}; + +/** + * Firmware memory page offsets + */ +#define BFI_IOC_SMEM_PG0_CB	(0x40) +#define BFI_IOC_SMEM_PG0_CT	(0x180) + +/** + * Firmware trace offset + */ +#define BFI_IOC_TRC_OFF		(0x4b00) +#define BFI_IOC_TRC_ENTS	256 + +#define BFI_IOC_FW_SIGNATURE	(0xbfadbfad) +#define BFI_IOC_MD5SUM_SZ	4 +struct bfi_ioc_image_hdr_s { +	u32        signature;	/*  constant signature */ +	u32        rsvd_a; +	u32        exec;		/*  exec vector        */ +	u32        param;		/*  parameters         */ +	u32        rsvd_b[4]; +	u32        md5sum[BFI_IOC_MD5SUM_SZ]; +}; + +/** + *  BFI_IOC_I2H_READY_EVENT message + */ +struct bfi_ioc_rdy_event_s { +	struct bfi_mhdr_s  mh;			/*  common msg header */ +	u8         init_status;	/*  init event status */ +	u8         rsvd[3]; +}; + +struct bfi_ioc_hbeat_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u32	   hb_count;	/*  current heart beat count	*/ +}; + +/** + * IOC hardware/firmware state + */ +enum bfi_ioc_state { +	BFI_IOC_UNINIT 	 = 0,		/*  not initialized                 */ +	BFI_IOC_INITING 	 = 1,	/*  h/w is being initialized        */ +	BFI_IOC_HWINIT 	 = 2,		/*  h/w is initialized              */ +	BFI_IOC_CFG 	 = 3,		/*  IOC configuration in progress   */ +	BFI_IOC_OP 		 = 4,	/*  IOC is operational              */ +	BFI_IOC_DISABLING 	 = 5,	/*  IOC is being disabled           */ +	BFI_IOC_DISABLED 	 = 6,	/*  IOC is disabled                 */ +	BFI_IOC_CFG_DISABLED = 7,	/*  IOC is being disabled;transient */ +	BFI_IOC_HBFAIL       = 8,	/*  IOC heart-beat failure          */ +	BFI_IOC_MEMTEST      = 9,	/*  IOC is doing memtest            */ +}; + +#define BFI_IOC_ENDIAN_SIG  0x12345678 + +enum { +	BFI_ADAPTER_TYPE_FC   = 0x01,		/*  FC adapters           */ +	BFI_ADAPTER_TYPE_MK   = 0x0f0000,	/*  adapter type mask     */ +	BFI_ADAPTER_TYPE_SH   = 16,	        /*  adapter type shift    */ +	BFI_ADAPTER_NPORTS_MK = 0xff00,		/*  number of ports mask  */ +	BFI_ADAPTER_NPORTS_SH = 8,	        /*  number of ports shift */ +	BFI_ADAPTER_SPEED_MK  = 0xff,		/*  adapter speed mask    */ +	BFI_ADAPTER_SPEED_SH  = 0,	        /*  adapter speed shift   */ +	BFI_ADAPTER_PROTO     = 0x100000,	/*  prototype adapaters   */ +	BFI_ADAPTER_TTV       = 0x200000,	/*  TTV debug capable     */ +	BFI_ADAPTER_UNSUPP    = 0x400000,	/*  unknown adapter type  */ +}; + +#define BFI_ADAPTER_GETP(__prop,__adap_prop)          		\ +    (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >>         \ +     BFI_ADAPTER_ ## __prop ## _SH) +#define BFI_ADAPTER_SETP(__prop, __val)         		\ +    ((__val) << BFI_ADAPTER_ ## __prop ## _SH) +#define BFI_ADAPTER_IS_PROTO(__adap_type)   			\ +    ((__adap_type) & BFI_ADAPTER_PROTO) +#define BFI_ADAPTER_IS_TTV(__adap_type)     			\ +    ((__adap_type) & BFI_ADAPTER_TTV) +#define BFI_ADAPTER_IS_UNSUPP(__adap_type)  			\ +    ((__adap_type) & BFI_ADAPTER_UNSUPP) +#define BFI_ADAPTER_IS_SPECIAL(__adap_type)                     \ +    ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO |     \ +			BFI_ADAPTER_UNSUPP)) + +/** + * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages + */ +struct bfi_ioc_ctrl_req_s { +	struct bfi_mhdr_s	mh; +	u8			ioc_class; +	u8         	rsvd[3]; +}; + +/** + * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages + */ +struct bfi_ioc_ctrl_reply_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header     */ +	u8         status;		/*  enable/disable status */ +	u8         rsvd[3]; +}; + +#define BFI_IOC_MSGSZ   8 +/** + * H2I Messages + */ +union bfi_ioc_h2i_msg_u { +	struct bfi_mhdr_s 	mh; +	struct bfi_ioc_ctrl_req_s enable_req; +	struct bfi_ioc_ctrl_req_s disable_req; +	struct bfi_ioc_getattr_req_s getattr_req; +	u32       		mboxmsg[BFI_IOC_MSGSZ]; +}; + +/** + * I2H Messages + */ +union bfi_ioc_i2h_msg_u { +	struct bfi_mhdr_s      	mh; +	struct bfi_ioc_rdy_event_s 	rdy_event; +	u32       		mboxmsg[BFI_IOC_MSGSZ]; +}; + +#pragma pack() + +#endif /* __BFI_IOC_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h new file mode 100644 index 00000000000..c3760df7257 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_IOCFC_H__ +#define __BFI_IOCFC_H__ + +#include "bfi.h" +#include <defs/bfa_defs_ioc.h> +#include <defs/bfa_defs_iocfc.h> +#include <defs/bfa_defs_boot.h> + +#pragma pack(1) + +enum bfi_iocfc_h2i_msgs { +	BFI_IOCFC_H2I_CFG_REQ 		= 1, +	BFI_IOCFC_H2I_GET_STATS_REQ 	= 2, +	BFI_IOCFC_H2I_CLEAR_STATS_REQ	= 3, +	BFI_IOCFC_H2I_SET_INTR_REQ 	= 4, +	BFI_IOCFC_H2I_UPDATEQ_REQ = 5, +}; + +enum bfi_iocfc_i2h_msgs { +	BFI_IOCFC_I2H_CFG_REPLY		= BFA_I2HM(1), +	BFI_IOCFC_I2H_GET_STATS_RSP 	= BFA_I2HM(2), +	BFI_IOCFC_I2H_CLEAR_STATS_RSP	= BFA_I2HM(3), +	BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(5), +}; + +struct bfi_iocfc_cfg_s { +	u8         num_cqs; 	/*  Number of CQs to be used     */ +	u8         sense_buf_len;	/*  SCSI sense length            */ +	u8         trunk_enabled;	/*  port trunking enabled        */ +	u8         trunk_ports;	/*  trunk ports bit map          */ +	u32        endian_sig;	/*  endian signature of host     */ + +	/** +	 * Request and response circular queue base addresses, size and +	 * shadow index pointers. +	 */ +	union bfi_addr_u  req_cq_ba[BFI_IOC_MAX_CQS]; +	union bfi_addr_u  req_shadow_ci[BFI_IOC_MAX_CQS]; +	u16    req_cq_elems[BFI_IOC_MAX_CQS]; +	union bfi_addr_u  rsp_cq_ba[BFI_IOC_MAX_CQS]; +	union bfi_addr_u  rsp_shadow_pi[BFI_IOC_MAX_CQS]; +	u16    rsp_cq_elems[BFI_IOC_MAX_CQS]; + +	union bfi_addr_u  stats_addr;	/*  DMA-able address for stats	  */ +	union bfi_addr_u  cfgrsp_addr;	/*  config response dma address  */ +	union bfi_addr_u  ioim_snsbase;  /*  IO sense buffer base address */ +	struct bfa_iocfc_intr_attr_s intr_attr; /*  IOC interrupt attributes */ +}; + +/** + * Boot target wwn information for this port. This contains either the stored + * or discovered boot target port wwns for the port. + */ +struct bfi_iocfc_bootwwns { +	wwn_t		wwn[BFA_BOOT_BOOTLUN_MAX]; +	u8		nwwns; +	u8		rsvd[7]; +}; + +struct bfi_iocfc_cfgrsp_s { +	struct bfa_iocfc_fwcfg_s	fwcfg; +	struct bfa_iocfc_intr_attr_s	intr_attr; +	struct bfi_iocfc_bootwwns	bootwwns; +}; + +/** + * BFI_IOCFC_H2I_CFG_REQ message + */ +struct bfi_iocfc_cfg_req_s { +	struct bfi_mhdr_s      mh; +	union bfi_addr_u      ioc_cfg_dma_addr; +}; + +/** + * BFI_IOCFC_I2H_CFG_REPLY message + */ +struct bfi_iocfc_cfg_reply_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header          */ +	u8         cfg_success;	/*  cfg reply status           */ +	u8         lpu_bm;		/*  LPUs assigned for this IOC */ +	u8         rsvd[2]; +}; + +/** + *  BFI_IOCFC_H2I_GET_STATS_REQ & BFI_IOCFC_H2I_CLEAR_STATS_REQ messages + */ +struct bfi_iocfc_stats_req_s { +	struct bfi_mhdr_s mh;		/*  msg header            */ +	u32        msgtag;		/*  msgtag for reply      */ +}; + +/** + * BFI_IOCFC_I2H_GET_STATS_RSP & BFI_IOCFC_I2H_CLEAR_STATS_RSP messages + */ +struct bfi_iocfc_stats_rsp_s { +	struct bfi_mhdr_s mh;		/*  common msg header     */ +	u8         status;		/*  reply status          */ +	u8         rsvd[3]; +	u32        msgtag;		/*  msgtag for reply      */ +}; + +/** + * BFI_IOCFC_H2I_SET_INTR_REQ message + */ +struct bfi_iocfc_set_intr_req_s { +	struct bfi_mhdr_s mh;		/*  common msg header     */ +	u8		coalesce;	/*  enable intr coalescing*/ +	u8         rsvd[3]; +	u16	delay;		/*  delay timer 0..1125us  */ +	u16	latency;	/*  latency timer 0..225us */ +}; + +/** + * BFI_IOCFC_H2I_UPDATEQ_REQ message + */ +struct bfi_iocfc_updateq_req_s { +	struct bfi_mhdr_s mh;		/*  common msg header     */ +	u32 reqq_ba;			/*  reqq base addr        */ +	u32 rspq_ba;			/*  rspq base addr        */ +	u32 reqq_sci;			/*  reqq shadow ci        */ +	u32 rspq_spi;			/*  rspq shadow pi        */ +}; + +/** + * BFI_IOCFC_I2H_UPDATEQ_RSP message + */ +struct bfi_iocfc_updateq_rsp_s { +	struct bfi_mhdr_s mh;		/*  common msg header     */ +	u8         status;		/*  updateq  status       */ +	u8         rsvd[3]; +}; + +/** + * H2I Messages + */ +union bfi_iocfc_h2i_msg_u { +	struct bfi_mhdr_s 		mh; +	struct bfi_iocfc_cfg_req_s 	cfg_req; +	struct bfi_iocfc_stats_req_s stats_get; +	struct bfi_iocfc_stats_req_s stats_clr; +	struct bfi_iocfc_updateq_req_s updateq_req; +	u32       			mboxmsg[BFI_IOC_MSGSZ]; +}; + +/** + * I2H Messages + */ +union bfi_iocfc_i2h_msg_u { +	struct bfi_mhdr_s      		mh; +	struct bfi_iocfc_cfg_reply_s 		cfg_reply; +	struct bfi_iocfc_stats_rsp_s stats_get_rsp; +	struct bfi_iocfc_stats_rsp_s stats_clr_rsp; +	struct bfi_iocfc_updateq_rsp_s updateq_rsp; +	u32       			mboxmsg[BFI_IOC_MSGSZ]; +}; + +#pragma pack() + +#endif /* __BFI_IOCFC_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_lport.h b/drivers/scsi/bfa/include/bfi/bfi_lport.h new file mode 100644 index 00000000000..29010614bac --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_lport.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_LPORT_H__ +#define __BFI_LPORT_H__ + +#include <bfi/bfi.h> + +#pragma pack(1) + +enum bfi_lport_h2i_msgs { +	BFI_LPORT_H2I_CREATE_REQ = 1, +	BFI_LPORT_H2I_DELETE_REQ = 2, +}; + +enum bfi_lport_i2h_msgs { +	BFI_LPORT_I2H_CREATE_RSP = BFA_I2HM(1), +	BFI_LPORT_I2H_DELETE_RSP = BFA_I2HM(2), +	BFI_LPORT_I2H_ONLINE	  = BFA_I2HM(3), +	BFI_LPORT_I2H_OFFLINE	  = BFA_I2HM(4), +}; + +#define BFI_LPORT_MAX_SYNNAME	64 + +enum bfi_lport_role_e { +	BFI_LPORT_ROLE_FCPIM	= 1, +	BFI_LPORT_ROLE_FCPTM	= 2, +	BFI_LPORT_ROLE_IPFC	= 4, +}; + +struct bfi_lport_create_req_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16	fabric_fwhdl;	/*  parent fabric instance	*/ +	u8		roles;		/*  lport FC-4 roles		*/ +	u8		rsvd; +	wwn_t		pwwn;		/*  port name			*/ +	wwn_t		nwwn;		/*  node name			*/ +	u8		symname[BFI_LPORT_MAX_SYNNAME]; +}; + +struct bfi_lport_create_rsp_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u8         status;		/*  lport creation status	*/ +	u8         rsvd[3]; +}; + +struct bfi_lport_delete_req_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        fw_handle;	/*  firmware lport handle	*/ +	u16        rsvd; +}; + +struct bfi_lport_delete_rsp_s { +	bfi_mhdr_t	mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host lport handle		*/ +	u8         status;		/*  lport deletion status	*/ +	u8         rsvd; +}; + +union bfi_lport_h2i_msg_u { +	bfi_msg_t		*msg; +	struct bfi_lport_create_req_s	*create_req; +	struct bfi_lport_delete_req_s	*delete_req; +}; + +union bfi_lport_i2h_msg_u { +	bfi_msg_t		*msg; +	struct bfi_lport_create_rsp_s	*create_rsp; +	struct bfi_lport_delete_rsp_s	*delete_rsp; +}; + +#pragma pack() + +#endif /* __BFI_LPORT_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h new file mode 100644 index 00000000000..414b0e30f6e --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_lps.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_LPS_H__ +#define __BFI_LPS_H__ + +#include <bfi/bfi.h> + +#pragma pack(1) + +enum bfi_lps_h2i_msgs { +	BFI_LPS_H2I_LOGIN_REQ	= 1, +	BFI_LPS_H2I_LOGOUT_REQ	= 2, +}; + +enum bfi_lps_i2h_msgs { +	BFI_LPS_H2I_LOGIN_RSP	= BFA_I2HM(1), +	BFI_LPS_H2I_LOGOUT_RSP	= BFA_I2HM(2), +}; + +struct bfi_lps_login_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u8		lp_tag; +	u8		alpa; +	u16	pdu_size; +	wwn_t		pwwn; +	wwn_t		nwwn; +	u8		fdisc; +	u8		auth_en; +	u8		rsvd[2]; +}; + +struct bfi_lps_login_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u8		lp_tag; +	u8		status; +	u8		lsrjt_rsn; +	u8		lsrjt_expl; +	wwn_t		port_name; +	wwn_t		node_name; +	u16	bb_credit; +	u8		f_port; +	u8		npiv_en; +	u32	lp_pid : 24; +	u32	auth_req : 8; +	mac_t		lp_mac; +	mac_t		fcf_mac; +	u8		ext_status; +	u8  	brcd_switch;/*  attached peer is brcd switch	*/ +}; + +struct bfi_lps_logout_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u8		lp_tag; +	u8		rsvd[3]; +	wwn_t		port_name; +}; + +struct bfi_lps_logout_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u8		lp_tag; +	u8		status; +	u8		rsvd[2]; +}; + +union bfi_lps_h2i_msg_u { +	struct bfi_mhdr_s		*msg; +	struct bfi_lps_login_req_s	*login_req; +	struct bfi_lps_logout_req_s	*logout_req; +}; + +union bfi_lps_i2h_msg_u { +	struct bfi_msg_s		*msg; +	struct bfi_lps_login_rsp_s	*login_rsp; +	struct bfi_lps_logout_rsp_s	*logout_rsp; +}; + +#pragma pack() + +#endif /* __BFI_LPS_H__ */ + + diff --git a/drivers/scsi/bfa/include/bfi/bfi_port.h b/drivers/scsi/bfa/include/bfi/bfi_port.h new file mode 100644 index 00000000000..3ec3bea110b --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_port.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFI_PORT_H__ +#define __BFI_PORT_H__ + +#include <bfi/bfi.h> +#include <defs/bfa_defs_pport.h> + +#pragma pack(1) + +enum bfi_port_h2i { +	BFI_PORT_H2I_ENABLE_REQ		= (1), +	BFI_PORT_H2I_DISABLE_REQ	= (2), +	BFI_PORT_H2I_GET_STATS_REQ	= (3), +	BFI_PORT_H2I_CLEAR_STATS_REQ	= (4), +}; + +enum bfi_port_i2h { +	BFI_PORT_I2H_ENABLE_RSP		= BFA_I2HM(1), +	BFI_PORT_I2H_DISABLE_RSP	= BFA_I2HM(2), +	BFI_PORT_I2H_GET_STATS_RSP	= BFA_I2HM(3), +	BFI_PORT_I2H_CLEAR_STATS_RSP	= BFA_I2HM(4), +}; + +/** + * Generic REQ type + */ +struct bfi_port_generic_req_s { +	struct bfi_mhdr_s  mh;		/*  msg header			    */ +	u32        msgtag;		/*  msgtag for reply		    */ +	u32	rsvd; +}; + +/** + * Generic RSP type + */ +struct bfi_port_generic_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		    */ +	u8         status;		/*  port enable status		    */ +	u8         rsvd[3]; +	u32        msgtag;		/*  msgtag for reply		    */ +}; + +/** + * @todo + * BFI_PORT_H2I_ENABLE_REQ + */ + +/** + * @todo + * BFI_PORT_I2H_ENABLE_RSP + */ + +/** + * BFI_PORT_H2I_DISABLE_REQ + */ + +/** + * BFI_PORT_I2H_DISABLE_RSP + */ + +/** + * BFI_PORT_H2I_GET_STATS_REQ + */ +struct bfi_port_get_stats_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		    */ +	union bfi_addr_u   dma_addr; +}; + +/** + * BFI_PORT_I2H_GET_STATS_RSP + */ + +/** + * BFI_PORT_H2I_CLEAR_STATS_REQ + */ + +/** + * BFI_PORT_I2H_CLEAR_STATS_RSP + */ + +union bfi_port_h2i_msg_u { +	struct bfi_mhdr_s		mh; +	struct bfi_port_generic_req_s	enable_req; +	struct bfi_port_generic_req_s	disable_req; +	struct bfi_port_get_stats_req_s	getstats_req; +	struct bfi_port_generic_req_s	clearstats_req; +}; + +union bfi_port_i2h_msg_u { +	struct bfi_mhdr_s         	mh; +	struct bfi_port_generic_rsp_s	enable_rsp; +	struct bfi_port_generic_rsp_s	disable_rsp; +	struct bfi_port_generic_rsp_s	getstats_rsp; +	struct bfi_port_generic_rsp_s	clearstats_rsp; +}; + +#pragma pack() + +#endif /* __BFI_PORT_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_pport.h b/drivers/scsi/bfa/include/bfi/bfi_pport.h new file mode 100644 index 00000000000..c96d246851a --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_pport.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFI_PPORT_H__ +#define __BFI_PPORT_H__ + +#include <bfi/bfi.h> +#include <defs/bfa_defs_pport.h> + +#pragma pack(1) + +enum bfi_pport_h2i { +	BFI_PPORT_H2I_ENABLE_REQ		= (1), +	BFI_PPORT_H2I_DISABLE_REQ		= (2), +	BFI_PPORT_H2I_GET_STATS_REQ		= (3), +	BFI_PPORT_H2I_CLEAR_STATS_REQ	= (4), +	BFI_PPORT_H2I_SET_SVC_PARAMS_REQ	= (5), +	BFI_PPORT_H2I_ENABLE_RX_VF_TAG_REQ	= (6), +	BFI_PPORT_H2I_ENABLE_TX_VF_TAG_REQ	= (7), +	BFI_PPORT_H2I_GET_QOS_STATS_REQ		= (8), +	BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ	= (9), +}; + +enum bfi_pport_i2h { +	BFI_PPORT_I2H_ENABLE_RSP		= BFA_I2HM(1), +	BFI_PPORT_I2H_DISABLE_RSP		= BFA_I2HM(2), +	BFI_PPORT_I2H_GET_STATS_RSP		= BFA_I2HM(3), +	BFI_PPORT_I2H_CLEAR_STATS_RSP	= BFA_I2HM(4), +	BFI_PPORT_I2H_SET_SVC_PARAMS_RSP	= BFA_I2HM(5), +	BFI_PPORT_I2H_ENABLE_RX_VF_TAG_RSP	= BFA_I2HM(6), +	BFI_PPORT_I2H_ENABLE_TX_VF_TAG_RSP	= BFA_I2HM(7), +	BFI_PPORT_I2H_EVENT			= BFA_I2HM(8), +	BFI_PPORT_I2H_GET_QOS_STATS_RSP		= BFA_I2HM(9), +	BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP	= BFA_I2HM(10), +}; + +/** + * Generic REQ type + */ +struct bfi_pport_generic_req_s { +	struct bfi_mhdr_s  mh;		/*  msg header			    */ +	u32        msgtag;		/*  msgtag for reply		    */ +}; + +/** + * Generic RSP type + */ +struct bfi_pport_generic_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		    */ +	u8         status;		/*  port enable status		    */ +	u8         rsvd[3]; +	u32        msgtag;		/*  msgtag for reply		    */ +}; + +/** + * BFI_PPORT_H2I_ENABLE_REQ + */ +struct bfi_pport_enable_req_s { +	struct bfi_mhdr_s  mh;		/*  msg header			    */ +	u32        rsvd1; +	wwn_t           nwwn;		/*  node wwn of physical port	    */ +	wwn_t           pwwn;		/*  port wwn of physical port	    */ +	struct bfa_pport_cfg_s port_cfg;	/*  port configuration	    */ +	union bfi_addr_u  stats_dma_addr;	/*  DMA address for stats  */ +	u32        msgtag;		/*  msgtag for reply		    */ +	u32        rsvd2; +}; + +/** + * BFI_PPORT_I2H_ENABLE_RSP + */ +#define bfi_pport_enable_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_DISABLE_REQ + */ +#define bfi_pport_disable_req_t struct bfi_pport_generic_req_s + +/** + * BFI_PPORT_I2H_DISABLE_RSP + */ +#define bfi_pport_disable_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_GET_STATS_REQ + */ +#define bfi_pport_get_stats_req_t struct bfi_pport_generic_req_s + +/** + * BFI_PPORT_I2H_GET_STATS_RSP + */ +#define bfi_pport_get_stats_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_CLEAR_STATS_REQ + */ +#define bfi_pport_clear_stats_req_t struct bfi_pport_generic_req_s + +/** + * BFI_PPORT_I2H_CLEAR_STATS_RSP + */ +#define bfi_pport_clear_stats_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_GET_QOS_STATS_REQ + */ +#define bfi_pport_get_qos_stats_req_t struct bfi_pport_generic_req_s + +/** + * BFI_PPORT_H2I_GET_QOS_STATS_RSP + */ +#define bfi_pport_get_qos_stats_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ + */ +#define bfi_pport_clear_qos_stats_req_t struct bfi_pport_generic_req_s + +/** + * BFI_PPORT_H2I_CLEAR_QOS_STATS_RSP + */ +#define bfi_pport_clear_qos_stats_rsp_t struct bfi_pport_generic_rsp_s + +/** + * BFI_PPORT_H2I_SET_SVC_PARAMS_REQ + */ +struct bfi_pport_set_svc_params_req_s { +	struct bfi_mhdr_s  mh;		/*  msg header */ +	u16        tx_bbcredit;	/*  Tx credits */ +	u16        rsvd; +}; + +/** + * BFI_PPORT_I2H_SET_SVC_PARAMS_RSP + */ + +/** + * BFI_PPORT_I2H_EVENT + */ +struct bfi_pport_event_s { +	struct bfi_mhdr_s 	mh;	/*  common msg header */ +	struct bfa_pport_link_s	link_state; +}; + +union bfi_pport_h2i_msg_u { +	struct bfi_mhdr_s			*mhdr; +	struct bfi_pport_enable_req_s		*penable; +	struct bfi_pport_generic_req_s		*pdisable; +	struct bfi_pport_generic_req_s		*pgetstats; +	struct bfi_pport_generic_req_s		*pclearstats; +	struct bfi_pport_set_svc_params_req_s	*psetsvcparams; +	struct bfi_pport_get_qos_stats_req_s	*pgetqosstats; +	struct bfi_pport_generic_req_s		*pclearqosstats; +}; + +union bfi_pport_i2h_msg_u { +	struct bfi_msg_s			*msg; +	struct bfi_pport_generic_rsp_s		*enable_rsp; +	struct bfi_pport_disable_rsp_s		*disable_rsp; +	struct bfi_pport_generic_rsp_s		*getstats_rsp; +	struct bfi_pport_clear_stats_rsp_s	*clearstats_rsp; +	struct bfi_pport_set_svc_params_rsp_s	*setsvcparasm_rsp; +	struct bfi_pport_get_qos_stats_rsp_s	*getqosstats_rsp; +	struct bfi_pport_clear_qos_stats_rsp_s	*clearqosstats_rsp; +	struct bfi_pport_event_s		*event; +}; + +#pragma pack() + +#endif /* __BFI_PPORT_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h new file mode 100644 index 00000000000..3520f55f09d --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_rport.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_RPORT_H__ +#define __BFI_RPORT_H__ + +#include <bfi/bfi.h> + +#pragma pack(1) + +enum bfi_rport_h2i_msgs { +	BFI_RPORT_H2I_CREATE_REQ = 1, +	BFI_RPORT_H2I_DELETE_REQ = 2, +	BFI_RPORT_H2I_SET_SPEED_REQ  = 3, +}; + +enum bfi_rport_i2h_msgs { +	BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1), +	BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2), +	BFI_RPORT_I2H_QOS_SCN    = BFA_I2HM(3), +}; + +struct bfi_rport_create_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host rport handle		*/ +	u16        max_frmsz;	/*  max rcv pdu size		*/ +	u32        pid       : 24,	/*  remote port ID		*/ +			lp_tag    : 8;	/*  local port tag		*/ +	u32        local_pid : 24,	/*  local port ID		*/ +			cisc      : 8; +	u8         fc_class;	/*  supported FC classes	*/ +	u8         vf_en;		/*  virtual fabric enable	*/ +	u16        vf_id;		/*  virtual fabric ID		*/ +}; + +struct bfi_rport_create_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u8         status;		/*  rport creation status	*/ +	u8         rsvd[3]; +	u16        bfa_handle;	/*  host rport handle		*/ +	u16        fw_handle;	/*  firmware rport handle	*/ +	struct bfa_rport_qos_attr_s qos_attr;  /* QoS Attributes */ +}; + +struct bfa_rport_speed_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u16        fw_handle;	/*  firmware rport handle	*/ +	u8		speed;		/*! rport's speed via RPSC  */ +	u8		rsvd; +}; + +struct bfi_rport_delete_req_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u16        fw_handle;	/*  firmware rport handle	*/ +	u16        rsvd; +}; + +struct bfi_rport_delete_rsp_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host rport handle		*/ +	u8         status;		/*  rport deletion status	*/ +	u8         rsvd; +}; + +struct bfi_rport_qos_scn_s { +	struct bfi_mhdr_s  mh;		/*  common msg header		*/ +	u16        bfa_handle;	/*  host rport handle		*/ +	u16        rsvd; +	struct bfa_rport_qos_attr_s old_qos_attr;  /* Old QoS Attributes */ +	struct bfa_rport_qos_attr_s new_qos_attr;  /* New QoS Attributes */ +}; + +union bfi_rport_h2i_msg_u { +	struct bfi_msg_s 		*msg; +	struct bfi_rport_create_req_s	*create_req; +	struct bfi_rport_delete_req_s	*delete_req; +	struct bfi_rport_speed_req_s	*speed_req; +}; + +union bfi_rport_i2h_msg_u { +	struct bfi_msg_s 		*msg; +	struct bfi_rport_create_rsp_s	*create_rsp; +	struct bfi_rport_delete_rsp_s	*delete_rsp; +	struct bfi_rport_qos_scn_s	*qos_scn_evt; +}; + +#pragma pack() + +#endif /* __BFI_RPORT_H__ */ + diff --git a/drivers/scsi/bfa/include/bfi/bfi_uf.h b/drivers/scsi/bfa/include/bfi/bfi_uf.h new file mode 100644 index 00000000000..f328a9e7e62 --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_uf.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_UF_H__ +#define __BFI_UF_H__ + +#include "bfi.h" + +#pragma pack(1) + +enum bfi_uf_h2i { +	BFI_UF_H2I_BUF_POST = 1, +}; + +enum bfi_uf_i2h { +	BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1), +}; + +#define BFA_UF_MAX_SGES	2 + +struct bfi_uf_buf_post_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		*/ +	u16        buf_tag;	/*  buffer tag			*/ +	u16        buf_len;	/*  total buffer length	*/ +	struct bfi_sge_s   sge[BFA_UF_MAX_SGES]; /*  buffer DMA SGEs	*/ +}; + +struct bfi_uf_frm_rcvd_s { +	struct bfi_mhdr_s  mh;		/*  Common msg header		*/ +	u16        buf_tag;	/*  buffer tag			*/ +	u16        rsvd; +	u16        frm_len;	/*  received frame length 	*/ +	u16        xfr_len;	/*  tranferred length		*/ +}; + +#pragma pack() + +#endif /* __BFI_UF_H__ */ diff --git a/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h new file mode 100644 index 00000000000..43ba7064e81 --- /dev/null +++ b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_cna_trcmod.h CNA trace modules + */ + +#ifndef __BFA_CNA_TRCMOD_H__ +#define __BFA_CNA_TRCMOD_H__ + +#include <cs/bfa_trc.h> + +/* + * !!! Only append to the enums defined here to avoid any versioning + * !!! needed between trace utility and driver version + */ +enum { +	BFA_TRC_CNA_CEE		= 1, +	BFA_TRC_CNA_PORT	= 2, +}; + +#endif /* __BFA_CNA_TRCMOD_H__ */ diff --git a/drivers/scsi/bfa/include/cna/cee/bfa_cee.h b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h new file mode 100644 index 00000000000..77f297f6804 --- /dev/null +++ b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_CEE_H__ +#define __BFA_CEE_H__ + +#include <defs/bfa_defs_cee.h> +#include <bfa_ioc.h> +#include <cs/bfa_trc.h> +#include <cs/bfa_log.h> + +typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status); +typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status); +typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status); +typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, bfa_status_t status); + +struct bfa_cee_cbfn_s { +	bfa_cee_get_attr_cbfn_t    get_attr_cbfn; +	void *get_attr_cbarg; +	bfa_cee_get_stats_cbfn_t   get_stats_cbfn; +	void *get_stats_cbarg; +	bfa_cee_reset_stats_cbfn_t reset_stats_cbfn; +	void *reset_stats_cbarg; +}; + +struct bfa_cee_s { +	void *dev; +	bfa_boolean_t get_attr_pending; +	bfa_boolean_t get_stats_pending; +	bfa_boolean_t reset_stats_pending; +	bfa_status_t get_attr_status; +	bfa_status_t get_stats_status; +	bfa_status_t reset_stats_status; +	struct bfa_cee_cbfn_s cbfn; +	struct bfa_ioc_hbfail_notify_s hbfail; +	struct bfa_trc_mod_s *trcmod; +	struct bfa_log_mod_s *logmod; +	struct bfa_cee_attr_s *attr; +	struct bfa_cee_stats_s *stats; +	struct bfa_dma_s attr_dma; +	struct bfa_dma_s stats_dma; +	struct bfa_ioc_s *ioc; +	struct bfa_mbox_cmd_s get_cfg_mb; +	struct bfa_mbox_cmd_s get_stats_mb; +	struct bfa_mbox_cmd_s reset_stats_mb; +}; + +u32 bfa_cee_meminfo(void); +void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, +			 u64 dma_pa); +void bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev, +			struct bfa_trc_mod_s *trcmod, +			struct bfa_log_mod_s *logmod); +void bfa_cee_detach(struct bfa_cee_s *cee); +bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee, +			 struct bfa_cee_attr_s *attr, +			bfa_cee_get_attr_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee, +			struct bfa_cee_stats_s *stats, +			bfa_cee_get_stats_cbfn_t cbfn, void *cbarg); +bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee, +			bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg); +#endif /* __BFA_CEE_H__ */ diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h new file mode 100644 index 00000000000..7cbf17d3141 --- /dev/null +++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_PORT_H__ +#define __BFA_PORT_H__ + +#include <defs/bfa_defs_port.h> +#include <bfa_ioc.h> +#include <cs/bfa_trc.h> +#include <cs/bfa_log.h> + +typedef void    (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status); +typedef void    (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status); + +struct bfa_port_s { +	void           *dev; +	struct bfa_ioc_s *ioc; +	struct bfa_trc_mod_s *trcmod; +	struct bfa_log_mod_s *logmod; +	u32        msgtag; +	bfa_boolean_t   stats_busy; +	struct bfa_mbox_cmd_s stats_mb; +	bfa_port_stats_cbfn_t stats_cbfn; +	void           *stats_cbarg; +	bfa_status_t    stats_status; +	union bfa_pport_stats_u *stats; +	struct bfa_dma_s stats_dma; +	bfa_boolean_t   endis_pending; +	struct bfa_mbox_cmd_s endis_mb; +	bfa_port_endis_cbfn_t endis_cbfn; +	void           *endis_cbarg; +	bfa_status_t    endis_status; +	struct bfa_ioc_hbfail_notify_s hbfail; +}; + +void            bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, +				void *dev, struct bfa_trc_mod_s *trcmod, +				struct bfa_log_mod_s *logmod); +void            bfa_port_detach(struct bfa_port_s *port); +void            bfa_port_hbfail(void *arg); + +bfa_status_t    bfa_port_get_stats(struct bfa_port_s *port, +				   union bfa_pport_stats_u *stats, +				   bfa_port_stats_cbfn_t cbfn, void *cbarg); +bfa_status_t    bfa_port_clear_stats(struct bfa_port_s *port, +				     bfa_port_stats_cbfn_t cbfn, void *cbarg); +bfa_status_t    bfa_port_enable(struct bfa_port_s *port, +				bfa_port_endis_cbfn_t cbfn, void *cbarg); +bfa_status_t    bfa_port_disable(struct bfa_port_s *port, +				 bfa_port_endis_cbfn_t cbfn, void *cbarg); +u32        bfa_port_meminfo(void); +void            bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, +				   u64 dma_pa); + +#endif /* __BFA_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h new file mode 100644 index 00000000000..1563ee51221 --- /dev/null +++ b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved. + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __ETHPORT_DEFS_H__ +#define __ETHPORT_DEFS_H__ + +struct bnad_drv_stats { +	u64 netif_queue_stop; +	u64 netif_queue_wakeup; +	u64 tso4; +	u64 tso6; +	u64 tso_err; +	u64 tcpcsum_offload; +	u64 udpcsum_offload; +	u64 csum_help; +	u64 csum_help_err; + +	u64 hw_stats_updates; +	u64 netif_rx_schedule; +	u64 netif_rx_complete; +	u64 netif_rx_dropped; +}; +#endif diff --git a/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h new file mode 100644 index 00000000000..eb7548030d0 --- /dev/null +++ b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved. + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __PHYPORT_DEFS_H__ +#define __PHYPORT_DEFS_H__ + +#define BNA_TXF_ID_MAX  	64 +#define BNA_RXF_ID_MAX  	64 + +/* + * Statistics + */ + +/* + * TxF Frame Statistics + */ +struct bna_stats_txf { +	u64        ucast_octets; +	u64        ucast; +	u64        ucast_vlan; + +	u64        mcast_octets; +	u64        mcast; +	u64        mcast_vlan; + +	u64        bcast_octets; +	u64        bcast; +	u64        bcast_vlan; + +	u64        errors; +	u64        filter_vlan;	/* frames filtered due to VLAN */ +	u64        filter_mac_sa;	/* frames filtered due to SA check */ +}; + +/* + * RxF Frame Statistics + */ +struct bna_stats_rxf { +	u64        ucast_octets; +	u64        ucast; +	u64        ucast_vlan; + +	u64        mcast_octets; +	u64        mcast; +	u64        mcast_vlan; + +	u64        bcast_octets; +	u64        bcast; +	u64        bcast_vlan; +	u64        frame_drops; +}; + +/* + * FC Tx Frame Statistics + */ +struct bna_stats_fc_tx { +	u64        txf_ucast_octets; +	u64        txf_ucast; +	u64        txf_ucast_vlan; + +	u64        txf_mcast_octets; +	u64        txf_mcast; +	u64        txf_mcast_vlan; + +	u64        txf_bcast_octets; +	u64        txf_bcast; +	u64        txf_bcast_vlan; + +	u64        txf_parity_errors; +	u64        txf_timeout; +	u64        txf_fid_parity_errors; +}; + +/* + * FC Rx Frame Statistics + */ +struct bna_stats_fc_rx { +	u64        rxf_ucast_octets; +	u64        rxf_ucast; +	u64        rxf_ucast_vlan; + +	u64        rxf_mcast_octets; +	u64        rxf_mcast; +	u64        rxf_mcast_vlan; + +	u64        rxf_bcast_octets; +	u64        rxf_bcast; +	u64        rxf_bcast_vlan; +}; + +/* + * RAD Frame Statistics + */ +struct cna_stats_rad { +	u64        rx_frames; +	u64        rx_octets; +	u64        rx_vlan_frames; + +	u64        rx_ucast; +	u64        rx_ucast_octets; +	u64        rx_ucast_vlan; + +	u64        rx_mcast; +	u64        rx_mcast_octets; +	u64        rx_mcast_vlan; + +	u64        rx_bcast; +	u64        rx_bcast_octets; +	u64        rx_bcast_vlan; + +	u64        rx_drops; +}; + +/* + * BPC Tx Registers + */ +struct cna_stats_bpc_tx { +	u64        tx_pause[8]; +	u64        tx_zero_pause[8];	/*  Pause cancellation */ +	u64        tx_first_pause[8];	/*  Pause initiation rather +						 *than retention */ +}; + +/* + * BPC Rx Registers + */ +struct cna_stats_bpc_rx { +	u64        rx_pause[8]; +	u64        rx_zero_pause[8];	/*  Pause cancellation */ +	u64        rx_first_pause[8];	/*  Pause initiation rather +						 *than retention */ +}; + +/* + * MAC Rx Statistics + */ +struct cna_stats_mac_rx { +	u64        frame_64;	/* both rx and tx counter */ +	u64        frame_65_127;	/* both rx and tx counter */ +	u64        frame_128_255;	/* both rx and tx counter */ +	u64        frame_256_511;	/* both rx and tx counter */ +	u64        frame_512_1023;	/* both rx and tx counter */ +	u64        frame_1024_1518;	/* both rx and tx counter */ +	u64        frame_1518_1522;	/* both rx and tx counter */ +	u64        rx_bytes; +	u64        rx_packets; +	u64        rx_fcs_error; +	u64        rx_multicast; +	u64        rx_broadcast; +	u64        rx_control_frames; +	u64        rx_pause; +	u64        rx_unknown_opcode; +	u64        rx_alignment_error; +	u64        rx_frame_length_error; +	u64        rx_code_error; +	u64        rx_carrier_sense_error; +	u64        rx_undersize; +	u64        rx_oversize; +	u64        rx_fragments; +	u64        rx_jabber; +	u64        rx_drop; +}; + +/* + * MAC Tx Statistics + */ +struct cna_stats_mac_tx { +	u64        tx_bytes; +	u64        tx_packets; +	u64        tx_multicast; +	u64        tx_broadcast; +	u64        tx_pause; +	u64        tx_deferral; +	u64        tx_excessive_deferral; +	u64        tx_single_collision; +	u64        tx_muliple_collision; +	u64        tx_late_collision; +	u64        tx_excessive_collision; +	u64        tx_total_collision; +	u64        tx_pause_honored; +	u64        tx_drop; +	u64        tx_jabber; +	u64        tx_fcs_error; +	u64        tx_control_frame; +	u64        tx_oversize; +	u64        tx_undersize; +	u64        tx_fragments; +}; + +/* + * Complete statistics + */ +struct bna_stats { +	struct cna_stats_mac_rx mac_rx_stats; +	struct cna_stats_bpc_rx bpc_rx_stats; +	struct cna_stats_rad rad_stats; +	struct bna_stats_fc_rx fc_rx_stats; +	struct cna_stats_mac_tx mac_tx_stats; +	struct cna_stats_bpc_tx bpc_tx_stats; +	struct bna_stats_fc_tx fc_tx_stats; +	struct bna_stats_rxf rxf_stats[BNA_TXF_ID_MAX]; +	struct bna_stats_txf txf_stats[BNA_RXF_ID_MAX]; +}; + +#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h new file mode 100644 index 00000000000..af8c1d533ba --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_checksum.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_checksum.h BFA checksum utilities + */ + +#ifndef __BFA_CHECKSUM_H__ +#define __BFA_CHECKSUM_H__ + +static inline u32 +bfa_checksum_u32(u32 *buf, int sz) +{ +	int		i, m = sz >> 2; +	u32	sum = 0; + +	for (i = 0; i < m; i++) +		sum ^= buf[i]; + +	return (sum); +} + +static inline u16 +bfa_checksum_u16(u16 *buf, int sz) +{ +	int             i, m = sz >> 1; +	u16        sum = 0; + +	for (i = 0; i < m; i++) +		sum ^= buf[i]; + +	return (sum); +} + +static inline u8 +bfa_checksum_u8(u8 *buf, int sz) +{ +	int             i; +	u8         sum = 0; + +	for (i = 0; i < sz; i++) +		sum ^= buf[i]; + +	return (sum); +} +#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h new file mode 100644 index 00000000000..441be86b1b0 --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_debug.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_debug.h BFA debug interfaces + */ + +#ifndef __BFA_DEBUG_H__ +#define __BFA_DEBUG_H__ + +#define bfa_assert(__cond)	do {					\ +	if (!(__cond)) 							\ +		bfa_panic(__LINE__, __FILE__, #__cond);      \ +} while (0) + +#define bfa_sm_fault(__mod, __event)	do {				\ +	bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event);      \ +} while (0) + +#ifndef BFA_PERF_BUILD +#define bfa_assert_fp(__cond)	bfa_assert(__cond) +#else +#define bfa_assert_fp(__cond) +#endif + +struct bfa_log_mod_s; +void bfa_panic(int line, char *file, char *panicstr); +void bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event); + +#endif /* __BFA_DEBUG_H__ */ diff --git a/drivers/scsi/bfa/include/cs/bfa_log.h b/drivers/scsi/bfa/include/cs/bfa_log.h new file mode 100644 index 00000000000..761cbe22130 --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_log.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_log.h BFA log library data structure and function definition + */ + +#ifndef __BFA_LOG_H__ +#define __BFA_LOG_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_aen.h> + +/* + * BFA log module definition + * + * To create a new module id: + * Add a #define at the end of the list below. Select a value for your + * definition so that it is one (1) greater than the previous + * definition. Modify the definition of BFA_LOG_MODULE_ID_MAX to become + * your new definition. + * Should have no gaps in between the values because this is used in arrays. + * IMPORTANT: AEN_IDs must be at the begining, otherwise update bfa_defs_aen.h + */ + +enum bfa_log_module_id { +	BFA_LOG_UNUSED_ID	= 0, + +	/* AEN defs begin */ +	BFA_LOG_AEN_MIN		= BFA_LOG_UNUSED_ID, + +	BFA_LOG_AEN_ID_ADAPTER 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_ADAPTER,/* 1 */ +	BFA_LOG_AEN_ID_PORT 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_PORT,	/* 2 */ +	BFA_LOG_AEN_ID_LPORT 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_LPORT,	/* 3 */ +	BFA_LOG_AEN_ID_RPORT 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_RPORT,	/* 4 */ +	BFA_LOG_AEN_ID_ITNIM 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_ITNIM,	/* 5 */ +	BFA_LOG_AEN_ID_TIN 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_TIN,	/* 6 */ +	BFA_LOG_AEN_ID_IPFC 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_IPFC,	/* 7 */ +	BFA_LOG_AEN_ID_AUDIT 	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_AUDIT,	/* 8 */ +	BFA_LOG_AEN_ID_IOC	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_IOC,	/* 9 */ +	BFA_LOG_AEN_ID_ETHPORT	= BFA_LOG_AEN_MIN + BFA_AEN_CAT_ETHPORT,/* 10 */ + +	BFA_LOG_AEN_MAX		= BFA_LOG_AEN_ID_ETHPORT, +	/* AEN defs end */ + +	BFA_LOG_MODULE_ID_MIN	= BFA_LOG_AEN_MAX, + +	BFA_LOG_FW_ID		= BFA_LOG_MODULE_ID_MIN + 1, +	BFA_LOG_HAL_ID		= BFA_LOG_MODULE_ID_MIN + 2, +	BFA_LOG_FCS_ID		= BFA_LOG_MODULE_ID_MIN + 3, +	BFA_LOG_WDRV_ID		= BFA_LOG_MODULE_ID_MIN + 4, +	BFA_LOG_LINUX_ID	= BFA_LOG_MODULE_ID_MIN + 5, +	BFA_LOG_SOLARIS_ID	= BFA_LOG_MODULE_ID_MIN + 6, + +	BFA_LOG_MODULE_ID_MAX 	= BFA_LOG_SOLARIS_ID, + +	/* Not part of any arrays */ +	BFA_LOG_MODULE_ID_ALL 	= BFA_LOG_MODULE_ID_MAX + 1, +	BFA_LOG_AEN_ALL 	= BFA_LOG_MODULE_ID_MAX + 2, +	BFA_LOG_DRV_ALL		= BFA_LOG_MODULE_ID_MAX + 3, +}; + +/* + * BFA log catalog name + */ +#define BFA_LOG_CAT_NAME	"BFA" + +/* + * bfa log severity values + */ +enum bfa_log_severity { +	BFA_LOG_INVALID = 0, +	BFA_LOG_CRITICAL = 1, +	BFA_LOG_ERROR = 2, +	BFA_LOG_WARNING = 3, +	BFA_LOG_INFO = 4, +	BFA_LOG_NONE = 5, +	BFA_LOG_LEVEL_MAX = BFA_LOG_NONE +}; + +#define BFA_LOG_MODID_OFFSET		16 + + +struct bfa_log_msgdef_s { +	u32	msg_id;		/*  message id */ +	int		attributes;	/*  attributes */ +	int		severity;	/*  severity level */ +	char		*msg_value; +					/*  msg string */ +	char		*message; +					/*  msg format string */ +	int		arg_type;	/*  argument type */ +	int		arg_num;	/*  number of argument */ +}; + +/* + * supported argument type + */ +enum bfa_log_arg_type { +	BFA_LOG_S = 0,		/*  string */ +	BFA_LOG_D,		/*  decimal */ +	BFA_LOG_I,		/*  integer */ +	BFA_LOG_O,		/*  oct number */ +	BFA_LOG_U,		/*  unsigned integer */ +	BFA_LOG_X,		/*  hex number */ +	BFA_LOG_F,		/*  floating */ +	BFA_LOG_C,		/*  character */ +	BFA_LOG_L,		/*  double */ +	BFA_LOG_P		/*  pointer */ +}; + +#define BFA_LOG_ARG_TYPE	2 +#define BFA_LOG_ARG0		(0 * BFA_LOG_ARG_TYPE) +#define BFA_LOG_ARG1		(1 * BFA_LOG_ARG_TYPE) +#define BFA_LOG_ARG2		(2 * BFA_LOG_ARG_TYPE) +#define BFA_LOG_ARG3		(3 * BFA_LOG_ARG_TYPE) + +#define BFA_LOG_GET_MOD_ID(msgid) ((msgid >> BFA_LOG_MODID_OFFSET) & 0xff) +#define BFA_LOG_GET_MSG_IDX(msgid) (msgid & 0xffff) +#define BFA_LOG_GET_MSG_ID(msgdef) ((msgdef)->msg_id) +#define BFA_LOG_GET_MSG_FMT_STRING(msgdef) ((msgdef)->message) +#define BFA_LOG_GET_SEVERITY(msgdef) ((msgdef)->severity) + +/* + * Event attributes + */ +#define BFA_LOG_ATTR_NONE	0 +#define BFA_LOG_ATTR_AUDIT	1 +#define BFA_LOG_ATTR_LOG	2 +#define BFA_LOG_ATTR_FFDC	4 + +#define BFA_LOG_CREATE_ID(msw, lsw) \ +	(((u32)msw << BFA_LOG_MODID_OFFSET) | lsw) + +struct bfa_log_mod_s; + +/** + * callback function + */ +typedef void (*bfa_log_cb_t)(struct bfa_log_mod_s *log_mod, u32 msg_id, +			const char *format, ...); + + +struct bfa_log_mod_s { +	char		instance_info[16];	/*  instance info */ +	int		log_level[BFA_LOG_MODULE_ID_MAX + 1]; +						/*  log level for modules */ +	bfa_log_cb_t	cbfn; 			/*  callback function */ +}; + +extern int bfa_log_init(struct bfa_log_mod_s *log_mod, +			char *instance_name, bfa_log_cb_t cbfn); +extern int bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...); +extern bfa_status_t bfa_log_set_level(struct bfa_log_mod_s *log_mod, +			int mod_id, enum bfa_log_severity log_level); +extern bfa_status_t bfa_log_set_level_all(struct bfa_log_mod_s *log_mod, +			enum bfa_log_severity log_level); +extern bfa_status_t bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod, +			enum bfa_log_severity log_level); +extern enum bfa_log_severity bfa_log_get_level(struct bfa_log_mod_s *log_mod, +			int mod_id); +extern enum bfa_log_severity bfa_log_get_msg_level( +			struct bfa_log_mod_s *log_mod, u32 msg_id); +/* + * array of messages generated from xml files + */ +extern struct bfa_log_msgdef_s bfa_log_msg_array[]; + +#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_perf.h b/drivers/scsi/bfa/include/cs/bfa_perf.h new file mode 100644 index 00000000000..45aa5f978ff --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_perf.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFAD_PERF_H__ +#define __BFAD_PERF_H__ + +#ifdef BFAD_PERF_BUILD + +#undef bfa_trc +#undef bfa_trc32 +#undef bfa_assert +#undef BFA_TRC_FILE + +#define bfa_trc(_trcp, _data) +#define bfa_trc32(_trcp, _data) +#define bfa_assert(__cond) +#define BFA_TRC_FILE(__mod, __submod) + +#endif + +#endif /* __BFAD_PERF_H__ */ diff --git a/drivers/scsi/bfa/include/cs/bfa_plog.h b/drivers/scsi/bfa/include/cs/bfa_plog.h new file mode 100644 index 00000000000..670f86e5fc6 --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_plog.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_PORTLOG_H__ +#define __BFA_PORTLOG_H__ + +#include "protocol/fc.h" +#include <defs/bfa_defs_types.h> + +#define BFA_PL_NLOG_ENTS 256 +#define BFA_PL_LOG_REC_INCR(_x) ((_x)++, (_x) %= BFA_PL_NLOG_ENTS) + +#define BFA_PL_STRING_LOG_SZ   32   /* number of chars in string log */ +#define BFA_PL_INT_LOG_SZ      8    /* number of integers in the integer log */ + +enum bfa_plog_log_type { +	BFA_PL_LOG_TYPE_INVALID = 0, +	BFA_PL_LOG_TYPE_INT 	= 1, +	BFA_PL_LOG_TYPE_STRING 	= 2, +}; + +/* + * the (fixed size) record format for each entry in the portlog + */ +struct bfa_plog_rec_s { +	u32        tv;	/* Filled by the portlog driver when the * +				 * entry is added to the circular log.   */ +	u8         port;	/* Source port that logged this entry. CM +				 * entities will use 0xFF */ +	u8         mid;	/* Integer value to be used by all entities * +				 * while logging. The module id to string   * +				 * conversion will be done by BFAL. See +				 * enum bfa_plog_mid */ +	u8         eid;	/* indicates Rx, Tx, IOCTL, etc. See +				 * enum bfa_plog_eid */ +	u8         log_type; /* indicates string log or integer log. +				   * see bfa_plog_log_type_t */ +	u8         log_num_ints; +	/* +	 * interpreted only if log_type is INT_LOG. indicates number of +	 * integers in the int_log[] (0-PL_INT_LOG_SZ). +	 */ +	u8         rsvd; +	u16        misc;	/* can be used to indicate fc frame length, +				 *etc.. */ +	union { +		char            string_log[BFA_PL_STRING_LOG_SZ]; +		u32        int_log[BFA_PL_INT_LOG_SZ]; +	} log_entry; + +}; + +/* + * the following #defines will be used by the logging entities to indicate + * their module id. BFAL will convert the integer value to string format + * +* process to be used while changing the following #defines: + *  - Always add new entries at the end + *  - define corresponding string in BFAL + *  - Do not remove any entry or rearrange the order. + */ +enum bfa_plog_mid { +	BFA_PL_MID_INVALID 	= 0, +	BFA_PL_MID_DEBUG 	= 1, +	BFA_PL_MID_DRVR 	= 2, +	BFA_PL_MID_HAL 		= 3, +	BFA_PL_MID_HAL_FCXP 	= 4, +	BFA_PL_MID_HAL_UF 	= 5, +	BFA_PL_MID_FCS 		= 6, +	BFA_PL_MID_MAX 		= 7 +}; + +#define BFA_PL_MID_STRLEN    8 +struct bfa_plog_mid_strings_s { +	char            m_str[BFA_PL_MID_STRLEN]; +}; + +/* + * the following #defines will be used by the logging entities to indicate + * their event type. BFAL will convert the integer value to string format + * +* process to be used while changing the following #defines: + *  - Always add new entries at the end + *  - define corresponding string in BFAL + *  - Do not remove any entry or rearrange the order. + */ +enum bfa_plog_eid { +	BFA_PL_EID_INVALID 		= 0, +	BFA_PL_EID_IOC_DISABLE 		= 1, +	BFA_PL_EID_IOC_ENABLE 		= 2, +	BFA_PL_EID_PORT_DISABLE 	= 3, +	BFA_PL_EID_PORT_ENABLE 		= 4, +	BFA_PL_EID_PORT_ST_CHANGE 	= 5, +	BFA_PL_EID_TX 			= 6, +	BFA_PL_EID_TX_ACK1 		= 7, +	BFA_PL_EID_TX_RJT 		= 8, +	BFA_PL_EID_TX_BSY 		= 9, +	BFA_PL_EID_RX 			= 10, +	BFA_PL_EID_RX_ACK1 		= 11, +	BFA_PL_EID_RX_RJT 		= 12, +	BFA_PL_EID_RX_BSY 		= 13, +	BFA_PL_EID_CT_IN 		= 14, +	BFA_PL_EID_CT_OUT 		= 15, +	BFA_PL_EID_DRIVER_START 	= 16, +	BFA_PL_EID_RSCN 		= 17, +	BFA_PL_EID_DEBUG 		= 18, +	BFA_PL_EID_MISC 		= 19, +	BFA_PL_EID_MAX 			= 20 +}; + +#define BFA_PL_ENAME_STRLEN    	8 +struct bfa_plog_eid_strings_s { +	char            e_str[BFA_PL_ENAME_STRLEN]; +}; + +#define BFA_PL_SIG_LEN	8 +#define BFA_PL_SIG_STR  "12pl123" + +/* + * per port circular log buffer + */ +struct bfa_plog_s { +	char            plog_sig[BFA_PL_SIG_LEN];	/* Start signature */ +	u8         plog_enabled; +	u8         rsvd[7]; +	u32        ticks; +	u16        head; +	u16        tail; +	struct bfa_plog_rec_s  plog_recs[BFA_PL_NLOG_ENTS]; +}; + +void bfa_plog_init(struct bfa_plog_s *plog); +void bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +			enum bfa_plog_eid event, u16 misc, char *log_str); +void bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +			enum bfa_plog_eid event, u16 misc, +			u32 *intarr, u32 num_ints); +void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +			enum bfa_plog_eid event, u16 misc, +			struct fchs_s *fchdr); +void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +			enum bfa_plog_eid event, u16 misc, +			struct fchs_s *fchdr, u32 pld_w0); +void bfa_plog_clear(struct bfa_plog_s *plog); +void bfa_plog_enable(struct bfa_plog_s *plog); +void bfa_plog_disable(struct bfa_plog_s *plog); +bfa_boolean_t	bfa_plog_get_setting(struct bfa_plog_s *plog); + +#endif /* __BFA_PORTLOG_H__ */ diff --git a/drivers/scsi/bfa/include/cs/bfa_q.h b/drivers/scsi/bfa/include/cs/bfa_q.h new file mode 100644 index 00000000000..ea895facedb --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_q.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_q.h Circular queue definitions. + */ + +#ifndef __BFA_Q_H__ +#define __BFA_Q_H__ + +#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next)) +#define bfa_q_next(_qe)	(((struct list_head *) (_qe))->next) +#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev) + +/* + * bfa_q_qe_init - to initialize a queue element + */ +#define bfa_q_qe_init(_qe) {						\ +	bfa_q_next(_qe) = (struct list_head *) NULL;			\ +	bfa_q_prev(_qe) = (struct list_head *) NULL;			\ +} + +/* + * bfa_q_deq - dequeue an element from head of the queue + */ +#define bfa_q_deq(_q, _qe) {						\ +	if (!list_empty(_q)) {					\ +		(*((struct list_head **) (_qe))) = bfa_q_next(_q);	\ +		bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) =	\ +						(struct list_head *) (_q); \ +		bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \ +		BFA_Q_DBG_INIT(*((struct list_head **) _qe));		\ +	} else {							\ +		*((struct list_head **) (_qe)) = (struct list_head *) NULL; \ +	}								\ +} + +/* + * bfa_q_deq_tail - dequeue an element from tail of the queue + */ +#define bfa_q_deq_tail(_q, _qe) {					    \ +	if (!list_empty(_q)) {					            \ +		*((struct list_head **) (_qe)) = bfa_q_prev(_q);	    \ +		bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = 	    \ +						(struct list_head *) (_q);  \ +		bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);    \ +		BFA_Q_DBG_INIT(*((struct list_head **) _qe));		    \ +	} else {							    \ +		*((struct list_head **) (_qe)) = (struct list_head *) NULL; \ +	}								    \ +} + +/* + * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not + * consistent across modules) + */ +#ifndef BFA_PERF_BUILD +#define BFA_Q_DBG_INIT(_qe)	bfa_q_qe_init(_qe) +#else +#define BFA_Q_DBG_INIT(_qe) +#endif + +#define bfa_q_is_on_q(_q, _qe)		\ +	bfa_q_is_on_q_func(_q, (struct list_head *)(_qe)) +extern int bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe); + +#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h new file mode 100644 index 00000000000..9877066680a --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_sm.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfasm.h State machine defines + */ + +#ifndef __BFA_SM_H__ +#define __BFA_SM_H__ + +typedef void (*bfa_sm_t)(void *sm, int event); + +#define bfa_sm_set_state(_sm, _state)	(_sm)->sm = (bfa_sm_t)(_state) +#define bfa_sm_send_event(_sm, _event)	(_sm)->sm((_sm), (_event)) +#define bfa_sm_get_state(_sm)		((_sm)->sm) +#define bfa_sm_cmp_state(_sm, _state)	((_sm)->sm == (bfa_sm_t)(_state)) + +/** + * For converting from state machine function to state encoding. + */ +struct bfa_sm_table_s { +	bfa_sm_t	sm;	/*  state machine function	*/ +	int		state;	/*  state machine encoding	*/ +	char		*name;	/*  state name for display	*/ +}; +#define BFA_SM(_sm)	((bfa_sm_t)(_sm)) + +int bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm); + +/** + * State machine with entry actions. + */ +typedef void (*bfa_fsm_t)(void *fsm, int event); + +/** + * oc - object class eg. bfa_ioc + * st - state, eg. reset + * otype - object type, eg. struct bfa_ioc_s + * etype - object type, eg. enum ioc_event + */ +#define bfa_fsm_state_decl(oc, st, otype, etype)		\ +	static void oc ## _sm_ ## st(otype * fsm, etype event);      \ +	static void oc ## _sm_ ## st ## _entry(otype * fsm) + +#define bfa_fsm_set_state(_fsm, _state) do {	\ +	(_fsm)->fsm = (bfa_fsm_t)(_state);      \ +	_state ## _entry(_fsm);      \ +} while (0) + +#define bfa_fsm_send_event(_fsm, _event)	\ +	(_fsm)->fsm((_fsm), (_event)) +#define bfa_fsm_cmp_state(_fsm, _state)		\ +	((_fsm)->fsm == (bfa_fsm_t)(_state)) + +#endif diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h new file mode 100644 index 00000000000..3e743928c74 --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_trc.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_TRC_H__ +#define __BFA_TRC_H__ + +#include <bfa_os_inc.h> + +#ifndef BFA_TRC_MAX +#define BFA_TRC_MAX	(4 * 1024) +#endif + +#ifndef BFA_TRC_TS +#define BFA_TRC_TS(_trcm)	((_trcm)->ticks ++) +#endif + +struct bfa_trc_s { +#ifdef __BIGENDIAN +	u16	fileno; +	u16	line; +#else +	u16	line; +	u16	fileno; +#endif +	u32	timestamp; +	union { +		struct { +			u32	rsvd; +			u32	u32; +		} u32; +		u64	u64; +	} data; +}; + + +struct bfa_trc_mod_s { +	u32	head; +	u32	tail; +	u32	ntrc; +	u32	stopped; +	u32	ticks; +	u32	rsvd[3]; +	struct bfa_trc_s trc[BFA_TRC_MAX]; +}; + + +enum { +	BFA_TRC_FW   = 1,	/*  firmware modules */ +	BFA_TRC_HAL  = 2,	/*  BFA modules */ +	BFA_TRC_FCS  = 3,	/*  BFA FCS modules */ +	BFA_TRC_LDRV = 4,	/*  Linux driver modules */ +	BFA_TRC_SDRV = 5,	/*  Solaris driver modules */ +	BFA_TRC_VDRV = 6,	/*  vmware driver modules */ +	BFA_TRC_WDRV = 7,	/*  windows driver modules */ +	BFA_TRC_AEN  = 8,	/*  AEN module */ +	BFA_TRC_BIOS = 9,	/*  bios driver modules */ +	BFA_TRC_EFI  = 10,	/*  EFI driver modules */ +	BNA_TRC_WDRV = 11,	/*  BNA windows driver modules */ +	BNA_TRC_VDRV = 12,	/*  BNA vmware driver modules */ +	BNA_TRC_SDRV = 13,	/*  BNA Solaris driver modules */ +	BNA_TRC_LDRV = 14,	/*  BNA Linux driver modules */ +	BNA_TRC_HAL  = 15,	/*  BNA modules */ +	BFA_TRC_CNA  = 16,	/*  Common modules */ +	BNA_TRC_IMDRV = 17	/*  BNA windows intermediate driver modules */ +}; +#define BFA_TRC_MOD_SH	10 +#define BFA_TRC_MOD(__mod)	((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH) + +/** + * Define a new tracing file (module). Module should match one defined above. + */ +#define BFA_TRC_FILE(__mod, __submod)					\ +	static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \ +						 BFA_TRC_MOD(__mod)) + + +#define bfa_trc32(_trcp, _data)	\ +	__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) + + +#ifndef BFA_BOOT_BUILD +#define bfa_trc(_trcp, _data)	\ +	__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data) +#else +void bfa_boot_trc(struct bfa_trc_mod_s *trcmod, u16 fileno, +			u16 line, u32 data); +#define bfa_trc(_trcp, _data)	\ +	bfa_boot_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) +#endif + + +static inline void +bfa_trc_init(struct bfa_trc_mod_s *trcm) +{ +	trcm->head = trcm->tail = trcm->stopped = 0; +	trcm->ntrc = BFA_TRC_MAX; +} + + +static inline void +bfa_trc_stop(struct bfa_trc_mod_s *trcm) +{ +	trcm->stopped = 1; +} + +#ifdef FWTRC +extern void dc_flush(void *data); +#else +#define dc_flush(data) +#endif + + +static inline void +__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data) +{ +	int		tail = trcm->tail; +	struct bfa_trc_s 	*trc = &trcm->trc[tail]; + +	if (trcm->stopped) +		return; + +	trc->fileno = (u16) fileno; +	trc->line = (u16) line; +	trc->data.u64 = data; +	trc->timestamp = BFA_TRC_TS(trcm); +	dc_flush(trc); + +	trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); +	if (trcm->tail == trcm->head) +		trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); +	dc_flush(trcm); +} + + +static inline void +__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data) +{ +	int		tail = trcm->tail; +	struct bfa_trc_s *trc = &trcm->trc[tail]; + +	if (trcm->stopped) +		return; + +	trc->fileno = (u16) fileno; +	trc->line = (u16) line; +	trc->data.u32.u32 = data; +	trc->timestamp = BFA_TRC_TS(trcm); +	dc_flush(trc); + +	trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); +	if (trcm->tail == trcm->head) +		trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); +	dc_flush(trcm); +} + +#ifndef BFA_PERF_BUILD +#define bfa_trc_fp(_trcp, _data)	bfa_trc(_trcp, _data) +#else +#define bfa_trc_fp(_trcp, _data) +#endif + +#endif /* __BFA_TRC_H__ */ + diff --git a/drivers/scsi/bfa/include/cs/bfa_wc.h b/drivers/scsi/bfa/include/cs/bfa_wc.h new file mode 100644 index 00000000000..0460bd4fc7c --- /dev/null +++ b/drivers/scsi/bfa/include/cs/bfa_wc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_wc.h Generic wait counter. + */ + +#ifndef __BFA_WC_H__ +#define __BFA_WC_H__ + +typedef void (*bfa_wc_resume_t) (void *cbarg); + +struct bfa_wc_s { +	bfa_wc_resume_t wc_resume; +	void		*wc_cbarg; +	int		wc_count; +}; + +static inline void +bfa_wc_up(struct bfa_wc_s *wc) +{ +	wc->wc_count++; +} + +static inline void +bfa_wc_down(struct bfa_wc_s *wc) +{ +	wc->wc_count--; +	if (wc->wc_count == 0) +		wc->wc_resume(wc->wc_cbarg); +} + +/** + * Initialize a waiting counter. + */ +static inline void +bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg) +{ +	wc->wc_resume = wc_resume; +	wc->wc_cbarg = wc_cbarg; +	wc->wc_count = 0; +	bfa_wc_up(wc); +} + +/** + * Wait for counter to reach zero + */ +static inline void +bfa_wc_wait(struct bfa_wc_s *wc) +{ +	bfa_wc_down(wc); +} + +#endif diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h new file mode 100644 index 00000000000..8c208fc8e32 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_ADAPTER_H__ +#define __BFA_DEFS_ADAPTER_H__ + +#include <protocol/types.h> +#include <defs/bfa_defs_version.h> +#include <defs/bfa_defs_mfg.h> + +/** + * BFA adapter level attributes. + */ +enum { +	BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE), +					/* +					 *!< adapter serial num length +					 */ +	BFA_ADAPTER_MODEL_NAME_LEN  = 16,  /*  model name length */ +	BFA_ADAPTER_MODEL_DESCR_LEN = 128, /*  model description length */ +	BFA_ADAPTER_MFG_NAME_LEN    = 8,   /*  manufacturer name length */ +	BFA_ADAPTER_SYM_NAME_LEN    = 64,  /*  adapter symbolic name length */ +	BFA_ADAPTER_OS_TYPE_LEN	    = 64,  /*  adapter os type length */ +}; + +struct bfa_adapter_attr_s { +	char            manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; +	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; +	u32	rsvd1; +	char            model[BFA_ADAPTER_MODEL_NAME_LEN]; +	char            model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; +	wwn_t           pwwn; +	char            node_symname[FC_SYMNAME_MAX]; +	char            hw_ver[BFA_VERSION_LEN]; +	char            fw_ver[BFA_VERSION_LEN]; +	char            optrom_ver[BFA_VERSION_LEN]; +	char            os_type[BFA_ADAPTER_OS_TYPE_LEN]; +	struct bfa_mfg_vpd_s	vpd; +	struct mac_s	mac; + +	u8		nports; +	u8		max_speed; +	u8		prototype; +	char	        asic_rev; + +	u8         pcie_gen; +	u8         pcie_lanes_orig; +	u8         pcie_lanes; +	u8	        cna_capable; +}; + +/** + * BFA adapter level events + * Arguments below are in BFAL context from Mgmt + * BFA_PORT_AEN_ADD:        [in]: None     [out]: serial_num, pwwn, nports + * BFA_PORT_AEN_REMOVE:     [in]: pwwn     [out]: serial_num, pwwn, nports + */ +enum bfa_adapter_aen_event { +	BFA_ADAPTER_AEN_ADD 	= 1,	/*  New Adapter found event */ +	BFA_ADAPTER_AEN_REMOVE 	= 2,	/*  Adapter removed event */ +}; + +struct bfa_adapter_aen_data_s { +	char            serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; +	u32        nports;	/*  Number of NPorts */ +	wwn_t           pwwn;	/*  WWN of one of its physical port */ +}; + +#endif /* __BFA_DEFS_ADAPTER_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_aen.h b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h new file mode 100644 index 00000000000..4c81a613db3 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_AEN_H__ +#define __BFA_DEFS_AEN_H__ + +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_ioc.h> +#include <defs/bfa_defs_adapter.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_lport.h> +#include <defs/bfa_defs_rport.h> +#include <defs/bfa_defs_itnim.h> +#include <defs/bfa_defs_tin.h> +#include <defs/bfa_defs_ipfc.h> +#include <defs/bfa_defs_audit.h> +#include <defs/bfa_defs_ethport.h> + +enum bfa_aen_category { +	BFA_AEN_CAT_ADAPTER 	= 1, +	BFA_AEN_CAT_PORT 	= 2, +	BFA_AEN_CAT_LPORT 	= 3, +	BFA_AEN_CAT_RPORT 	= 4, +	BFA_AEN_CAT_ITNIM 	= 5, +	BFA_AEN_CAT_TIN 	= 6, +	BFA_AEN_CAT_IPFC 	= 7, +	BFA_AEN_CAT_AUDIT 	= 8, +	BFA_AEN_CAT_IOC 	= 9, +	BFA_AEN_CAT_ETHPORT	= 10, +	BFA_AEN_MAX_CAT 	= 10 +}; + +#pragma pack(1) +union bfa_aen_data_u { +	struct bfa_adapter_aen_data_s 	adapter; +	struct bfa_port_aen_data_s 	port; +	struct bfa_lport_aen_data_s 	lport; +	struct bfa_rport_aen_data_s 	rport; +	struct bfa_itnim_aen_data_s 	itnim; +	struct bfa_audit_aen_data_s 	audit; +	struct bfa_ioc_aen_data_s 	ioc; +	struct bfa_ethport_aen_data_s 	ethport; +}; + +struct bfa_aen_entry_s { +	enum bfa_aen_category 	aen_category; +	int			aen_type; +	union bfa_aen_data_u  	aen_data; +	struct bfa_timeval_s   	aen_tv; +	s32         	seq_num; +	s32         	bfad_num; +	s32         	rsvd[1]; +}; + +#pragma pack() + +#define bfa_aen_event_t int + +#endif /* __BFA_DEFS_AEN_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_audit.h b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h new file mode 100644 index 00000000000..8e3a962bf20 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_AUDIT_H__ +#define __BFA_DEFS_AUDIT_H__ + +#include <bfa_os_inc.h> + +/** + * BFA audit events + */ +enum bfa_audit_aen_event { +	BFA_AUDIT_AEN_AUTH_ENABLE 	= 1, +	BFA_AUDIT_AEN_AUTH_DISABLE 	= 2, +}; + +/** + * audit event data + */ +struct bfa_audit_aen_data_s { +	wwn_t           pwwn; +}; + +#endif /* __BFA_DEFS_AUDIT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h new file mode 100644 index 00000000000..dd19c83aba5 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_AUTH_H__ +#define __BFA_DEFS_AUTH_H__ + +#include <defs/bfa_defs_types.h> + +#define PUBLIC_KEY			15409 +#define PRIVATE_KEY			19009 +#define KEY_LEN				32399 +#define BFA_AUTH_SECRET_STRING_LEN	256 +#define BFA_AUTH_FAIL_TIMEOUT		0xFF + +/** + * Authentication status + */ +enum bfa_auth_status { +	BFA_AUTH_STATUS_NONE 	= 0,	/*  no authentication */ +	BFA_AUTH_UNINIT 	= 1,	/*  state - uninit */ +	BFA_AUTH_NEG_SEND 	= 2,	/*  state - negotiate send */ +	BFA_AUTH_CHAL_WAIT 	= 3,	/*  state - challenge wait */ +	BFA_AUTH_NEG_RETRY 	= 4,	/*  state - negotiate retry */ +	BFA_AUTH_REPLY_SEND 	= 5,	/*  state - reply send */ +	BFA_AUTH_STATUS_WAIT 	= 6,	/*  state - status wait */ +	BFA_AUTH_SUCCESS 	= 7,	/*  state - success */ +	BFA_AUTH_FAILED 	= 8,	/*  state - failed */ +	BFA_AUTH_STATUS_UNKNOWN = 9,	/*  authentication status unknown */ +}; + +struct auth_proto_stats_s { +	u32        auth_rjts; +	u32        auth_negs; +	u32        auth_dones; + +	u32        dhchap_challenges; +	u32        dhchap_replies; +	u32        dhchap_successes; +}; + +/** + * Authentication related statistics + */ +struct bfa_auth_stats_s { +	u32           auth_failures;	/*  authentication failures */ +	u32           auth_successes;	/*  authentication successes*/ +	struct auth_proto_stats_s auth_rx_stats; /*  Rx protocol stats */ +	struct auth_proto_stats_s auth_tx_stats; /*  Tx protocol stats */ +}; + +/** + * Authentication hash function algorithms + */ +enum bfa_auth_algo { +	BFA_AUTH_ALGO_MD5 	= 1,	/*  Message-Digest algorithm 5 */ +	BFA_AUTH_ALGO_SHA1 	= 2,	/*  Secure Hash Algorithm 1 */ +	BFA_AUTH_ALGO_MS 	= 3,	/*  MD5, then SHA-1 */ +	BFA_AUTH_ALGO_SM 	= 4,	/*  SHA-1, then MD5 */ +}; + +/** + * DH Groups + * + * Current value could be combination of one or more of the following values + */ +enum bfa_auth_group { +	BFA_AUTH_GROUP_DHNULL 	= 0,	/*  DH NULL (value == 0) */ +	BFA_AUTH_GROUP_DH768 	= 1,	/*  DH group 768 (value == 1) */ +	BFA_AUTH_GROUP_DH1024 	= 2,	/*  DH group 1024 (value == 2) */ +	BFA_AUTH_GROUP_DH1280 	= 4,	/*  DH group 1280 (value == 3) */ +	BFA_AUTH_GROUP_DH1536 	= 8,	/*  DH group 1536 (value == 4) */ + +	BFA_AUTH_GROUP_ALL 	= 256	/*  Use default DH group order +					 *    0, 1, 2, 3, 4 */ +}; + +/** + * Authentication secret sources + */ +enum bfa_auth_secretsource { +	BFA_AUTH_SECSRC_LOCAL 	= 1,	/*  locally configured */ +	BFA_AUTH_SECSRC_RADIUS 	= 2,	/*  use radius server */ +	BFA_AUTH_SECSRC_TACACS 	= 3,	/*  TACACS server */ +}; + +/** + * Authentication attributes + */ +struct bfa_auth_attr_s { +	enum bfa_auth_status 	status; +	enum bfa_auth_algo 	algo; +	enum bfa_auth_group 	dh_grp; +	u16		rjt_code; +	u16		rjt_code_exp; +	u8			secret_set; +	u8			resv[7]; +}; + +#endif /* __BFA_DEFS_AUTH_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h new file mode 100644 index 00000000000..6f4aa528354 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_BOOT_H__ +#define __BFA_DEFS_BOOT_H__ + +#include <protocol/types.h> +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_pport.h> + +enum { +	BFA_BOOT_BOOTLUN_MAX = 4,	/*  maximum boot lun per IOC */ +}; + +#define BOOT_CFG_REV1	1 + +/** + *      Boot options setting. Boot options setting determines from where + *      to get the boot lun information + */ +enum bfa_boot_bootopt { +    BFA_BOOT_AUTO_DISCOVER = 0,    /*  Boot from blun provided by fabric */ +    BFA_BOOT_STORED_BLUN   = 1,    /*  Boot from bluns stored in flash   */ +    BFA_BOOT_FIRST_LUN     = 2,    /*  Boot from first discovered blun   */ +}; + +/** + * Boot lun information. + */ +struct bfa_boot_bootlun_s { +	wwn_t           pwwn;	/*  port wwn of target */ +	lun_t           lun;	/*  64-bit lun */ +}; + +/** + * BOOT boot configuraton + */ +struct bfa_boot_cfg_s { +	u8         version; +	u8         rsvd1; +	u16        chksum; + +	u8         enable;		/*  enable/disable SAN boot */ +	u8         speed;		/*  boot speed settings */ +	u8         topology;	/*  boot topology setting */ +	u8         bootopt;	/*  bfa_boot_bootopt_t */ + +	u32        nbluns;		/*  number of boot luns */ + +	u32        rsvd2; + +	struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX]; +	struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX]; +}; + + +#endif /* __BFA_DEFS_BOOT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_cee.h b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h new file mode 100644 index 00000000000..520a22f52dd --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + *  bfa_defs_cee.h Interface declarations between host based + *	BFAL and DCBX/LLDP module in Firmware + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_CEE_H__ +#define __BFA_DEFS_CEE_H__ + +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_pport.h> +#include <protocol/types.h> + +#pragma pack(1) + +#define BFA_CEE_LLDP_MAX_STRING_LEN (128) + + +/* FIXME: this is coming from the protocol spec. Can the host & apps share the +   protocol .h files ? + */ +#define BFA_CEE_LLDP_SYS_CAP_OTHER       0x0001 +#define BFA_CEE_LLDP_SYS_CAP_REPEATER    0x0002 +#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE  0x0004 +#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP     0x0008 +#define BFA_CEE_LLDP_SYS_CAP_ROUTER      0x0010 +#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 	 0x0020 +#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD   0x0040 +#define BFA_CEE_LLDP_SYS_CAP_STATION     0x0080 +#define BFA_CEE_LLDP_SYS_CAP_CVLAN	     0x0100 +#define BFA_CEE_LLDP_SYS_CAP_SVLAN 	     0x0200 +#define BFA_CEE_LLDP_SYS_CAP_TPMR		 0x0400 + + +/* LLDP string type */ +struct bfa_cee_lldp_str_s { +	u8 sub_type; +	u8 len; +	u8 rsvd[2]; +	u8 value[BFA_CEE_LLDP_MAX_STRING_LEN]; +}; + + +/* LLDP paramters */ +struct bfa_cee_lldp_cfg_s { +	struct bfa_cee_lldp_str_s chassis_id; +	struct bfa_cee_lldp_str_s port_id; +	struct bfa_cee_lldp_str_s port_desc; +	struct bfa_cee_lldp_str_s sys_name; +	struct bfa_cee_lldp_str_s sys_desc; +	struct bfa_cee_lldp_str_s mgmt_addr; +	u16    time_to_interval; +	u16    enabled_system_cap; +}; + +enum bfa_cee_dcbx_version_e { +	DCBX_PROTOCOL_PRECEE = 1, +	DCBX_PROTOCOL_CEE    = 2, +}; + +enum bfa_cee_lls_e { +	CEE_LLS_DOWN_NO_TLV = 0, /* LLS is down because the TLV not sent by +				  * the peer */ +	CEE_LLS_DOWN        = 1, /* LLS is down as advertised by the peer */ +	CEE_LLS_UP          = 2, +}; + +/* CEE/DCBX parameters */ +struct bfa_cee_dcbx_cfg_s { +	u8 pgid[8]; +	u8 pg_percentage[8]; +	u8 pfc_enabled;          /* bitmap of priorties with PFC enabled */ +	u8 fcoe_user_priority;   /* bitmap of priorities used for FcoE +				       * traffic */ +	u8 dcbx_version;	/* operating version:CEE or preCEE */ +	u8 lls_fcoe;	/* FCoE Logical Link Status */ +	u8 lls_lan;	/* LAN Logical Link Status */ +	u8 rsvd[3]; +}; + +/* CEE status */ +/* Making this to tri-state for the benefit of port list command */ +enum bfa_cee_status_e { +    CEE_PHY_DOWN = 0, +    CEE_PHY_UP = 1, +    CEE_UP = 2, +}; + +/* CEE Query */ +struct bfa_cee_attr_s { +	u8                   cee_status; +	u8                   error_reason; +	struct bfa_cee_lldp_cfg_s lldp_remote; +	struct bfa_cee_dcbx_cfg_s dcbx_remote; +	mac_t src_mac; +	u8 link_speed; +	u8 filler[3]; +}; + + + + +/* LLDP/DCBX/CEE Statistics */ + +struct bfa_cee_lldp_stats_s { +	u32 frames_transmitted; +	u32 frames_aged_out; +	u32 frames_discarded; +	u32 frames_in_error; +	u32 frames_rcvd; +	u32 tlvs_discarded; +	u32 tlvs_unrecognized; +}; + +struct bfa_cee_dcbx_stats_s { +	u32 subtlvs_unrecognized; +	u32 negotiation_failed; +	u32 remote_cfg_changed; +	u32 tlvs_received; +	u32 tlvs_invalid; +	u32 seqno; +	u32 ackno; +	u32 recvd_seqno; +	u32 recvd_ackno; +}; + +struct bfa_cee_cfg_stats_s { +	u32 cee_status_down; +	u32 cee_status_up; +	u32 cee_hw_cfg_changed; +	u32 recvd_invalid_cfg; +}; + + +struct bfa_cee_stats_s { +	struct bfa_cee_lldp_stats_s lldp_stats; +	struct bfa_cee_dcbx_stats_s dcbx_stats; +	struct bfa_cee_cfg_stats_s  cfg_stats; +}; + +#pragma pack() + + +#endif	/* __BFA_DEFS_CEE_H__ */ + + diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h new file mode 100644 index 00000000000..57049805762 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_DRIVER_H__ +#define __BFA_DEFS_DRIVER_H__ + +/** + * Driver statistics + */ +	u16    tm_io_abort; +    u16    tm_io_abort_comp; +    u16    tm_lun_reset; +    u16    tm_lun_reset_comp; +    u16    tm_target_reset; +    u16    tm_bus_reset; +    u16    ioc_restart;        /*  IOC restart count */ +    u16    io_pending;         /*  outstanding io count per-IOC */ +    u64    control_req; +    u64    input_req; +    u64    output_req; +    u64    input_words; +    u64    output_words; +} bfa_driver_stats_t; + + +#endif /* __BFA_DEFS_DRIVER_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h new file mode 100644 index 00000000000..79f9b3e146f --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_ETHPORT_H__ +#define __BFA_DEFS_ETHPORT_H__ + +#include <defs/bfa_defs_status.h> +#include <protocol/types.h> +#include <cna/pstats/phyport_defs.h> +#include <cna/pstats/ethport_defs.h> + +struct bna_tx_info_s { +	u32    miniport_state; +	u32    adapter_state; +	u64    tx_count; +	u64    tx_wi; +	u64    tx_sg; +	u64    tx_tcp_chksum; +	u64    tx_udp_chksum; +	u64    tx_ip_chksum; +	u64    tx_lsov1; +	u64    tx_lsov2; +	u64    tx_max_sg_len ; +}; + +struct bna_rx_queue_info_s { +	u16    q_id ; +	u16    buf_size ; +	u16    buf_count ; +	u16    rsvd ; +	u64    rx_count ; +	u64    rx_dropped ; +	u64    rx_unsupported ; +	u64    rx_internal_err ; +	u64    rss_count ; +	u64    vlan_count ; +	u64    rx_tcp_chksum ; +	u64    rx_udp_chksum ; +	u64    rx_ip_chksum ; +	u64    rx_hds ; +}; + +struct bna_rx_q_set_s { +	u16    q_set_type; +	u32    miniport_state; +	u32    adapter_state; +	struct bna_rx_queue_info_s    rx_queue[2]; +}; + +struct bna_port_stats_s { +	struct bna_tx_info_s   tx_stats; +	u16        qset_count ; +	struct bna_rx_q_set_s  rx_qset[8]; +}; + +struct bfa_ethport_stats_s { +	struct bna_stats_txf	txf_stats[1]; +	struct bna_stats_rxf	rxf_stats[1]; +	struct bnad_drv_stats drv_stats; +}; + +/** + * Ethernet port events + * Arguments below are in BFAL context from Mgmt + * BFA_PORT_AEN_ETH_LINKUP:    [in]: mac [out]: mac + * BFA_PORT_AEN_ETH_LINKDOWN:  [in]: mac [out]: mac + * BFA_PORT_AEN_ETH_ENABLE:  [in]: mac [out]: mac + * BFA_PORT_AEN_ETH_DISABLE:  [in]: mac [out]: mac + * + */ +enum bfa_ethport_aen_event { +	BFA_ETHPORT_AEN_LINKUP = 1, /*  Base Port Ethernet link up event */ +	BFA_ETHPORT_AEN_LINKDOWN = 2, /*  Base Port Ethernet link down event */ +	BFA_ETHPORT_AEN_ENABLE = 3, /*  Base Port Ethernet link enable event */ +	BFA_ETHPORT_AEN_DISABLE = 4, /*  Base Port Ethernet link disable +				      * event */ +}; + +struct bfa_ethport_aen_data_s { +	mac_t mac;	/*  MAC address of the physical port */ +}; + + +#endif /* __BFA_DEFS_ETHPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h new file mode 100644 index 00000000000..c08f4f5026a --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_FCPIM_H__ +#define __BFA_DEFS_FCPIM_H__ + +struct bfa_fcpim_stats_s { +	u32        total_ios;	/*  Total IO count */ +	u32        qresumes;	/*  IO waiting for CQ space */ +	u32        no_iotags;	/*  NO IO contexts */ +	u32        io_aborts;	/*  IO abort requests */ +	u32        no_tskims;	/*  NO task management contexts */ +	u32        iocomp_ok;	/*  IO completions with OK status */ +	u32        iocomp_underrun;	/*  IO underrun (good) */ +	u32        iocomp_overrun;	/*  IO overrun (good) */ +	u32        iocomp_aborted;	/*  Aborted IO requests */ +	u32        iocomp_timedout;	/*  IO timeouts */ +	u32        iocom_nexus_abort;	/*  IO selection timeouts */ +	u32        iocom_proto_err;	/*  IO protocol errors */ +	u32        iocom_dif_err;	/*  IO SBC-3 protection errors */ +	u32        iocom_tm_abort;	/*  IO aborted by TM requests */ +	u32        iocom_sqer_needed;	/*  IO retry for SQ error +						 *recovery */ +	u32        iocom_res_free;	/*  Delayed freeing of IO resources */ +	u32        iocomp_scsierr;	/*  IO with non-good SCSI status */ +	u32        iocom_hostabrts;	/*  Host IO abort requests */ +	u32        iocom_utags;	/*  IO comp with unknown tags */ +	u32        io_cleanups;	/*  IO implicitly aborted */ +	u32        io_tmaborts;	/*  IO aborted due to TM commands */ +	u32        rsvd; +}; +#endif /*__BFA_DEFS_FCPIM_H__*/ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h new file mode 100644 index 00000000000..9ccf53bef65 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_IM_COMMON_H__ +#define __BFA_DEFS_IM_COMMON_H__ + +#define	BFA_ADAPTER_NAME_LEN	256 +#define BFA_ADAPTER_GUID_LEN    256 +#define RESERVED_VLAN_NAME      L"PORT VLAN" +#define PASSTHRU_VLAN_NAME      L"PASSTHRU VLAN" + +	u64	tx_pkt_cnt; +	u64	rx_pkt_cnt; +	u32	duration; +	u8		status; +} bfa_im_stats_t, *pbfa_im_stats_t; + +#endif /* __BFA_DEFS_IM_COMMON_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h new file mode 100644 index 00000000000..a486a7eb81d --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_IM_TEAM_H__ +#define __BFA_DEFS_IM_TEAM_H__ + +#include <protocol/types.h> + +#define	BFA_TEAM_MAX_PORTS	8 +#define	BFA_TEAM_NAME_LEN	256 +#define BFA_MAX_NUM_TEAMS	16 +#define BFA_TEAM_INVALID_DELAY -1 + +	BFA_LACP_RATE_SLOW = 1, +	BFA_LACP_RATE_FAST +} bfa_im_lacp_rate_t; + +	BFA_TEAM_MODE_FAIL_OVER = 1, +	BFA_TEAM_MODE_FAIL_BACK, +	BFA_TEAM_MODE_LACP, +	BFA_TEAM_MODE_NONE +} bfa_im_team_mode_t; + +	BFA_XMIT_POLICY_L2 = 1, +	BFA_XMIT_POLICY_L3_L4 +} bfa_im_xmit_policy_t; + +	bfa_im_team_mode_t     team_mode; +	bfa_im_lacp_rate_t     lacp_rate; +	bfa_im_xmit_policy_t   xmit_policy; +	int   	          delay; +	wchar_t    	  primary[BFA_ADAPTER_NAME_LEN]; +	wchar_t        	  preferred_primary[BFA_ADAPTER_NAME_LEN]; +	mac_t	          mac; +	u16       	  num_ports; +	u16          num_vlans; +	u16 vlan_list[BFA_MAX_VLANS_PER_PORT]; +	wchar_t	 team_guid_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_GUID_LEN]; +	wchar_t	 ioc_name_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_NAME_LEN]; +} bfa_im_team_attr_t; + +	wchar_t		             team_name[BFA_TEAM_NAME_LEN]; +	bfa_im_xmit_policy_t	 xmit_policy; +	int                 	 delay; +	wchar_t                	 primary[BFA_ADAPTER_NAME_LEN]; +	wchar_t               	 preferred_primary[BFA_ADAPTER_NAME_LEN]; +} bfa_im_team_edit_t, *pbfa_im_team_edit_t; + +	wchar_t					team_name[BFA_TEAM_NAME_LEN]; +	bfa_im_team_mode_t      team_mode; +	mac_t	               	mac; +} bfa_im_team_info_t; + +	bfa_im_team_info_t 		team_info[BFA_MAX_NUM_TEAMS]; +	u16 				num_teams; +} bfa_im_team_list_t, *pbfa_im_team_list_t; + +#endif /* __BFA_DEFS_IM_TEAM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h new file mode 100644 index 00000000000..b1d532da3a9 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_IOC_H__ +#define __BFA_DEFS_IOC_H__ + +#include <protocol/types.h> +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_version.h> +#include <defs/bfa_defs_adapter.h> +#include <defs/bfa_defs_pm.h> + +enum { +	BFA_IOC_DRIVER_LEN	= 16, +	BFA_IOC_CHIP_REV_LEN 	= 8, +}; + +/** + * Driver and firmware versions. + */ +struct bfa_ioc_driver_attr_s { +	char            driver[BFA_IOC_DRIVER_LEN];	/*  driver name */ +	char            driver_ver[BFA_VERSION_LEN];	/*  driver version */ +	char            fw_ver[BFA_VERSION_LEN];	/*  firmware version*/ +	char            bios_ver[BFA_VERSION_LEN];	/*  bios version */ +	char            efi_ver[BFA_VERSION_LEN];	/*  EFI version */ +	char            ob_ver[BFA_VERSION_LEN];	/*  openboot version*/ +}; + +/** + * IOC PCI device attributes + */ +struct bfa_ioc_pci_attr_s { +	u16        vendor_id;	/*  PCI vendor ID */ +	u16        device_id;	/*  PCI device ID */ +	u16        ssid;		/*  subsystem ID */ +	u16        ssvid;		/*  subsystem vendor ID */ +	u32        pcifn;		/*  PCI device function */ +	u32        rsvd;		/* padding */ +	u8         chip_rev[BFA_IOC_CHIP_REV_LEN];	 /*  chip revision */ +}; + +/** + * IOC states + */ +enum bfa_ioc_state { +	BFA_IOC_RESET       = 1,  /*  IOC is in reset state */ +	BFA_IOC_SEMWAIT     = 2,  /*  Waiting for IOC hardware semaphore */ +	BFA_IOC_HWINIT 	    = 3,  /*  IOC hardware is being initialized */ +	BFA_IOC_GETATTR     = 4,  /*  IOC is being configured */ +	BFA_IOC_OPERATIONAL = 5,  /*  IOC is operational */ +	BFA_IOC_INITFAIL    = 6,  /*  IOC hardware failure */ +	BFA_IOC_HBFAIL      = 7,  /*  IOC heart-beat failure */ +	BFA_IOC_DISABLING   = 8,  /*  IOC is being disabled */ +	BFA_IOC_DISABLED    = 9,  /*  IOC is disabled */ +	BFA_IOC_FWMISMATCH  = 10, /*  IOC firmware different from drivers */ +}; + +/** + * IOC firmware stats + */ +struct bfa_fw_ioc_stats_s { +	u32        hb_count; +	u32        cfg_reqs; +	u32        enable_reqs; +	u32        disable_reqs; +	u32        stats_reqs; +	u32        clrstats_reqs; +	u32        unknown_reqs; +	u32        ic_reqs;		/*  interrupt coalesce reqs */ +}; + +/** + * IOC driver stats + */ +struct bfa_ioc_drv_stats_s { +	u32	ioc_isrs; +	u32	ioc_enables; +	u32	ioc_disables; +	u32	ioc_hbfails; +	u32	ioc_boots; +	u32	stats_tmos; +	u32        hb_count; +	u32        disable_reqs; +	u32        enable_reqs; +	u32        disable_replies; +	u32        enable_replies; +}; + +/** + * IOC statistics + */ +struct bfa_ioc_stats_s { +	struct bfa_ioc_drv_stats_s	drv_stats; /*  driver IOC stats */ +	struct bfa_fw_ioc_stats_s 	fw_stats;  /*  firmware IOC stats */ +}; + + +enum bfa_ioc_type_e { +	BFA_IOC_TYPE_FC	  = 1, +	BFA_IOC_TYPE_FCoE = 2, +	BFA_IOC_TYPE_LL	  = 3, +}; + +/** + * IOC attributes returned in queries + */ +struct bfa_ioc_attr_s { +	enum bfa_ioc_type_e		ioc_type; +	enum bfa_ioc_state 		state;		/*  IOC state      */ +	struct bfa_adapter_attr_s	adapter_attr;	/*  HBA attributes */ +	struct bfa_ioc_driver_attr_s 	driver_attr;	/*  driver attr    */ +	struct bfa_ioc_pci_attr_s	pci_attr; +	u8				port_id;	/*  port number    */ +}; + +/** + * BFA IOC level events + */ +enum bfa_ioc_aen_event { +	BFA_IOC_AEN_HBGOOD	= 1,	/*  Heart Beat restore event	*/ +	BFA_IOC_AEN_HBFAIL	= 2,	/*  Heart Beat failure event	*/ +	BFA_IOC_AEN_ENABLE	= 3,	/*  IOC enabled event		*/ +	BFA_IOC_AEN_DISABLE	= 4,	/*  IOC disabled event		*/ +	BFA_IOC_AEN_FWMISMATCH	= 5,	/*  IOC firmware mismatch	*/ +}; + +/** + * BFA IOC level event data, now just a place holder + */ +struct bfa_ioc_aen_data_s { +	enum bfa_ioc_type_e ioc_type; +	wwn_t	pwwn; +	mac_t	mac; +}; + +#endif /* __BFA_DEFS_IOC_H__ */ + diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h new file mode 100644 index 00000000000..d76bcbd9820 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_IOCFC_H__ +#define __BFA_DEFS_IOCFC_H__ + +#include <protocol/types.h> +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_version.h> +#include <defs/bfa_defs_adapter.h> +#include <defs/bfa_defs_pm.h> + +#define BFA_IOCFC_INTR_DELAY	1125 +#define BFA_IOCFC_INTR_LATENCY	225 + +/** + * Interrupt coalescing configuration. + */ +struct bfa_iocfc_intr_attr_s { +	bfa_boolean_t	coalesce;	/*  enable/disable coalescing */ +	u16	latency;	/*  latency in microseconds   */ +	u16	delay;		/*  delay in microseconds     */ +}; + +/** + * IOC firmware configuraton + */ +struct bfa_iocfc_fwcfg_s { +	u16        num_fabrics;	/*  number of fabrics		*/ +	u16        num_lports;	/*  number of local lports	*/ +	u16        num_rports;	/*  number of remote ports	*/ +	u16        num_ioim_reqs;	/*  number of IO reqs		*/ +	u16        num_tskim_reqs;	/*  task management requests	*/ +	u16        num_iotm_reqs;	/*  number of TM IO reqs	*/ +	u16        num_tsktm_reqs;	/*  TM task management requests*/ +	u16        num_fcxp_reqs;	/*  unassisted FC exchanges	*/ +	u16        num_uf_bufs;	/*  unsolicited recv buffers	*/ +	u8		num_cqs; +	u8		rsvd; +}; + +struct bfa_iocfc_drvcfg_s { +	u16        num_reqq_elems;	/*  number of req queue elements */ +	u16        num_rspq_elems;	/*  number of rsp queue elements */ +	u16        num_sgpgs;	/*  number of total SG pages	  */ +	u16        num_sboot_tgts;	/*  number of SAN boot targets	  */ +	u16        num_sboot_luns;	/*  number of SAN boot luns	  */ +	u16	    ioc_recover;	/*  IOC recovery mode		  */ +	u16	    min_cfg;	/*  minimum configuration	  */ +	u16        path_tov;	/*  device path timeout	  */ +	bfa_boolean_t   delay_comp; /*  delay completion of +							failed inflight IOs */ +	u32		rsvd; +}; +/** + * IOC configuration + */ +struct bfa_iocfc_cfg_s { +	struct bfa_iocfc_fwcfg_s	fwcfg;	/*  firmware side config */ +	struct bfa_iocfc_drvcfg_s	drvcfg;	/*  driver side config	  */ +}; + +/** + * IOC firmware IO stats + */ +struct bfa_fw_io_stats_s { +	u32	host_abort;		/*  IO aborted by host driver*/ +	u32	host_cleanup;		/*  IO clean up by host driver */ + +	u32	fw_io_timeout;		/*  IOs timedout */ +	u32	fw_frm_parse;		/*  frame parsed by f/w */ +	u32	fw_frm_data;		/*  fcp_data frame parsed by f/w */ +	u32	fw_frm_rsp;		/*  fcp_rsp frame parsed by f/w */ +	u32	fw_frm_xfer_rdy;	/*  xfer_rdy frame parsed by f/w */ +	u32	fw_frm_bls_acc;		/*  BLS ACC  frame parsed by f/w */ +	u32	fw_frm_tgt_abort;	/*  target ABTS parsed by f/w */ +	u32	fw_frm_unknown;		/*  unknown parsed by f/w */ +	u32	fw_data_dma;		/*  f/w DMA'ed the data frame */ +	u32	fw_frm_drop;		/*  f/w drop the frame */ + +	u32	rec_timeout;		/*  FW rec timed out */ +	u32	error_rec;			/*  FW sending rec on +							* an error condition*/ +	u32	wait_for_si;		/*  FW wait for SI */ +	u32	rec_rsp_inval;		/*  REC rsp invalid */ +	u32	seqr_io_abort;		/*  target does not know cmd so abort */ +	u32	seqr_io_retry;		/*  SEQR failed so retry IO */ + +	u32	itn_cisc_upd_rsp;	/*  ITN cisc updated on fcp_rsp */ +	u32	itn_cisc_upd_data;	/*  ITN cisc updated on fcp_data */ +	u32	itn_cisc_upd_xfer_rdy;	/*  ITN cisc updated on fcp_data */ + +	u32	fcp_data_lost;		/*  fcp data lost */ + +	u32	ro_set_in_xfer_rdy;	/*  Target set RO in Xfer_rdy frame */ +	u32	xfer_rdy_ooo_err;	/*  Out of order Xfer_rdy received */ +	u32	xfer_rdy_unknown_err;	/*  unknown error in xfer_rdy frame */ + +	u32	io_abort_timeout;	/*  ABTS timedout  */ +	u32	sler_initiated;		/*  SLER initiated */ + +	u32	unexp_fcp_rsp;		/*  fcp response in wrong state */ + +	u32	fcp_rsp_under_run;	/*  fcp rsp IO underrun */ +	u32        fcp_rsp_under_run_wr;   /*  fcp rsp IO underrun for write */ +	u32	fcp_rsp_under_run_err;	/*  fcp rsp IO underrun error */ +	u32        fcp_rsp_resid_inval;    /*  invalid residue */ +	u32	fcp_rsp_over_run;	/*  fcp rsp IO overrun */ +	u32	fcp_rsp_over_run_err;	/*  fcp rsp IO overrun error */ +	u32	fcp_rsp_proto_err;	/*  protocol error in fcp rsp */ +	u32	fcp_rsp_sense_err;	/*  error in sense info in fcp rsp */ +	u32	fcp_conf_req;		/*  FCP conf requested */ + +	u32	tgt_aborted_io;		/*  target initiated abort */ + +	u32	ioh_edtov_timeout_event;/*  IOH edtov timer popped */ +	u32	ioh_fcp_rsp_excp_event;	/*  IOH FCP_RSP exception */ +	u32	ioh_fcp_conf_event;	/*  IOH FCP_CONF */ +	u32	ioh_mult_frm_rsp_event;	/*  IOH multi_frame FCP_RSP */ +	u32	ioh_hit_class2_event;	/*  IOH hit class2 */ +	u32	ioh_miss_other_event;	/*  IOH miss other */ +	u32	ioh_seq_cnt_err_event;	/*  IOH seq cnt error */ +	u32	ioh_len_err_event;		/*  IOH len error - fcp_dl != +							* bytes xfered */ +	u32	ioh_seq_len_err_event;	/*  IOH seq len error */ +	u32	ioh_data_oor_event;	/*  Data out of range */ +	u32	ioh_ro_ooo_event;	/*  Relative offset out of range */ +	u32	ioh_cpu_owned_event;	/*  IOH hit -iost owned by f/w */ +	u32	ioh_unexp_frame_event;	/*  unexpected frame recieved +						 *   count */ +	u32	ioh_err_int;		/*  IOH error int during data-phase +						 *   for scsi write +						 */ +}; + +/** + * IOC port firmware stats + */ + +struct bfa_fw_port_fpg_stats_s { +    u32    intr_evt; +    u32    intr; +    u32    intr_excess; +    u32    intr_cause0; +    u32    intr_other; +    u32    intr_other_ign; +    u32    sig_lost; +    u32    sig_regained; +    u32    sync_lost; +    u32    sync_to; +    u32    sync_regained; +    u32    div2_overflow; +    u32    div2_underflow; +    u32    efifo_overflow; +    u32    efifo_underflow; +    u32    idle_rx; +    u32    lrr_rx; +    u32    lr_rx; +    u32    ols_rx; +    u32    nos_rx; +    u32    lip_rx; +    u32    arbf0_rx; +    u32    mrk_rx; +    u32    const_mrk_rx; +    u32    prim_unknown; +    u32    rsvd; +}; + + +struct bfa_fw_port_lksm_stats_s { +    u32    hwsm_success;       /*  hwsm state machine success          */ +    u32    hwsm_fails;         /*  hwsm fails                          */ +    u32    hwsm_wdtov;         /*  hwsm timed out                      */ +    u32    swsm_success;       /*  swsm success                        */ +    u32    swsm_fails;         /*  swsm fails                          */ +    u32    swsm_wdtov;         /*  swsm timed out                      */ +    u32    busybufs;           /*  link init failed due to busybuf     */ +    u32    buf_waits;          /*  bufwait state entries               */ +    u32    link_fails;         /*  link failures                       */ +    u32    psp_errors;         /*  primitive sequence protocol errors  */ +    u32    lr_unexp;           /*  No. of times LR rx-ed unexpectedly  */ +    u32    lrr_unexp;          /*  No. of times LRR rx-ed unexpectedly */ +    u32    lr_tx;              /*  No. of times LR tx started          */ +    u32    lrr_tx;             /*  No. of times LRR tx started         */ +    u32    ols_tx;             /*  No. of times OLS tx started         */ +    u32    nos_tx;             /*  No. of times NOS tx started         */ +}; + + +struct bfa_fw_port_snsm_stats_s { +    u32    hwsm_success;       /*  Successful hwsm terminations        */ +    u32    hwsm_fails;         /*  hwsm fail count                     */ +    u32    hwsm_wdtov;         /*  hwsm timed out                      */ +    u32    swsm_success;       /*  swsm success                        */ +    u32    swsm_wdtov;         /*  swsm timed out                      */ +    u32    error_resets;       /*  error resets initiated by upsm      */ +    u32    sync_lost;          /*  Sync loss count                     */ +    u32    sig_lost;           /*  Signal loss count                   */ +}; + + +struct bfa_fw_port_physm_stats_s { +    u32    module_inserts;     /*  Module insert count                 */ +    u32    module_xtracts;     /*  Module extracts count               */ +    u32    module_invalids;    /*  Invalid module inserted count       */ +    u32    module_read_ign;    /*  Module validation status ignored    */ +    u32    laser_faults;       /*  Laser fault count                   */ +    u32    rsvd; +}; + + +struct bfa_fw_fip_stats_s { +    u32    disc_req;           /*  Discovery solicit requests          */ +    u32    disc_rsp;           /*  Discovery solicit response          */ +    u32    disc_err;           /*  Discovery advt. parse errors        */ +    u32    disc_unsol;         /*  Discovery unsolicited               */ +    u32    disc_timeouts;      /*  Discovery timeouts                  */ +    u32    linksvc_unsupp;     /*  Unsupported link service req        */ +    u32    linksvc_err;        /*  Parse error in link service req     */ +    u32    logo_req;           /*  Number of FIP logos received        */ +    u32    clrvlink_req;       /*  Clear virtual link req              */ +    u32    op_unsupp;          /*  Unsupported FIP operation           */ +    u32    untagged;           /*  Untagged frames (ignored)           */ +    u32    rsvd; +}; + + +struct bfa_fw_lps_stats_s { +    u32    mac_invalids;       /*  Invalid mac assigned                */ +    u32    rsvd; +}; + + +struct bfa_fw_fcoe_stats_s { +    u32    cee_linkups;        /*  CEE link up count                   */ +    u32    cee_linkdns;        /*  CEE link down count                 */ +    u32    fip_linkups;        /*  FIP link up count                   */ +    u32    fip_linkdns;        /*  FIP link up count                   */ +    u32    fip_fails;          /*  FIP fail count                      */ +    u32    mac_invalids;       /*  Invalid mac assigned                */ +}; + +/** + * IOC firmware FCoE port stats + */ +struct bfa_fw_fcoe_port_stats_s { +    struct bfa_fw_fcoe_stats_s  fcoe_stats; +    struct bfa_fw_fip_stats_s   fip_stats; +}; + +/** + * IOC firmware FC port stats + */ +struct bfa_fw_fc_port_stats_s { +	struct bfa_fw_port_fpg_stats_s		fpg_stats; +	struct bfa_fw_port_physm_stats_s	physm_stats; +	struct bfa_fw_port_snsm_stats_s		snsm_stats; +	struct bfa_fw_port_lksm_stats_s		lksm_stats; +}; + +/** + * IOC firmware FC port stats + */ +union bfa_fw_port_stats_s { +	struct bfa_fw_fc_port_stats_s	fc_stats; +	struct bfa_fw_fcoe_port_stats_s	fcoe_stats; +}; + +/** + * IOC firmware stats + */ +struct bfa_fw_stats_s { +	struct bfa_fw_ioc_stats_s	ioc_stats; +	struct bfa_fw_io_stats_s	io_stats; +	union  bfa_fw_port_stats_s	port_stats; +}; + +/** + * IOC statistics + */ +struct bfa_iocfc_stats_s { +	struct bfa_fw_stats_s 	fw_stats;	/*  firmware IOC stats      */ +}; + +/** + * IOC attributes returned in queries + */ +struct bfa_iocfc_attr_s { +	struct bfa_iocfc_cfg_s		config;		/*  IOCFC config   */ +	struct bfa_iocfc_intr_attr_s	intr_attr;	/*  interrupt attr */ +}; + +#define BFA_IOCFC_PATHTOV_MAX	60 +#define BFA_IOCFC_QDEPTH_MAX	2000 + +#endif /* __BFA_DEFS_IOC_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h new file mode 100644 index 00000000000..7cb63ea98f3 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_IPFC_H__ +#define __BFA_DEFS_IPFC_H__ + +#include <bfa_os_inc.h> +#include <protocol/types.h> +#include <defs/bfa_defs_types.h> + +/** + * FCS ip remote port states + */ +enum bfa_iprp_state { +	BFA_IPRP_UNINIT  = 0,	/*  PORT is not yet initialized */ +	BFA_IPRP_ONLINE  = 1,	/*  process login is complete */ +	BFA_IPRP_OFFLINE = 2,	/*  iprp is offline */ +}; + +/** + * FCS remote port statistics + */ +struct bfa_iprp_stats_s { +	u32        offlines; +	u32        onlines; +	u32        rscns; +	u32        plogis; +	u32        logos; +	u32        plogi_timeouts; +	u32        plogi_rejects; +}; + +/** + * FCS iprp attribute returned in queries + */ +struct bfa_iprp_attr_s { +	enum bfa_iprp_state state; +}; + +struct bfa_ipfc_stats_s { +	u32 arp_sent; +	u32 arp_recv; +	u32 arp_reply_sent; +	u32 arp_reply_recv; +	u32 farp_sent; +	u32 farp_recv; +	u32 farp_reply_sent; +	u32 farp_reply_recv; +	u32 farp_reject_sent; +	u32 farp_reject_recv; +}; + +struct bfa_ipfc_attr_s { +	bfa_boolean_t enabled; +}; + +#endif /* __BFA_DEFS_IPFC_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h new file mode 100644 index 00000000000..2ec769903d2 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_ITNIM_H__ +#define __BFA_DEFS_ITNIM_H__ + +#include <bfa_os_inc.h> +#include <protocol/types.h> + +/** + * FCS itnim states + */ +enum bfa_itnim_state { +	BFA_ITNIM_OFFLINE 	= 0,	/*  offline */ +	BFA_ITNIM_PRLI_SEND 	= 1,	/*  prli send */ +	BFA_ITNIM_PRLI_SENT 	= 2,	/*  prli sent */ +	BFA_ITNIM_PRLI_RETRY 	= 3,	/*  prli retry */ +	BFA_ITNIM_HCB_ONLINE 	= 4,	/*  online callback */ +	BFA_ITNIM_ONLINE 	= 5,	/*  online */ +	BFA_ITNIM_HCB_OFFLINE 	= 6,	/*  offline callback */ +	BFA_ITNIM_INITIATIOR 	= 7,	/*  initiator */ +}; + +struct bfa_itnim_hal_stats_s { +	u32	onlines;	/*  ITN nexus onlines (PRLI done) */ +	u32	offlines;	/*  ITN Nexus offlines 	*/ +	u32	creates;	/*  ITN create requests 	*/ +	u32	deletes;	/*  ITN delete requests 	*/ +	u32	create_comps;	/*  ITN create completions 	*/ +	u32	delete_comps;	/*  ITN delete completions 	*/ +	u32	sler_events;	/*  SLER (sequence level error +					 * recovery) events */ +	u32	ioc_disabled;	/*  Num IOC disables		*/ +	u32	cleanup_comps;	/*  ITN cleanup completions */ +	u32	tm_cmnds;	/*  task management(TM) cmnds sent */ +	u32	tm_fw_rsps;	/*  TM cmds firmware responses */ +	u32	tm_success;	/*  TM successes */ +	u32	tm_failures;	/*  TM failures */ +	u32	tm_io_comps;	/*  TM IO completions */ +	u32	tm_qresumes;	/*  TM queue resumes (after waiting +					 * for resources) +					 */ +	u32	tm_iocdowns;	/*  TM cmnds affected by IOC down */ +	u32	tm_cleanups;	/*  TM cleanups */ +	u32	tm_cleanup_comps; +					/*  TM cleanup completions */ +	u32	ios;		/*  IO requests */ +	u32	io_comps;	/*  IO completions */ +	u64	input_reqs;	/*  INPUT requests */ +	u64	output_reqs;	/*  OUTPUT requests */ +}; + +/** + * FCS remote port statistics + */ +struct bfa_itnim_stats_s { +	u32        onlines;	/*  num rport online */ +	u32        offlines;	/*  num rport offline */ +	u32        prli_sent;	/*  num prli sent out */ +	u32        fcxp_alloc_wait;/*  num fcxp alloc waits */ +	u32        prli_rsp_err;	/*  num prli rsp errors */ +	u32        prli_rsp_acc;	/*  num prli rsp accepts */ +	u32        initiator;	/*  rport is an initiator */ +	u32        prli_rsp_parse_err;	/*  prli rsp parsing errors */ +	u32        prli_rsp_rjt;	/*  num prli rsp rejects */ +	u32        timeout;	/*  num timeouts detected */ +	u32        sler;		/*  num sler notification from BFA */ +	u32	rsvd; +	struct bfa_itnim_hal_stats_s	hal_stats; +}; + +/** + * FCS itnim attributes returned in queries + */ +struct bfa_itnim_attr_s { +	enum bfa_itnim_state state; /*  FCS itnim state        */ +	u8 retry;		/*  data retransmision support */ +	u8	task_retry_id;  /*  task retry ident support   */ +	u8 rec_support;    /*  REC supported              */ +	u8 conf_comp;      /*  confirmed completion supp  */ +}; + +/** + * BFA ITNIM events. + * Arguments below are in BFAL context from Mgmt + * BFA_ITNIM_AEN_NEW:       [in]: None  [out]: vf_id, lpwwn + * BFA_ITNIM_AEN_DELETE:    [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), + *				  [out]: vf_id, ppwwn, lpwwn, rpwwn + * BFA_ITNIM_AEN_ONLINE:    [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), + *				  [out]: vf_id, ppwwn, lpwwn, rpwwn + * BFA_ITNIM_AEN_OFFLINE:   [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), + *				  [out]: vf_id, ppwwn, lpwwn, rpwwn + * BFA_ITNIM_AEN_DISCONNECT:[in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets), + *				  [out]: vf_id, ppwwn, lpwwn, rpwwn + */ +enum bfa_itnim_aen_event { +	BFA_ITNIM_AEN_ONLINE 	= 1,	/*  Target online */ +	BFA_ITNIM_AEN_OFFLINE 	= 2,	/*  Target offline */ +	BFA_ITNIM_AEN_DISCONNECT = 3,	/*  Target disconnected */ +}; + +/** + * BFA ITNIM event data structure. + */ +struct bfa_itnim_aen_data_s { +	u16        vf_id;	/*  vf_id of the IT nexus */ +	u16        rsvd[3]; +	wwn_t           ppwwn;	/*  WWN of its physical port */ +	wwn_t           lpwwn;	/*  WWN of logical port */ +	wwn_t           rpwwn;	/*  WWN of remote(target) port */ +}; + +#endif /* __BFA_DEFS_ITNIM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_led.h b/drivers/scsi/bfa/include/defs/bfa_defs_led.h new file mode 100644 index 00000000000..62039273264 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_led.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_LED_H__ +#define __BFA_DEFS_LED_H__ + +#define	BFA_LED_MAX_NUM		3 + +enum bfa_led_op { +	BFA_LED_OFF   = 0, +	BFA_LED_ON    = 1, +	BFA_LED_FLICK = 2, +	BFA_LED_BLINK = 3, +}; + +enum bfa_led_color { +	BFA_LED_GREEN = 0, +	BFA_LED_AMBER = 1, +}; + +#endif /* __BFA_DEFS_LED_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_lport.h b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h new file mode 100644 index 00000000000..7359f82aacf --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_LPORT_H__ +#define __BFA_DEFS_LPORT_H__ + +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_port.h> + +/** + * BFA AEN logical port events. + * Arguments below are in BFAL context from Mgmt + * BFA_LPORT_AEN_NEW:       [in]: None         [out]: vf_id, ppwwn, lpwwn, roles + * BFA_LPORT_AEN_DELETE:    [in]: lpwwn        [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_ONLINE:    [in]: lpwwn        [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_OFFLINE:   [in]: lpwwn        [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_DISCONNECT:[in]: lpwwn        [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_NEW_PROP:  [in]: None         [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_DELETE_PROP:     [in]: lpwwn  [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_NEW_STANDARD:    [in]: None   [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_DELETE_STANDARD: [in]: lpwwn  [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_NPIV_DUP_WWN:    [in]: lpwwn  [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_NPIV_FABRIC_MAX: [in]: lpwwn  [out]: vf_id, ppwwn. lpwwn, roles + * BFA_LPORT_AEN_NPIV_UNKNOWN:    [in]: lpwwn  [out]: vf_id, ppwwn. lpwwn, roles + */ +enum bfa_lport_aen_event { +	BFA_LPORT_AEN_NEW	= 1,	/*  LPort created event */ +	BFA_LPORT_AEN_DELETE	= 2,	/*  LPort deleted event */ +	BFA_LPORT_AEN_ONLINE	= 3,	/*  LPort online event */ +	BFA_LPORT_AEN_OFFLINE	= 4,	/*  LPort offline event */ +	BFA_LPORT_AEN_DISCONNECT = 5,	/*  LPort disconnect event */ +	BFA_LPORT_AEN_NEW_PROP	= 6,	/*  VPort created event */ +	BFA_LPORT_AEN_DELETE_PROP = 7,	/*  VPort deleted event */ +	BFA_LPORT_AEN_NEW_STANDARD = 8,	/*  VPort created event */ +	BFA_LPORT_AEN_DELETE_STANDARD = 9,  /*  VPort deleted event */ +	BFA_LPORT_AEN_NPIV_DUP_WWN = 10,    /*  VPort configured with +					     *   duplicate WWN event +						 */ +	BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11, /*  Max NPIV in fabric/fport */ +	BFA_LPORT_AEN_NPIV_UNKNOWN = 12, /*  Unknown NPIV Error code event */ +}; + +/** + * BFA AEN event data structure + */ +struct bfa_lport_aen_data_s { +	u16        vf_id;	/*  vf_id of this logical port */ +	u16        rsvd; +	enum bfa_port_role roles;	/*  Logical port mode,IM/TM/IP etc */ +	wwn_t           ppwwn;	/*  WWN of its physical port */ +	wwn_t           lpwwn;	/*  WWN of this logical port */ +}; + +#endif /* __BFA_DEFS_LPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h new file mode 100644 index 00000000000..13fd4ab6aae --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_MFG_H__ +#define __BFA_DEFS_MFG_H__ + +#include <bfa_os_inc.h> + +/** + * Manufacturing block version + */ +#define BFA_MFG_VERSION				1 + +/** + * Manufacturing block format + */ +#define BFA_MFG_SERIALNUM_SIZE			11 +#define BFA_MFG_PARTNUM_SIZE			14 +#define BFA_MFG_SUPPLIER_ID_SIZE		10 +#define BFA_MFG_SUPPLIER_PARTNUM_SIZE	20 +#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE	20 +#define BFA_MFG_SUPPLIER_REVISION_SIZE	4 +#define STRSZ(_n)	(((_n) + 4) & ~3) + +/** + * VPD data length + */ +#define BFA_MFG_VPD_LEN     256 + +/** + * All numerical fields are in big-endian format. + */ +struct bfa_mfg_vpd_s { +    u8     version;    /*  vpd data version */ +    u8     vpd_sig[3]; /*  characters 'V', 'P', 'D' */ +    u8     chksum;     /*  u8 checksum */ +    u8     vendor;     /*  vendor */ +    u8     len;        /*  vpd data length excluding header */ +    u8     rsv; +    u8     data[BFA_MFG_VPD_LEN];  /*  vpd data */ +}; + +#pragma pack(1) + +#endif /* __BFA_DEFS_MFG_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h new file mode 100644 index 00000000000..c9b83321694 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_PCI_H__ +#define __BFA_DEFS_PCI_H__ + +/** + * PCI device and vendor ID information + */ +enum { +	BFA_PCI_VENDOR_ID_BROCADE	= 0x1657, +	BFA_PCI_DEVICE_ID_FC_8G2P	= 0x13, +	BFA_PCI_DEVICE_ID_FC_8G1P	= 0x17, +	BFA_PCI_DEVICE_ID_CT		= 0x14, +}; + +/** + * PCI sub-system device and vendor ID information + */ +enum { +	BFA_PCI_FCOE_SSDEVICE_ID	= 0x14, +}; + +#define BFA_PCI_ACCESS_RANGES 1	/* Maximum number of device address ranges +				 * mapped through different BAR(s). */ + +#endif /* __BFA_DEFS_PCI_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pm.h b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h new file mode 100644 index 00000000000..e8d6d959006 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_PM_H__ +#define __BFA_DEFS_PM_H__ + +#include <bfa_os_inc.h> + +/** + * BFA power management device states + */ +enum bfa_pm_ds { +	BFA_PM_DS_D0 = 0,	/*  full power mode */ +	BFA_PM_DS_D1 = 1,	/*  power save state 1 */ +	BFA_PM_DS_D2 = 2,	/*  power save state 2 */ +	BFA_PM_DS_D3 = 3,	/*  power off state */ +}; + +#endif /* __BFA_DEFS_PM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pom.h b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h new file mode 100644 index 00000000000..d9fa278472b --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_POM_H__ +#define __BFA_DEFS_POM_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_types.h> + +/** + * POM health status levels for each attributes. + */ +enum bfa_pom_entry_health { +	BFA_POM_HEALTH_NOINFO  = 1,	/*  no information */ +	BFA_POM_HEALTH_NORMAL  = 2,	/*  health is normal */ +	BFA_POM_HEALTH_WARNING = 3,	/*  warning level */ +	BFA_POM_HEALTH_ALARM   = 4,	/*  alarming level */ +}; + +/** + * Reading of temperature/voltage/current/power + */ +struct bfa_pom_entry_s { +	enum bfa_pom_entry_health health;	/*  POM entry health */ +	u32        curr_value;	/*  current value */ +	u32        thr_warn_high;	/*  threshold warning high */ +	u32        thr_warn_low;	/*  threshold warning low */ +	u32        thr_alarm_low;	/*  threshold alaram low */ +	u32        thr_alarm_high;	/*  threshold alarm high */ +}; + +/** + * POM attributes + */ +struct bfa_pom_attr_s { +	struct bfa_pom_entry_s temperature;	/*  centigrade */ +	struct bfa_pom_entry_s voltage;	/*  volts */ +	struct bfa_pom_entry_s curr;	/*  milli amps */ +	struct bfa_pom_entry_s txpower;	/*  micro watts */ +	struct bfa_pom_entry_s rxpower;	/*  micro watts */ +}; + +#endif /* __BFA_DEFS_POM_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h new file mode 100644 index 00000000000..de0696c81bc --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_PORT_H__ +#define __BFA_DEFS_PORT_H__ + +#include <bfa_os_inc.h> +#include <protocol/types.h> +#include <defs/bfa_defs_pport.h> +#include <defs/bfa_defs_ioc.h> + +#define BFA_FCS_FABRIC_IPADDR_SZ  16 + +/** + * symbolic names for base port/virtual port + */ +#define BFA_SYMNAME_MAXLEN	128	/* vmware/windows uses 128 bytes */ +struct bfa_port_symname_s { +	char            symname[BFA_SYMNAME_MAXLEN]; +}; + +/** +* Roles of FCS port: + *     - FCP IM and FCP TM roles cannot be enabled together for a FCS port + *     - Create multiple ports if both IM and TM functions required. + *     - Atleast one role must be specified. + */ +enum bfa_port_role { +	BFA_PORT_ROLE_FCP_IM 	= 0x01,	/*  FCP initiator role */ +	BFA_PORT_ROLE_FCP_TM 	= 0x02,	/*  FCP target role */ +	BFA_PORT_ROLE_FCP_IPFC 	= 0x04,	/*  IP over FC role */ +	BFA_PORT_ROLE_FCP_MAX 	= BFA_PORT_ROLE_FCP_IPFC | BFA_PORT_ROLE_FCP_IM +}; + +/** + * FCS port configuration. + */ +struct bfa_port_cfg_s { +    wwn_t               pwwn;       /*  port wwn */ +    wwn_t               nwwn;       /*  node wwn */ +    struct bfa_port_symname_s  sym_name;   /*  vm port symbolic name */ +    enum bfa_port_role     roles;      /*  FCS port roles */ +	u32			rsvd; +    u8             tag[16];	/*  opaque tag from application */ +}; + +/** + * FCS port states + */ +enum bfa_port_state { +	BFA_PORT_UNINIT  = 0,	/*  PORT is not yet initialized */ +	BFA_PORT_FDISC   = 1,	/*  FDISC is in progress */ +	BFA_PORT_ONLINE  = 2,	/*  login to fabric is complete */ +	BFA_PORT_OFFLINE = 3,	/*  No login to fabric */ +}; + +/** + * FCS port type. Required for VmWare. + */ +enum bfa_port_type { +	BFA_PORT_TYPE_PHYSICAL = 0, +	BFA_PORT_TYPE_VIRTUAL, +}; + +/** + * FCS port offline reason. Required for VmWare. + */ +enum bfa_port_offline_reason { +	BFA_PORT_OFFLINE_UNKNOWN = 0, +	BFA_PORT_OFFLINE_LINKDOWN, +	BFA_PORT_OFFLINE_FAB_UNSUPPORTED,	/*  NPIV not supported by the +						 *    fabric */ +	BFA_PORT_OFFLINE_FAB_NORESOURCES, +	BFA_PORT_OFFLINE_FAB_LOGOUT, +}; + +/** + * FCS lport info. Required for VmWare. + */ +struct bfa_port_info_s { +	u8         port_type;	/* bfa_port_type_t : physical or +					 * virtual */ +	u8         port_state;	/* one of bfa_port_state values */ +	u8         offline_reason;	/* one of bfa_port_offline_reason_t +					 * values */ +	wwn_t           port_wwn; +	wwn_t           node_wwn; + +	/* +	 * following 4 feilds are valid for Physical Ports only +	 */ +	u32        max_vports_supp;	/* Max supported vports */ +	u32        num_vports_inuse;	/* Num of in use vports */ +	u32        max_rports_supp;	/* Max supported rports */ +	u32        num_rports_inuse;	/* Num of doscovered rports */ + +}; + +/** + * FCS port statistics + */ +struct bfa_port_stats_s { +	u32        ns_plogi_sent; +	u32        ns_plogi_rsp_err; +	u32        ns_plogi_acc_err; +	u32        ns_plogi_accepts; +	u32        ns_rejects;	/* NS command rejects */ +	u32        ns_plogi_unknown_rsp; +	u32        ns_plogi_alloc_wait; + +	u32        ns_retries;	/* NS command retries */ +	u32        ns_timeouts;	/* NS command timeouts */ + +	u32        ns_rspnid_sent; +	u32        ns_rspnid_accepts; +	u32        ns_rspnid_rsp_err; +	u32        ns_rspnid_rejects; +	u32        ns_rspnid_alloc_wait; + +	u32        ns_rftid_sent; +	u32        ns_rftid_accepts; +	u32        ns_rftid_rsp_err; +	u32        ns_rftid_rejects; +	u32        ns_rftid_alloc_wait; + +	u32	ns_rffid_sent; +	u32	ns_rffid_accepts; +	u32	ns_rffid_rsp_err; +	u32	ns_rffid_rejects; +	u32	ns_rffid_alloc_wait; + +	u32        ns_gidft_sent; +	u32        ns_gidft_accepts; +	u32        ns_gidft_rsp_err; +	u32        ns_gidft_rejects; +	u32        ns_gidft_unknown_rsp; +	u32        ns_gidft_alloc_wait; + +	/* +	 * Mgmt Server stats +	 */ +	u32        ms_retries;	/* MS command retries */ +	u32        ms_timeouts;	/* MS command timeouts */ +	u32        ms_plogi_sent; +	u32        ms_plogi_rsp_err; +	u32        ms_plogi_acc_err; +	u32        ms_plogi_accepts; +	u32        ms_rejects;	/* NS command rejects */ +	u32        ms_plogi_unknown_rsp; +	u32        ms_plogi_alloc_wait; + +	u32        num_rscn;	/* Num of RSCN received */ +	u32        num_portid_rscn;/* Num portid format RSCN +								* received */ + +	u32	uf_recvs; 	/* unsolicited recv frames      */ +	u32	uf_recv_drops; 	/* dropped received frames	*/ + +	u32	rsvd; 		/* padding for 64 bit alignment */ +}; + +/** + * BFA port attribute returned in queries + */ +struct bfa_port_attr_s { +	enum bfa_port_state state;		/*  port state */ +	u32         pid;		/*  port ID */ +	struct bfa_port_cfg_s   port_cfg;	/*  port configuration */ +	enum bfa_pport_type port_type;	/*  current topology */ +	u32         loopback;	/*  cable is externally looped back */ +	wwn_t		fabric_name; /*  attached switch's nwwn */ +	u8		fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /*  attached +							* fabric's ip addr */ +}; + +/** + * BFA physical port Level events + * Arguments below are in BFAL context from Mgmt + * BFA_PORT_AEN_ONLINE:     [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_OFFLINE:    [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_RLIR:       [in]: None	[out]: pwwn, rlir_data, rlir_len + * BFA_PORT_AEN_SFP_INSERT: [in]: pwwn	[out]: port_id, pwwn + * BFA_PORT_AEN_SFP_REMOVE: [in]: pwwn	[out]: port_id, pwwn + * BFA_PORT_AEN_SFP_POM:    [in]: pwwn	[out]: level, port_id, pwwn + * BFA_PORT_AEN_ENABLE:     [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_DISABLE:    [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_AUTH_ON:    [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_AUTH_OFF:   [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_DISCONNECT: [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_QOS_NEG:    [in]: pwwn	[out]: pwwn + * BFA_PORT_AEN_FABRIC_NAME_CHANGE: [in]: pwwn, [out]: pwwn, fwwn + * + */ +enum bfa_port_aen_event { +	BFA_PORT_AEN_ONLINE     = 1,	/*  Physical Port online event */ +	BFA_PORT_AEN_OFFLINE    = 2,	/*  Physical Port offline event */ +	BFA_PORT_AEN_RLIR       = 3,	/*  RLIR event, not supported */ +	BFA_PORT_AEN_SFP_INSERT = 4,	/*  SFP inserted event */ +	BFA_PORT_AEN_SFP_REMOVE = 5,	/*  SFP removed event */ +	BFA_PORT_AEN_SFP_POM    = 6,	/*  SFP POM event */ +	BFA_PORT_AEN_ENABLE     = 7,	/*  Physical Port enable event */ +	BFA_PORT_AEN_DISABLE    = 8,	/*  Physical Port disable event */ +	BFA_PORT_AEN_AUTH_ON    = 9,	/*  Physical Port auth success event */ +	BFA_PORT_AEN_AUTH_OFF   = 10,	/*  Physical Port auth fail event */ +	BFA_PORT_AEN_DISCONNECT = 11,	/*  Physical Port disconnect event */ +	BFA_PORT_AEN_QOS_NEG    = 12,  	/*  Base Port QOS negotiation event */ +	BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /*  Fabric Name/WWN change +					       * event */ +	BFA_PORT_AEN_SFP_ACCESS_ERROR = 14, /*  SFP read error event */ +	BFA_PORT_AEN_SFP_UNSUPPORT = 15, /*  Unsupported SFP event */ +}; + +enum bfa_port_aen_sfp_pom { +	BFA_PORT_AEN_SFP_POM_GREEN = 1,	/*  Normal */ +	BFA_PORT_AEN_SFP_POM_AMBER = 2,	/*  Warning */ +	BFA_PORT_AEN_SFP_POM_RED   = 3,	/*  Critical */ +	BFA_PORT_AEN_SFP_POM_MAX   = BFA_PORT_AEN_SFP_POM_RED +}; + +struct bfa_port_aen_data_s { +	enum bfa_ioc_type_e ioc_type; +	wwn_t           pwwn;	      /*  WWN of the physical port */ +	wwn_t           fwwn;	      /*  WWN of the fabric port */ +	mac_t           mac;	      /*  MAC addres of the ethernet port, +				       * applicable to CNA port only */ +	int             phy_port_num; /*! For SFP related events */ +	enum bfa_port_aen_sfp_pom level; /*  Only transitions will +					  * be informed */ +}; + +#endif /* __BFA_DEFS_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h new file mode 100644 index 00000000000..a000bc4e2d4 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_PPORT_H__ +#define __BFA_DEFS_PPORT_H__ + +#include <bfa_os_inc.h> +#include <protocol/fc.h> +#include <defs/bfa_defs_types.h> +#include <defs/bfa_defs_qos.h> +#include <cna/pstats/phyport_defs.h> + +/* Modify char* port_stt[] in bfal_port.c if a new state was added */ +enum bfa_pport_states { +	BFA_PPORT_ST_UNINIT 		= 1, +	BFA_PPORT_ST_ENABLING_QWAIT 	= 2, +	BFA_PPORT_ST_ENABLING 		= 3, +	BFA_PPORT_ST_LINKDOWN 		= 4, +	BFA_PPORT_ST_LINKUP 		= 5, +	BFA_PPORT_ST_DISABLING_QWAIT 	= 6, +	BFA_PPORT_ST_DISABLING		= 7, +	BFA_PPORT_ST_DISABLED 		= 8, +	BFA_PPORT_ST_STOPPED 		= 9, +	BFA_PPORT_ST_IOCDOWN 		= 10, +	BFA_PPORT_ST_IOCDIS 		= 11, +	BFA_PPORT_ST_FWMISMATCH		= 12, +	BFA_PPORT_ST_MAX_STATE, +}; + +/** + * 	Port speed settings. Each specific speed is a bit field. Use multiple + *      bits to specify speeds to be selected for auto-negotiation. + */ +enum bfa_pport_speed { +	BFA_PPORT_SPEED_UNKNOWN = 0, +	BFA_PPORT_SPEED_1GBPS 	= 1, +	BFA_PPORT_SPEED_2GBPS 	= 2, +	BFA_PPORT_SPEED_4GBPS 	= 4, +	BFA_PPORT_SPEED_8GBPS 	= 8, +	BFA_PPORT_SPEED_10GBPS 	= 10, +	BFA_PPORT_SPEED_AUTO = +		(BFA_PPORT_SPEED_1GBPS | BFA_PPORT_SPEED_2GBPS | +		 BFA_PPORT_SPEED_4GBPS | BFA_PPORT_SPEED_8GBPS), +}; + +/** + * 		Port operational type (in sync with SNIA port type). + */ +enum bfa_pport_type { +	BFA_PPORT_TYPE_UNKNOWN = 1,	/*  port type is unkown */ +	BFA_PPORT_TYPE_TRUNKED = 2,	/*  Trunked mode */ +	BFA_PPORT_TYPE_NPORT   = 5,	/*  P2P with switched fabric */ +	BFA_PPORT_TYPE_NLPORT  = 6,	/*  public loop */ +	BFA_PPORT_TYPE_LPORT   = 20,	/*  private loop */ +	BFA_PPORT_TYPE_P2P     = 21,	/*  P2P with no switched fabric */ +	BFA_PPORT_TYPE_VPORT   = 22,	/*  NPIV - virtual port */ +}; + +/** + * 		Port topology setting. A port's topology and fabric login status + * 		determine its operational type. + */ +enum bfa_pport_topology { +	BFA_PPORT_TOPOLOGY_NONE = 0,	/*  No valid topology */ +	BFA_PPORT_TOPOLOGY_P2P  = 1,	/*  P2P only */ +	BFA_PPORT_TOPOLOGY_LOOP = 2,	/*  LOOP topology */ +	BFA_PPORT_TOPOLOGY_AUTO = 3,	/*  auto topology selection */ +}; + +/** + * 		Physical port loopback types. + */ +enum bfa_pport_opmode { +	BFA_PPORT_OPMODE_NORMAL   = 0x00, /*  normal non-loopback mode */ +	BFA_PPORT_OPMODE_LB_INT   = 0x01, /*  internal loop back */ +	BFA_PPORT_OPMODE_LB_SLW   = 0x02, /*  serial link wrapback (serdes) */ +	BFA_PPORT_OPMODE_LB_EXT   = 0x04, /*  external loop back (serdes) */ +	BFA_PPORT_OPMODE_LB_CBL   = 0x08, /*  cabled loop back */ +	BFA_PPORT_OPMODE_LB_NLINT = 0x20, /*  NL_Port internal loopback */ +}; + +#define BFA_PPORT_OPMODE_LB_HARD(_mode)			\ +	((_mode == BFA_PPORT_OPMODE_LB_INT) ||		\ +     (_mode == BFA_PPORT_OPMODE_LB_SLW) ||		\ +     (_mode == BFA_PPORT_OPMODE_LB_EXT)) + +/** +		Port State (in sync with SNIA port state). + */ +enum bfa_pport_snia_state { +	BFA_PPORT_STATE_UNKNOWN  = 1,	/*  port is not initialized */ +	BFA_PPORT_STATE_ONLINE   = 2,	/*  port is ONLINE */ +	BFA_PPORT_STATE_DISABLED = 3,	/*  port is disabled by user */ +	BFA_PPORT_STATE_BYPASSED = 4,	/*  port is bypassed (in LOOP) */ +	BFA_PPORT_STATE_DIAG     = 5,	/*  port diagnostics is active */ +	BFA_PPORT_STATE_LINKDOWN = 6,	/*  link is down */ +	BFA_PPORT_STATE_LOOPBACK = 8,	/*  port is looped back */ +}; + +/** + * 		Port link state + */ +enum bfa_pport_linkstate { +	BFA_PPORT_LINKUP 	 = 1,	/*  Physical port/Trunk link up */ +	BFA_PPORT_LINKDOWN 	 = 2,	/*  Physical port/Trunk link down */ +	BFA_PPORT_TRUNK_LINKDOWN = 3,	/*  Trunk link down (new tmaster) */ +}; + +/** + * 		Port link state event + */ +#define bfa_pport_event_t enum bfa_pport_linkstate + +/** + * 		Port link state reason code + */ +enum bfa_pport_linkstate_rsn { +	BFA_PPORT_LINKSTATE_RSN_NONE		= 0, +	BFA_PPORT_LINKSTATE_RSN_DISABLED 	= 1, +	BFA_PPORT_LINKSTATE_RSN_RX_NOS 		= 2, +	BFA_PPORT_LINKSTATE_RSN_RX_OLS 		= 3, +	BFA_PPORT_LINKSTATE_RSN_RX_LIP 		= 4, +	BFA_PPORT_LINKSTATE_RSN_RX_LIPF7 	= 5, +	BFA_PPORT_LINKSTATE_RSN_SFP_REMOVED 	= 6, +	BFA_PPORT_LINKSTATE_RSN_PORT_FAULT 	= 7, +	BFA_PPORT_LINKSTATE_RSN_RX_LOS 		= 8, +	BFA_PPORT_LINKSTATE_RSN_LOCAL_FAULT 	= 9, +	BFA_PPORT_LINKSTATE_RSN_REMOTE_FAULT 	= 10, +	BFA_PPORT_LINKSTATE_RSN_TIMEOUT 	= 11, + + + +	/* CEE related reason codes/errors */ +	CEE_LLDP_INFO_AGED_OUT       = 20, +	CEE_LLDP_SHUTDOWN_TLV_RCVD   = 21, +	CEE_PEER_NOT_ADVERTISE_DCBX  = 22, +	CEE_PEER_NOT_ADVERTISE_PG    = 23, +	CEE_PEER_NOT_ADVERTISE_PFC   = 24, +	CEE_PEER_NOT_ADVERTISE_FCOE  = 25, +	CEE_PG_NOT_COMPATIBLE        = 26, +	CEE_PFC_NOT_COMPATIBLE       = 27, +	CEE_FCOE_NOT_COMPATIBLE      = 28, +	CEE_BAD_PG_RCVD              = 29, +	CEE_BAD_BW_RCVD              = 30, +	CEE_BAD_PFC_RCVD             = 31, +	CEE_BAD_FCOE_PRI_RCVD        = 32, +	CEE_FCOE_PRI_PFC_OFF         = 33, +	CEE_DUP_CONTROL_TLV_RCVD     = 34, +	CEE_DUP_FEAT_TLV_RCVD        = 35, +	CEE_APPLY_NEW_CFG            = 36,	/* reason, not an error */ +	CEE_PROTOCOL_INIT            = 37,  /* reason, not an error */ +	CEE_PHY_LINK_DOWN            = 38, +	CEE_LLS_FCOE_ABSENT          = 39, +	CEE_LLS_FCOE_DOWN            = 40 +}; + +/** + *      Default Target Rate Limiting Speed. + */ +#define BFA_PPORT_DEF_TRL_SPEED  BFA_PPORT_SPEED_1GBPS + +/** + *      Physical port configuration + */ +struct bfa_pport_cfg_s { +	u8         topology;	/*  bfa_pport_topology		*/ +	u8         speed;		/*  enum bfa_pport_speed	*/ +	u8         trunked;	/*  trunked or not		*/ +	u8         qos_enabled;	/*  qos enabled or not		*/ +	u8         trunk_ports;	/*  bitmap of trunked ports	*/ +	u8         cfg_hardalpa;	/*  is hard alpa configured	*/ +	u16        maxfrsize;	/*  maximum frame size		*/ +	u8         hardalpa;	/*  configured hard alpa	*/ +	u8         rx_bbcredit;	/*  receive buffer credits	*/ +	u8         tx_bbcredit;	/*  transmit buffer credits	*/ +	u8         ratelimit;	/*  ratelimit enabled or not	*/ +	u8         trl_def_speed;	/*  ratelimit default speed	*/ +	u8		rsvd[3]; +	u16   	path_tov;	/*  device path timeout	*/ +	u16   	q_depth;	/*  SCSI Queue depth		*/ +}; + +/** + * 		Port attribute values. + */ +struct bfa_pport_attr_s { +	/* +	 * Static fields +	 */ +	wwn_t           nwwn;		/*  node wwn */ +	wwn_t           pwwn;		/*  port wwn */ +	enum fc_cos     cos_supported;	/*  supported class of services */ +	u32        rsvd; +	struct fc_symname_s    port_symname;	/*  port symbolic name */ +	enum bfa_pport_speed speed_supported; /*  supported speeds */ +	bfa_boolean_t   pbind_enabled;	/*  Will be set if Persistent binding +					 *   enabled. Relevant only in Windows +					 */ + +	/* +	 * Configured values +	 */ +	struct bfa_pport_cfg_s pport_cfg;	/*  pport cfg */ + +	/* +	 * Dynamic field - info from BFA +	 */ +	enum bfa_pport_states 	port_state;	/*  current port state */ +	enum bfa_pport_speed 	speed;		/*  current speed */ +	enum bfa_pport_topology 	topology;	/*  current topology */ +	bfa_boolean_t		beacon;		/*  current beacon status */ +	bfa_boolean_t		link_e2e_beacon;/*  set if link beacon on */ +	bfa_boolean_t		plog_enabled;	/*  set if portlog is enabled*/ + +	/* +	 * Dynamic field - info from FCS +	 */ +	u32        	pid;		/*  port ID */ +	enum bfa_pport_type 	port_type;	/*  current topology */ +	u32        	loopback;	/*  external loopback */ +	u32		rsvd1; +	u32		rsvd2;		/*  padding for 64 bit */ +}; + +/** + * 		FC Port statistics. + */ +struct bfa_pport_fc_stats_s { +	u64        secs_reset;	/*  seconds since stats is reset */ +	u64        tx_frames;	/*  transmitted frames */ +	u64        tx_words;	/*  transmitted words */ +	u64        rx_frames;	/*  received frames */ +	u64        rx_words;	/*  received words */ +	u64        lip_count;	/*  LIPs seen */ +	u64        nos_count;	/*  NOS count */ +	u64        error_frames;	/*  errored frames (sent?) */ +	u64        dropped_frames;	/*  dropped frames */ +	u64        link_failures;	/*  link failure count */ +	u64        loss_of_syncs;	/*  loss of sync count */ +	u64        loss_of_signals;/*  loss of signal count */ +	u64        primseq_errs;	/*  primitive sequence protocol */ +	u64        bad_os_count;	/*  invalid ordered set */ +	u64        err_enc_out;	/*  Encoding error outside frame */ +	u64        invalid_crcs;	/*  frames received with invalid CRC*/ +	u64	undersized_frm; /*  undersized frames */ +	u64	oversized_frm;	/*  oversized frames */ +	u64	bad_eof_frm;	/*  frames with bad EOF */ +	struct bfa_qos_stats_s	qos_stats;	/*  QoS statistics */ +}; + +/** + * 		Eth Port statistics. + */ +struct bfa_pport_eth_stats_s { +	u64	secs_reset;	/*  seconds since stats is reset */ +	u64	frame_64;      /*  both rx and tx counter */ +	u64	frame_65_127;      /* both rx and tx counter */ +	u64	frame_128_255;     /* both rx and tx counter */ +	u64	frame_256_511;     /* both rx and tx counter */ +	u64	frame_512_1023;    /* both rx and tx counter */ +	u64	frame_1024_1518;   /* both rx and tx counter */ +	u64	frame_1519_1522;   /* both rx and tx counter */ + +	u64	tx_bytes; +	u64	tx_packets; +	u64	tx_mcast_packets; +	u64	tx_bcast_packets; +	u64	tx_control_frame; +	u64	tx_drop; +	u64	tx_jabber; +	u64	tx_fcs_error; +	u64	tx_fragments; + +	u64	rx_bytes; +	u64	rx_packets; +	u64	rx_mcast_packets; +	u64	rx_bcast_packets; +	u64	rx_control_frames; +	u64	rx_unknown_opcode; +	u64	rx_drop; +	u64	rx_jabber; +	u64	rx_fcs_error; +	u64	rx_alignment_error; +	u64	rx_frame_length_error; +	u64	rx_code_error; +	u64	rx_fragments; + +	u64	rx_pause; /* BPC */ +	u64	rx_zero_pause; /*  BPC Pause cancellation */ +	u64	tx_pause;      /* BPC */ +	u64	tx_zero_pause; /*  BPC Pause cancellation */ +	u64	rx_fcoe_pause; /* BPC */ +	u64	rx_fcoe_zero_pause; /*  BPC Pause cancellation */ +	u64	tx_fcoe_pause;      /* BPC */ +	u64	tx_fcoe_zero_pause; /*  BPC Pause cancellation */ +}; + +/** + * 		Port statistics. + */ +union bfa_pport_stats_u { +	struct bfa_pport_fc_stats_s	fc; +	struct bfa_pport_eth_stats_s 	eth; +}; + +/** + *              Port FCP mappings. + */ +struct bfa_pport_fcpmap_s { +	char		osdevname[256]; +	u32	bus; +	u32        target; +	u32        oslun; +	u32        fcid; +	wwn_t           nwwn; +	wwn_t           pwwn; +	u64        fcplun; +	char		luid[256]; +}; + +/** + *              Port RNID info. + */ +struct bfa_pport_rnid_s { +	wwn_t             wwn; +	u32          unittype; +	u32          portid; +	u32          attached_nodes_num; +	u16          ip_version; +	u16          udp_port; +	u8           ipaddr[16]; +	u16          rsvd; +	u16          topologydiscoveryflags; +}; + +/** + * 		Link state information + */ +struct bfa_pport_link_s { +	u8         linkstate;	/*  Link state bfa_pport_linkstate */ +	u8         linkstate_rsn;	/*  bfa_pport_linkstate_rsn_t */ +	u8         topology;	/*  P2P/LOOP bfa_pport_topology */ +	u8         speed;		/*  Link speed (1/2/4/8 G) */ +	u32        linkstate_opt;	/*  Linkstate optional data (debug) */ +	u8         trunked;	/*  Trunked or not (1 or 0) */ +	u8         resvd[3]; +	struct bfa_qos_attr_s  qos_attr;   /* QoS Attributes */ +	struct bfa_qos_vc_attr_s qos_vc_attr;  /*  VC info from ELP */ +	union { +		struct { +			u8         tmaster;/*  Trunk Master or +						 *    not (1 or 0) */ +			u8         tlinks;	/*  Trunk links bitmap +						 *    (linkup) */ +			u8         resv1;	/*  Reserved */ +		} trunk_info; + +		struct { +			u8         myalpa;	   /*  alpa claimed */ +			u8         login_req; /*  Login required or +						    *    not (1 or 0) */ +			u8         alpabm_val;/*  alpa bitmap valid +						    *    or not (1 or 0) */ +			struct fc_alpabm_s     alpabm;	   /*  alpa bitmap */ +		} loop_info; +	} tl; +}; + +#endif /* __BFA_DEFS_PPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_qos.h b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h new file mode 100644 index 00000000000..aadbacd1d2d --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_QOS_H__ +#define __BFA_DEFS_QOS_H__ + +/** + * QoS states + */ +enum bfa_qos_state { +	BFA_QOS_ONLINE = 1,		/*  QoS is online */ +	BFA_QOS_OFFLINE = 2,		/*  QoS is offline */ +}; + + +/** + * QoS  Priority levels. + */ +enum bfa_qos_priority { +	BFA_QOS_UNKNOWN = 0, +	BFA_QOS_HIGH  = 1,	/*  QoS Priority Level High */ +	BFA_QOS_MED  =  2,	/*  QoS Priority Level Medium */ +	BFA_QOS_LOW  =  3,	/*  QoS Priority Level Low */ +}; + + +/** + * QoS  bandwidth allocation for each priority level + */ +enum bfa_qos_bw_alloc { +	BFA_QOS_BW_HIGH  = 60,	/*  bandwidth allocation for High */ +	BFA_QOS_BW_MED  =  30,	/*  bandwidth allocation for Medium */ +	BFA_QOS_BW_LOW  =  10,	/*  bandwidth allocation for Low */ +}; + +/** + * QoS attribute returned in QoS Query + */ +struct bfa_qos_attr_s { +	enum bfa_qos_state state;		/*  QoS current state */ +	u32  total_bb_cr;  	 	/*  Total BB Credits */ +}; + +/** + * These fields should be displayed only from the CLI. + * There will be a separate BFAL API (get_qos_vc_attr ?) + * to retrieve this. + * + */ +#define  BFA_QOS_MAX_VC  16 + +struct bfa_qos_vc_info_s { +	u8 vc_credit; +	u8 borrow_credit; +	u8 priority; +	u8 resvd; +}; + +struct bfa_qos_vc_attr_s { +	u16  total_vc_count;                    /*  Total VC Count */ +	u16  shared_credit; +	u32  elp_opmode_flags; +	struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC];  /*   as many as +							    * total_vc_count */ +}; + +/** + * QoS statistics + */ +struct bfa_qos_stats_s { +	u32	flogi_sent; 		/*  QoS Flogi sent */ +	u32	flogi_acc_recvd;	/*  QoS Flogi Acc received */ +	u32	flogi_rjt_recvd; /*  QoS Flogi rejects received */ +	u32	flogi_retries;		/*  QoS Flogi retries */ + +	u32	elp_recvd; 	   	/*  QoS ELP received */ +	u32	elp_accepted;       /*  QoS ELP Accepted */ +	u32	elp_rejected;       /*  QoS ELP rejected */ +	u32	elp_dropped;        /*  QoS ELP dropped  */ + +	u32	qos_rscn_recvd;     /*  QoS RSCN received */ +	u32	rsvd; 		/* padding for 64 bit alignment */ +}; + +#endif /* __BFA_DEFS_QOS_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_rport.h b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h new file mode 100644 index 00000000000..e0af59d6d2f --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_RPORT_H__ +#define __BFA_DEFS_RPORT_H__ + +#include <bfa_os_inc.h> +#include <protocol/types.h> +#include <defs/bfa_defs_pport.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_qos.h> + +/** + * FCS remote port states + */ +enum bfa_rport_state { +	BFA_RPORT_UNINIT 	= 0,	/*  PORT is not yet initialized */ +	BFA_RPORT_OFFLINE 	= 1,	/*  rport is offline */ +	BFA_RPORT_PLOGI 	= 2,	/*  PLOGI to rport is in progress */ +	BFA_RPORT_ONLINE 	= 3,	/*  login to rport is complete */ +	BFA_RPORT_PLOGI_RETRY 	= 4,	/*  retrying login to rport */ +	BFA_RPORT_NSQUERY 	= 5,	/*  nameserver query */ +	BFA_RPORT_ADISC 	= 6,	/*  ADISC authentication */ +	BFA_RPORT_LOGO 		= 7,	/*  logging out with rport */ +	BFA_RPORT_LOGORCV 	= 8,	/*  handling LOGO from rport */ +	BFA_RPORT_NSDISC 	= 9,	/*  re-discover rport */ +}; + +/** + *  Rport Scsi Function : Initiator/Target. + */ +enum bfa_rport_function { +	BFA_RPORT_INITIATOR 	= 0x01,	/*  SCSI Initiator	*/ +	BFA_RPORT_TARGET 	= 0x02,	/*  SCSI Target	*/ +}; + +/** + * port/node symbolic names for rport + */ +#define BFA_RPORT_SYMNAME_MAXLEN	255 +struct bfa_rport_symname_s { +	char            symname[BFA_RPORT_SYMNAME_MAXLEN]; +}; + +struct bfa_rport_hal_stats_s { +	u32        sm_un_cr;	    /*  uninit: create events      */ +	u32        sm_un_unexp;	    /*  uninit: exception events   */ +	u32        sm_cr_on;	    /*  created: online events     */ +	u32        sm_cr_del;	    /*  created: delete events     */ +	u32        sm_cr_hwf;	    /*  created: IOC down          */ +	u32        sm_cr_unexp;	    /*  created: exception events  */ +	u32        sm_fwc_rsp;	    /*  fw create: f/w responses   */ +	u32        sm_fwc_del;	    /*  fw create: delete events   */ +	u32        sm_fwc_off;	    /*  fw create: offline events  */ +	u32        sm_fwc_hwf;	    /*  fw create: IOC down        */ +	u32        sm_fwc_unexp;	    /*  fw create: exception events*/ +	u32        sm_on_off;	    /*  online: offline events     */ +	u32        sm_on_del;	    /*  online: delete events      */ +	u32        sm_on_hwf;	    /*  online: IOC down events    */ +	u32        sm_on_unexp;	    /*  online: exception events   */ +	u32        sm_fwd_rsp;	    /*  fw delete: fw responses    */ +	u32        sm_fwd_del;	    /*  fw delete: delete events   */ +	u32        sm_fwd_hwf;	    /*  fw delete: IOC down events */ +	u32        sm_fwd_unexp;	    /*  fw delete: exception events*/ +	u32        sm_off_del;	    /*  offline: delete events     */ +	u32        sm_off_on;	    /*  offline: online events     */ +	u32        sm_off_hwf;	    /*  offline: IOC down events   */ +	u32        sm_off_unexp;	    /*  offline: exception events  */ +	u32        sm_del_fwrsp;	    /*  delete: fw responses       */ +	u32        sm_del_hwf;	    /*  delete: IOC down events    */ +	u32        sm_del_unexp;	    /*  delete: exception events   */ +	u32        sm_delp_fwrsp;	    /*  delete pend: fw responses  */ +	u32        sm_delp_hwf;	    /*  delete pend: IOC downs     */ +	u32        sm_delp_unexp;	    /*  delete pend: exceptions    */ +	u32        sm_offp_fwrsp;	    /*  off-pending: fw responses  */ +	u32        sm_offp_del;	    /*  off-pending: deletes       */ +	u32        sm_offp_hwf;	    /*  off-pending: IOC downs     */ +	u32        sm_offp_unexp;	    /*  off-pending: exceptions    */ +	u32        sm_iocd_off;	    /*  IOC down: offline events   */ +	u32        sm_iocd_del;	    /*  IOC down: delete events    */ +	u32        sm_iocd_on;	    /*  IOC down: online events    */ +	u32        sm_iocd_unexp;	    /*  IOC down: exceptions       */ +	u32        rsvd; +}; + +/** + * FCS remote port statistics + */ +struct bfa_rport_stats_s { +	u32        offlines;           /*  remote port offline count  */ +	u32        onlines;            /*  remote port online count   */ +	u32        rscns;              /*  RSCN affecting rport       */ +	u32        plogis;		    /*  plogis sent                */ +	u32        plogi_accs;	    /*  plogi accepts              */ +	u32        plogi_timeouts;	    /*  plogi timeouts             */ +	u32        plogi_rejects;	    /*  rcvd plogi rejects         */ +	u32        plogi_failed;	    /*  local failure              */ +	u32        plogi_rcvd;	    /*  plogis rcvd                */ +	u32        prli_rcvd;          /*  inbound PRLIs              */ +	u32        adisc_rcvd;         /*  ADISCs received            */ +	u32        adisc_rejects;      /*  recvd  ADISC rejects       */ +	u32        adisc_sent;         /*  ADISC requests sent        */ +	u32        adisc_accs;         /*  ADISC accepted by rport    */ +	u32        adisc_failed;       /*  ADISC failed (no response) */ +	u32        adisc_rejected;     /*  ADISC rejected by us    */ +	u32        logos;              /*  logos sent                 */ +	u32        logo_accs;          /*  LOGO accepts from rport    */ +	u32        logo_failed;        /*  LOGO failures              */ +	u32        logo_rejected;      /*  LOGO rejects from rport    */ +	u32        logo_rcvd;          /*  LOGO from remote port      */ + +	u32        rpsc_rcvd;         /*  RPSC received            */ +	u32        rpsc_rejects;      /*  recvd  RPSC rejects       */ +	u32        rpsc_sent;         /*  RPSC requests sent        */ +	u32        rpsc_accs;         /*  RPSC accepted by rport    */ +	u32        rpsc_failed;       /*  RPSC failed (no response) */ +	u32        rpsc_rejected;     /*  RPSC rejected by us    */ + +	u32        rsvd; +	struct bfa_rport_hal_stats_s	hal_stats;  /*  BFA rport stats    */ +}; + +/** + *  Rport's QoS attributes + */ +struct bfa_rport_qos_attr_s { +	enum bfa_qos_priority qos_priority;  /*  rport's QoS priority   */ +	u32	       qos_flow_id;	  /*  QoS flow Id	 */ +}; + +/** + * FCS remote port attributes returned in queries + */ +struct bfa_rport_attr_s { +	wwn_t           	nwwn;	/*  node wwn */ +	wwn_t           	pwwn;	/*  port wwn */ +	enum fc_cos cos_supported;	/*  supported class of services */ +	u32        	pid;	/*  port ID */ +	u32        	df_sz;	/*  Max payload size */ +	enum bfa_rport_state 	state;	/*  Rport State machine state */ +	enum fc_cos        	fc_cos;	/*  FC classes of services */ +	bfa_boolean_t   	cisc;	/*  CISC capable device */ +	struct bfa_rport_symname_s symname; /*  Symbolic Name */ +	enum bfa_rport_function	scsi_function; /*  Initiator/Target */ +	struct bfa_rport_qos_attr_s qos_attr; /*  qos attributes  */ +	enum bfa_pport_speed curr_speed;   /*  operating speed got from +					    * RPSC ELS. UNKNOWN, if RPSC +					    * is not supported */ +	bfa_boolean_t 	trl_enforced;	/*  TRL enforced ? TRUE/FALSE */ +	enum bfa_pport_speed	assigned_speed;	/* Speed assigned by the user. +						 * will be used if RPSC is not +						 * supported by the rport */ +}; + +#define bfa_rport_aen_qos_data_t struct bfa_rport_qos_attr_s + +/** + * BFA remote port events + * Arguments below are in BFAL context from Mgmt + * BFA_RPORT_AEN_ONLINE:    [in]: lpwwn	[out]: vf_id, lpwwn, rpwwn + * BFA_RPORT_AEN_OFFLINE:   [in]: lpwwn [out]: vf_id, lpwwn, rpwwn + * BFA_RPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn + * BFA_RPORT_AEN_QOS_PRIO:  [in]: lpwwn [out]: vf_id, lpwwn, rpwwn, prio + * BFA_RPORT_AEN_QOS_FLOWID:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn, flow_id + */ +enum bfa_rport_aen_event { +	BFA_RPORT_AEN_ONLINE      = 1,	/*  RPort online event */ +	BFA_RPORT_AEN_OFFLINE     = 2,	/*  RPort offline event */ +	BFA_RPORT_AEN_DISCONNECT  = 3,	/*  RPort disconnect event */ +	BFA_RPORT_AEN_QOS_PRIO    = 4,	/*  QOS priority change event */ +	BFA_RPORT_AEN_QOS_FLOWID  = 5,	/*  QOS flow Id change event */ +}; + +struct bfa_rport_aen_data_s { +	u16        vf_id;	/*  vf_id of this logical port */ +	u16        rsvd[3]; +	wwn_t           ppwwn;	/*  WWN of its physical port */ +	wwn_t           lpwwn;	/*  WWN of this logical port */ +	wwn_t           rpwwn;	/*  WWN of this remote port */ +	union { +		bfa_rport_aen_qos_data_t qos; +	} priv; +}; + +#endif /* __BFA_DEFS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h new file mode 100644 index 00000000000..cdceaeb9f4b --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_STATUS_H__ +#define __BFA_DEFS_STATUS_H__ + +/** + * API status return values + * + * NOTE: The error msgs are auto generated from the comments. Only singe line + * comments are supported + */ +enum bfa_status { +	BFA_STATUS_OK 		= 0,	/*  Success */ +	BFA_STATUS_FAILED 	= 1,	/*  Operation failed */ +	BFA_STATUS_EINVAL 	= 2,	/*  Invalid params Check input +					 * parameters */ +	BFA_STATUS_ENOMEM 	= 3,	/*  Out of resources */ +	BFA_STATUS_ENOSYS 	= 4,	/*  Function not implemented */ +	BFA_STATUS_ETIMER 	= 5,	/*  Timer expired - Retry, if +					 * persists, contact support */ +	BFA_STATUS_EPROTOCOL 	= 6,	/*  Protocol error */ +	BFA_STATUS_ENOFCPORTS 	= 7,	/*  No FC ports resources */ +	BFA_STATUS_NOFLASH 	= 8,	/*  Flash not present */ +	BFA_STATUS_BADFLASH 	= 9,	/*  Flash is corrupted or bad */ +	BFA_STATUS_SFP_UNSUPP 	= 10,	/*  Unsupported SFP - Replace SFP */ +	BFA_STATUS_UNKNOWN_VFID = 11,	/*  VF_ID not found */ +	BFA_STATUS_DATACORRUPTED = 12,	/*  Diag returned data corrupted +					 * contact support */ +	BFA_STATUS_DEVBUSY 	= 13,	/*  Device busy - Retry operation */ +	BFA_STATUS_ABORTED 	= 14,	/*  Operation aborted */ +	BFA_STATUS_NODEV 	= 15,	/*  Dev is not present */ +	BFA_STATUS_HDMA_FAILED 	= 16,	/*  Host dma failed contact support */ +	BFA_STATUS_FLASH_BAD_LEN = 17,	/*  Flash bad length */ +	BFA_STATUS_UNKNOWN_LWWN = 18,	/*  LPORT PWWN not found */ +	BFA_STATUS_UNKNOWN_RWWN = 19,	/*  RPORT PWWN not found */ +	BFA_STATUS_FCPT_LS_RJT 	= 20,	/*  Got LS_RJT for FC Pass +					 * through Req */ +	BFA_STATUS_VPORT_EXISTS = 21,	/*  VPORT already exists */ +	BFA_STATUS_VPORT_MAX 	= 22,	/*  Reached max VPORT supported +					 * limit */ +	BFA_STATUS_UNSUPP_SPEED = 23,	/*  Invalid Speed Check speed +					 * setting */ +	BFA_STATUS_INVLD_DFSZ 	= 24,	/*  Invalid Max data field size */ +	BFA_STATUS_CNFG_FAILED 	= 25,	/*  Setting can not be persisted */ +	BFA_STATUS_CMD_NOTSUPP 	= 26,	/*  Command/API not supported */ +	BFA_STATUS_NO_ADAPTER 	= 27,	/*  No Brocade Adapter Found */ +	BFA_STATUS_LINKDOWN 	= 28,	/*  Link is down - Check or replace +					 * SFP/cable */ +	BFA_STATUS_FABRIC_RJT 	= 29,	/*  Reject from attached fabric */ +	BFA_STATUS_UNKNOWN_VWWN = 30,	/*  VPORT PWWN not found */ +	BFA_STATUS_NSLOGIN_FAILED = 31,	/*  Nameserver login failed */ +	BFA_STATUS_NO_RPORTS 	= 32,	/*  No remote ports found */ +	BFA_STATUS_NSQUERY_FAILED = 33,	/*  Nameserver query failed */ +	BFA_STATUS_PORT_OFFLINE = 34,	/*  Port is not online */ +	BFA_STATUS_RPORT_OFFLINE = 35,	/*  RPORT is not online */ +	BFA_STATUS_TGTOPEN_FAILED = 36,	/*  Remote SCSI target open failed */ +	BFA_STATUS_BAD_LUNS 	= 37,	/*  No valid LUNs found */ +	BFA_STATUS_IO_FAILURE 	= 38,	/*  SCSI target IO failure */ +	BFA_STATUS_NO_FABRIC 	= 39,	/*  No switched fabric present */ +	BFA_STATUS_EBADF 	= 40,	/*  Bad file descriptor */ +	BFA_STATUS_EINTR 	= 41,	/*  A signal was caught during ioctl */ +	BFA_STATUS_EIO 		= 42,	/*  I/O error */ +	BFA_STATUS_ENOTTY 	= 43,	/*  Inappropriate I/O control +					 * operation */ +	BFA_STATUS_ENXIO 	= 44,	/*  No such device or address */ +	BFA_STATUS_EFOPEN 	= 45,	/*  Failed to open file */ +	BFA_STATUS_VPORT_WWN_BP = 46,	/*  WWN is same as base port's WWN */ +	BFA_STATUS_PORT_NOT_DISABLED = 47, /*  Port not disabled disable port +					    * first */ +	BFA_STATUS_BADFRMHDR 	= 48,	/*  Bad frame header */ +	BFA_STATUS_BADFRMSZ 	= 49,	/*  Bad frame size check and replace +					 * SFP/cable */ +	BFA_STATUS_MISSINGFRM 	= 50,	/*  Missing frame check and replace +					 * SFP/cable */ +	BFA_STATUS_LINKTIMEOUT 	= 51,	/*  Link timeout check and replace +					 * SFP/cable */ +	BFA_STATUS_NO_FCPIM_NEXUS = 52,	/*  No FCP Nexus exists with the +					 * rport */ +	BFA_STATUS_CHECKSUM_FAIL = 53,	/*  checksum failure */ +	BFA_STATUS_GZME_FAILED 	= 54,	/*  Get zone member query failed */ +	BFA_STATUS_SCSISTART_REQD = 55,	/*  SCSI disk require START command */ +	BFA_STATUS_IOC_FAILURE 	= 56,	/*  IOC failure - Retry, if persists +					 * contact support */ +	BFA_STATUS_INVALID_WWN 	= 57,	/*  Invalid WWN */ +	BFA_STATUS_MISMATCH 	= 58,	/*  Version mismatch */ +	BFA_STATUS_IOC_ENABLED 	= 59,	/*  IOC is already enabled */ +	BFA_STATUS_ADAPTER_ENABLED = 60, /*  Adapter is not disabled disable +					  * adapter first */ +	BFA_STATUS_IOC_NON_OP 	= 61,	/*  IOC is not operational. Enable IOC +					 * and if it still fails, +					 * contact support */ +	BFA_STATUS_ADDR_MAP_FAILURE = 62, /*  PCI base address not mapped +					   * in OS */ +	BFA_STATUS_SAME_NAME 	= 63,	/*  Name exists! use a different +					 * name */ +	BFA_STATUS_PENDING      = 64,   /*  API completes asynchronously */ +	BFA_STATUS_8G_SPD	= 65,	/*  Speed setting not valid for +					 * 8G HBA */ +	BFA_STATUS_4G_SPD	= 66,	/*  Speed setting not valid for +					 * 4G HBA */ +	BFA_STATUS_AD_IS_ENABLE = 67,	/*  Adapter is already enabled */ +	BFA_STATUS_EINVAL_TOV 	= 68,	/*  Invalid path failover TOV */ +	BFA_STATUS_EINVAL_QDEPTH = 69,	/*  Invalid queue depth value */ +	BFA_STATUS_VERSION_FAIL = 70,	/*  Application/Driver version +					 * mismatch */ +	BFA_STATUS_DIAG_BUSY    = 71,	/*  diag busy */ +	BFA_STATUS_BEACON_ON	= 72,	/*  Port Beacon already on */ +	BFA_STATUS_BEACON_OFF	= 73,	/*  Port Beacon already off */ +	BFA_STATUS_LBEACON_ON   = 74,	/*  Link End-to-End Beacon already +					 * on */ +	BFA_STATUS_LBEACON_OFF	= 75,	/*  Link End-to-End Beacon already +					 * off */ +	BFA_STATUS_PORT_NOT_INITED = 76, /*  Port not initialized */ +	BFA_STATUS_RPSC_ENABLED = 77, /*  Target has a valid speed */ +	BFA_STATUS_ENOFSAVE = 78,	/*  No saved firmware trace */ +	BFA_STATUS_BAD_FILE = 79,	/*  Not a valid Brocade Boot Code +					 * file */ +	BFA_STATUS_RLIM_EN = 80,	/*  Target rate limiting is already +					 * enabled */ +	BFA_STATUS_RLIM_DIS = 81,  /*  Target rate limiting is already +				    * disabled */ +	BFA_STATUS_IOC_DISABLED = 82,   /*  IOC is already disabled */ +	BFA_STATUS_ADAPTER_DISABLED = 83,   /*  Adapter is already disabled */ +	BFA_STATUS_BIOS_DISABLED = 84,   /*  Bios is already disabled */ +	BFA_STATUS_AUTH_ENABLED = 85,   /*  Authentication is already +					 * enabled */ +	BFA_STATUS_AUTH_DISABLED = 86,   /*  Authentication is already +					 * disabled */ +	BFA_STATUS_ERROR_TRL_ENABLED = 87,   /*  Target rate limiting is +					      * enabled */ +	BFA_STATUS_ERROR_QOS_ENABLED = 88,   /*  QoS is enabled */ +	BFA_STATUS_NO_SFP_DEV = 89, /*  No SFP device check or replace SFP */ +	BFA_STATUS_MEMTEST_FAILED = 90,	/*  Memory test failed contact +					 * support */ +	BFA_STATUS_INVALID_DEVID = 91,	/*  Invalid device id provided */ +	BFA_STATUS_QOS_ENABLED = 92, /*  QOS is already enabled */ +	BFA_STATUS_QOS_DISABLED = 93, /*  QOS is already disabled */ +	BFA_STATUS_INCORRECT_DRV_CONFIG = 94, /*  Check configuration +					       * key/value pair */ +	BFA_STATUS_REG_FAIL = 95, /*  Can't read windows registry */ +	BFA_STATUS_IM_INV_CODE = 96, /*  Invalid IOCTL code */ +	BFA_STATUS_IM_INV_VLAN = 97, /*  Invalid VLAN ID */ +	BFA_STATUS_IM_INV_ADAPT_NAME = 98, /*  Invalid adapter name */ +	BFA_STATUS_IM_LOW_RESOURCES = 99, /*  Memory allocation failure in +					   * driver */ +	BFA_STATUS_IM_VLANID_IS_PVID = 100, /*  Given VLAN id same as PVID */ +	BFA_STATUS_IM_VLANID_EXISTS = 101, /*  Given VLAN id already exists */ +	BFA_STATUS_IM_FW_UPDATE_FAIL = 102, /*  Updating firmware with new +					     * VLAN ID failed */ +	BFA_STATUS_PORTLOG_ENABLED = 103, /*  Port Log is already enabled */ +	BFA_STATUS_PORTLOG_DISABLED = 104, /*  Port Log is already disabled */ +	BFA_STATUS_FILE_NOT_FOUND = 105, /*  Specified file could not be +					  * found */ +	BFA_STATUS_QOS_FC_ONLY = 106, /*  QOS can be enabled for FC mode +				       * only */ +	BFA_STATUS_RLIM_FC_ONLY = 107, /*  RATELIM can be enabled for FC mode +					* only */ +	BFA_STATUS_CT_SPD = 108, /*  Invalid speed selection for Catapult. */ +	BFA_STATUS_LEDTEST_OP = 109, /*  LED test is operating */ +	BFA_STATUS_CEE_NOT_DN = 110, /*  eth port is not at down state, please +				      * bring down first */ +	BFA_STATUS_10G_SPD = 111, /*  Speed setting not valid for 10G HBA */ +	BFA_STATUS_IM_INV_TEAM_NAME = 112, /*  Invalid team name */ +	BFA_STATUS_IM_DUP_TEAM_NAME = 113, /*  Given team name already +					    * exists */ +	BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /*  Given adapter is part +						    * of another team */ +	BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /*  Adapter has VLANs configured. +					      * Delete all VLANs before +					      * creating team */ +	BFA_STATUS_IM_PVID_MISMATCH = 116, /*  Mismatching PVIDs configured +					    * for adapters */ +	BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /*  Mismatching link speeds +						  * configured for adapters */ +	BFA_STATUS_IM_MTU_MISMATCH = 118, /*  Mismatching MTUs configured for +					   * adapters */ +	BFA_STATUS_IM_RSS_MISMATCH = 119, /*  Mismatching RSS parameters +					   * configured for adapters */ +	BFA_STATUS_IM_HDS_MISMATCH = 120, /*  Mismatching HDS parameters +					   * configured for adapters */ +	BFA_STATUS_IM_OFFLOAD_MISMATCH = 121, /*  Mismatching offload +					       * parameters configured for +					       * adapters */ +	BFA_STATUS_IM_PORT_PARAMS = 122, /*  Error setting port parameters */ +	BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123, /*  Port is not part of team */ +	BFA_STATUS_IM_CANNOT_REM_PRI = 124, /*  Primary adapter cannot be +					     * removed. Change primary before +					     * removing */ +	BFA_STATUS_IM_MAX_PORTS_REACHED = 125, /*  Exceeding maximum ports +						* per team */ +	BFA_STATUS_IM_LAST_PORT_DELETE = 126, /*  Last port in team being +					       * deleted */ +	BFA_STATUS_IM_NO_DRIVER = 127, /*  IM driver is not installed */ +	BFA_STATUS_IM_MAX_VLANS_REACHED = 128, /*  Exceeding maximum VLANs +						* per port */ +	BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129, /* Bios speed config not +						  * allowed for CNA */ +	BFA_STATUS_NO_MINPORT_DRIVER = 130, /*  Miniport driver is not +					     * loaded */ +	BFA_STATUS_CARD_TYPE_MISMATCH = 131, /*  Card type mismatch */ +	BFA_STATUS_BAD_ASICBLK = 132, /*  Bad ASIC block */ +	BFA_STATUS_NO_DRIVER = 133, /*  Storage/Ethernet driver not loaded */ +	BFA_STATUS_INVALID_MAC = 134, /*  Invalid mac address */ +	BFA_STATUS_IM_NO_VLAN = 135, /*  No VLANs configured on the adapter */ +	BFA_STATUS_IM_ETH_LB_FAILED = 136, /*  Ethernet loopback test failed */ +	BFA_STATUS_IM_PVID_REMOVE = 137, /*  Cannot remove port vlan (PVID) */ +	BFA_STATUS_IM_PVID_EDIT = 138, /*  Cannot edit port vlan (PVID) */ +	BFA_STATUS_CNA_NO_BOOT = 139, /*  Boot upload not allowed for CNA */ +	BFA_STATUS_IM_PVID_NON_ZERO = 140, /*  Port VLAN ID (PVID) is Set to +					    * Non-Zero Value */ +	BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141, /*  Acquiring Network +						  * Subsytem Lock Failed.Please +						  * try after some time */ +	BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /*  Acquiring Network Subsytem +						 * handle Failed. Please try +						 * after some time */ +	BFA_STATUS_IM_NOT_BOUND = 143, /*  Brocade 10G Ethernet Service is not +					* Enabled on this port */ +	BFA_STATUS_INSUFFICIENT_PERMS = 144, /*  User doesn't have sufficient +					      * permissions to execute the BCU +					      * application */ +	BFA_STATUS_IM_INV_VLAN_NAME = 145, /*  Invalid/Reserved Vlan name +					    * string. The name is not allowed +					    * for the normal Vlans */ +	BFA_STATUS_CMD_NOTSUPP_CNA = 146, /*  Command not supported for CNA */ +	BFA_STATUS_IM_PASSTHRU_EDIT = 147, /*  Can not edit passthru vlan id */ +	BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation +					  * failed */ +	BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation +					    * failed */ +	BFA_STATUS_MAX_VAL		/*  Unknown error code */ +}; +#define bfa_status_t enum bfa_status + +enum bfa_eproto_status { +	BFA_EPROTO_BAD_ACCEPT = 0, +	BFA_EPROTO_UNKNOWN_RSP = 1 +}; +#define bfa_eproto_status_t enum bfa_eproto_status + +#endif /* __BFA_DEFS_STATUS_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tin.h b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h new file mode 100644 index 00000000000..e05a2db7abe --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_TIN_H__ +#define __BFA_DEFS_TIN_H__ + +#include <protocol/types.h> +#include <protocol/fc.h> + +/** + * FCS tin states + */ +enum bfa_tin_state_e { +	BFA_TIN_SM_OFFLINE = 0,		/*  tin is offline */ +	BFA_TIN_SM_WOS_LOGIN = 1,	/*  Waiting PRLI ACC/RJT from ULP */ +	BFA_TIN_SM_WFW_ONLINE = 2,	/*  Waiting ACK to PRLI ACC from FW */ +	BFA_TIN_SM_ONLINE = 3,		/*  tin login is complete */ +	BFA_TIN_SM_WIO_RELOGIN = 4,	/*  tin relogin is in progress */ +	BFA_TIN_SM_WIO_LOGOUT = 5,	/*  Processing of PRLO req from +					 *   Initiator is in progress +					 */ +	BFA_TIN_SM_WOS_LOGOUT = 6,	/*  Processing of PRLO req from +					 *   Initiator is in progress +					 */ +	BFA_TIN_SM_WIO_CLEAN = 7,	/*  Waiting for IO cleanup before tin +					 *   is offline. This can be triggered +					 *   by RPORT LOGO (rcvd/sent) or by +					 *   PRLO (rcvd/sent) +					 */ +}; + +struct bfa_prli_req_s { +	struct fchs_s fchs; +	struct fc_prli_s prli_payload; +}; + +struct bfa_prlo_req_s { +	struct fchs_s fchs; +	struct fc_prlo_s prlo_payload; +}; + +void bfa_tin_send_login_rsp(void *bfa_tin, u32 login_rsp, +				struct fc_ls_rjt_s rjt_payload); +void bfa_tin_send_logout_rsp(void *bfa_tin, u32 logout_rsp, +				struct fc_ls_rjt_s rjt_payload); +/** + * FCS target port statistics + */ +struct bfa_tin_stats_s { +	u32 onlines;	/*  ITN nexus onlines (PRLI done) */ +	u32 offlines;	/*  ITN Nexus offlines 	*/ +	u32 prli_req_parse_err;	/*  prli req parsing errors */ +	u32 prli_rsp_rjt;	/*  num prli rsp rejects sent */ +	u32 prli_rsp_acc;	/*  num prli rsp accepts sent */ +	u32 cleanup_comps;	/*  ITN cleanup completions */ +}; + +/** + * FCS tin attributes returned in queries + */ +struct bfa_tin_attr_s { +	enum bfa_tin_state_e state; +	u8	seq_retry;    /*  Sequence retry supported      */ +	u8	rsvd[3]; +}; + +/** + * BFA TIN async event data structure for BFAL + */ +enum bfa_tin_aen_event { +	BFA_TIN_AEN_ONLINE 	= 1,	/*  Target online */ +	BFA_TIN_AEN_OFFLINE 	= 2,	/*  Target offline */ +	BFA_TIN_AEN_DISCONNECT	= 3,	/*  Target disconnected */ +}; + +/** + * BFA TIN event data structure. + */ +struct bfa_tin_aen_data_s { +	u16 vf_id;	/*  vf_id of the IT nexus */ +	u16 rsvd[3]; +	wwn_t lpwwn;	/*  WWN of logical port */ +	wwn_t rpwwn;	/*  WWN of remote(target) port */ +}; + +/** + * Below APIs are needed from BFA driver + * Move these to BFA driver public header file? + */ +/*  TIN rcvd new PRLI & gets bfad_tin_t ptr from driver this callback */ +void *bfad_tin_rcvd_login_req(void *bfad_tm_port, void *bfa_tin, +				wwn_t rp_wwn, u32 rp_fcid, +				struct bfa_prli_req_s prli_req); +/*  TIN rcvd new PRLO */ +void bfad_tin_rcvd_logout_req(void *bfad_tin, wwn_t rp_wwn, u32 rp_fcid, +				struct bfa_prlo_req_s prlo_req); +/*  TIN is online and ready for IO */ +void bfad_tin_online(void *bfad_tin); +/*  TIN is offline and BFA driver can shutdown its upper stack */ +void bfad_tin_offline(void *bfad_tin); +/*  TIN does not need this BFA driver tin tag anymore, so can be freed */ +void bfad_tin_res_free(void *bfad_tin); + +#endif /* __BFA_DEFS_TIN_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h new file mode 100644 index 00000000000..31881d21851 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_TSENSOR_H__ +#define __BFA_DEFS_TSENSOR_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_types.h> + +/** + * Temperature sensor status values + */ +enum bfa_tsensor_status { +	BFA_TSENSOR_STATUS_UNKNOWN   = 1,   /*  unkown status */ +	BFA_TSENSOR_STATUS_FAULTY    = 2,   /*  sensor is faulty */ +	BFA_TSENSOR_STATUS_BELOW_MIN = 3,   /*  temperature below mininum */ +	BFA_TSENSOR_STATUS_NOMINAL   = 4,   /*  normal temperature */ +	BFA_TSENSOR_STATUS_ABOVE_MAX = 5,   /*  temperature above maximum */ +}; + +/** + * Temperature sensor attribute + */ +struct bfa_tsensor_attr_s { +	enum bfa_tsensor_status status;	/*  temperature sensor status */ +	u32        	value;	/*  current temperature in celsius */ +}; + +#endif /* __BFA_DEFS_TSENSOR_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_types.h b/drivers/scsi/bfa/include/defs/bfa_defs_types.h new file mode 100644 index 00000000000..4348332b107 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_types.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_TYPES_H__ +#define __BFA_DEFS_TYPES_H__ + +#include <bfa_os_inc.h> + +enum bfa_boolean { +	BFA_FALSE = 0, +	BFA_TRUE  = 1 +}; +#define bfa_boolean_t enum bfa_boolean + +#define BFA_STRING_32	32 + +#endif /* __BFA_DEFS_TYPES_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_version.h b/drivers/scsi/bfa/include/defs/bfa_defs_version.h new file mode 100644 index 00000000000..f8902a2c9aa --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_version.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#ifndef __BFA_DEFS_VERSION_H__ +#define __BFA_DEFS_VERSION_H__ + +#define BFA_VERSION_LEN		64 + +#endif diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vf.h b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h new file mode 100644 index 00000000000..3235be5e942 --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_VF_H__ +#define __BFA_DEFS_VF_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_port.h> +#include <protocol/types.h> + +/** + * VF states + */ +enum bfa_vf_state { +	BFA_VF_UNINIT    = 0,	/*  fabric is not yet initialized */ +	BFA_VF_LINK_DOWN = 1,	/*  link is down */ +	BFA_VF_FLOGI     = 2,	/*  flogi is in progress */ +	BFA_VF_AUTH      = 3,	/*  authentication in progress */ +	BFA_VF_NOFABRIC  = 4,	/*  fabric is not present */ +	BFA_VF_ONLINE    = 5,	/*  login to fabric is complete */ +	BFA_VF_EVFP      = 6,	/*  EVFP is in progress */ +	BFA_VF_ISOLATED  = 7,	/*  port isolated due to vf_id mismatch */ +}; + +/** + * VF statistics + */ +struct bfa_vf_stats_s { +	u32        flogi_sent;	/*  Num FLOGIs sent 		*/ +	u32        flogi_rsp_err;	/*  FLOGI response errors 	*/ +	u32        flogi_acc_err;	/*  FLOGI accept errors 	*/ +	u32        flogi_accepts;	/*  FLOGI accepts received 	*/ +	u32        flogi_rejects;	/*  FLOGI rejects received 	*/ +	u32        flogi_unknown_rsp; /*  Unknown responses for FLOGI */ +	u32        flogi_alloc_wait; /*  Allocation waits prior to +					   * sending FLOGI +					   */ +	u32        flogi_rcvd;	/*  FLOGIs received */ +	u32        flogi_rejected;	/*  Incoming FLOGIs rejected */ +	u32        fabric_onlines;	/*  Internal fabric online +					 * notification sent to other +					 * modules +					 */ +	u32        fabric_offlines; /*  Internal fabric offline +					  * notification sent to other +					  * modules +					  */ +	u32        resvd; +}; + +/** + * VF attributes returned in queries + */ +struct bfa_vf_attr_s { +	enum bfa_vf_state  state;		/*  VF state */ +	u32        rsvd; +	wwn_t           fabric_name;	/*  fabric name */ +}; + +#endif /* __BFA_DEFS_VF_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vport.h b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h new file mode 100644 index 00000000000..9f021f43b3b --- /dev/null +++ b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_DEFS_VPORT_H__ +#define __BFA_DEFS_VPORT_H__ + +#include <bfa_os_inc.h> +#include <defs/bfa_defs_port.h> +#include <protocol/types.h> + +/** + * VPORT states + */ +enum bfa_vport_state { +	BFA_FCS_VPORT_UNINIT 		= 0, +	BFA_FCS_VPORT_CREATED 		= 1, +	BFA_FCS_VPORT_OFFLINE 		= 1, +	BFA_FCS_VPORT_FDISC_SEND 	= 2, +	BFA_FCS_VPORT_FDISC 		= 3, +	BFA_FCS_VPORT_FDISC_RETRY 	= 4, +	BFA_FCS_VPORT_ONLINE 		= 5, +	BFA_FCS_VPORT_DELETING 		= 6, +	BFA_FCS_VPORT_CLEANUP 		= 6, +	BFA_FCS_VPORT_LOGO_SEND 	= 7, +	BFA_FCS_VPORT_LOGO 			= 8, +	BFA_FCS_VPORT_ERROR			= 9, +	BFA_FCS_VPORT_MAX_STATE, +}; + +/** + * vport statistics + */ +struct bfa_vport_stats_s { +	struct bfa_port_stats_s port_stats;	/*  base class (port) stats */ +	/* +	 * TODO - remove +	 */ + +	u32        fdisc_sent;	/*  num fdisc sent */ +	u32        fdisc_accepts;	/*  fdisc accepts */ +	u32        fdisc_retries;	/*  fdisc retries */ +	u32        fdisc_timeouts;	/*  fdisc timeouts */ +	u32        fdisc_rsp_err;	/*  fdisc response error */ +	u32        fdisc_acc_bad;	/*  bad fdisc accepts */ +	u32        fdisc_rejects;	/*  fdisc rejects */ +	u32        fdisc_unknown_rsp; +	/* +	 *!< fdisc rsp unknown error +	 */ +	u32        fdisc_alloc_wait;/*  fdisc req (fcxp)alloc wait */ + +	u32        logo_alloc_wait;/*  logo req (fcxp) alloc wait */ +	u32        logo_sent;	/*  logo sent */ +	u32        logo_accepts;	/*  logo accepts */ +	u32        logo_rejects;	/*  logo rejects */ +	u32        logo_rsp_err;	/*  logo rsp errors */ +	u32        logo_unknown_rsp; +			/*  logo rsp unknown errors */ + +	u32        fab_no_npiv;	/*  fabric does not support npiv */ + +	u32        fab_offline;	/*  offline events from fab SM */ +	u32        fab_online;	/*  online events from fab SM */ +	u32        fab_cleanup;	/*  cleanup request from fab SM */ +	u32        rsvd; +}; + +/** + * BFA vport attribute returned in queries + */ +struct bfa_vport_attr_s { +	struct bfa_port_attr_s   port_attr; /*  base class (port) attributes */ +	enum bfa_vport_state vport_state; /*  vport state */ +	u32          rsvd; +}; + +#endif /* __BFA_DEFS_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb.h b/drivers/scsi/bfa/include/fcb/bfa_fcb.h new file mode 100644 index 00000000000..2963b0bc30e --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcb.h BFA FCS callback interfaces + */ + +#ifndef __BFA_FCB_H__ +#define __BFA_FCB_H__ + +/** + *  fcb Main fcs callbacks + */ + +void bfa_fcb_exit(struct bfad_s *bfad); + + + +#endif /* __BFA_FCB_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h new file mode 100644 index 00000000000..a6c70aee0aa --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** +* : bfad_fcpim.h - BFA FCS initiator mode remote port callbacks + */ + +#ifndef __BFAD_FCB_FCPIM_H__ +#define __BFAD_FCB_FCPIM_H__ + +struct bfad_itnim_s; + +/* + * RPIM callbacks + */ + +/** + * 	Memory allocation for remote port instance. Called before PRLI is + * 	initiated to the remote target port. + * + * @param[in] bfad		- driver instance + * @param[out] itnim		- FCS remote port (IM) instance + * @param[out] itnim_drv	- driver remote port (IM) instance + * + * @return None + */ +void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, +				    struct bfad_itnim_s **itnim_drv); + +/** + * 		Free remote port (IM) instance. + * + * @param[in] bfad	- driver instance + * @param[in] itnim_drv	- driver remote port instance + * + * @return None + */ +void            bfa_fcb_itnim_free(struct bfad_s *bfad, +				   struct bfad_itnim_s *itnim_drv); + +/** + * 	Notification of when login with a remote target device is complete. + * + * @param[in] itnim_drv	- driver remote port instance + * + * @return None + */ +void            bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv); + +/** + * 	Notification when login with the remote device is severed. + * + * @param[in] itnim_drv	- driver remote port instance + * + * @return None + */ +void            bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv); + +void            bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim_drv); +void            bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim_drv); + +#endif /* __BFAD_FCB_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h new file mode 100644 index 00000000000..5fd7f986fa3 --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcb_port.h BFA FCS virtual port driver interfaces + */ + +#ifndef __BFA_FCB_PORT_H__ +#define __BFA_FCB_PORT_H__ + +#include <fcb/bfa_fcb_vport.h> +/** + *  fcs_port_fcb FCS port driver interfaces + */ + +/* + * Forward declarations + */ +struct bfad_port_s; + +/* + * Callback functions from BFA FCS to driver + */ + +/** + * 	Call from FCS to driver module when a port is instantiated. The port + * 	can be a base port or a virtual port with in the base fabric or + * 	a virtual fabric. + * + *  On this callback, driver is supposed to create scsi_host, scsi_tgt or + *  network interfaces bases on ports personality/roles. + * + *      base port of base fabric:	vf_drv == NULL && vp_drv == NULL + *      vport of base fabric:		vf_drv == NULL && vp_drv != NULL + *      base port of VF:		vf_drv != NULL && vp_drv == NULL + *      vport of VF:			vf_drv != NULL && vp_drv != NULL + * + * @param[in] bfad   - driver instance + * @param[in] port   - FCS port instance + * @param[in] roles  - port roles: IM, TM, IP + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) + * @param[in] vp_drv - vport driver instance, NULL if base port + * + * @return None + */ +struct bfad_port_s *bfa_fcb_port_new(struct bfad_s *bfad, +			struct bfa_fcs_port_s *port, +			enum bfa_port_role roles, struct bfad_vf_s *vf_drv, +			struct bfad_vport_s *vp_drv); + +/** + * 	Call from FCS to driver module when a port is deleted. The port + * 	can be a base port or a virtual port with in the base fabric or + * 	a virtual fabric. + * + * @param[in] bfad   - driver instance + * @param[in] roles  - port roles: IM, TM, IP + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) + * @param[in] vp_drv - vport driver instance, NULL if base port + * + * @return None + */ +void bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles, +			struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); + +/** + * 	Notification when port transitions to ONLINE state. + * + * Online notification is a logical link up for the local port. This + * notification is sent after a successfull FLOGI, or a successful + * link initialization in proviate-loop or N2N topologies. + * + * @param[in] bfad   - driver instance + * @param[in] roles  - port roles: IM, TM, IP + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) + * @param[in] vp_drv - vport driver instance, NULL if base port + * + * @return None + */ +void bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles, +			struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); + +/** + * 	Notification when port transitions to OFFLINE state. + * + * Offline notification is a logical link down for the local port. + * + * @param[in] bfad   - driver instance + * @param[in] roles  - port roles: IM, TM, IP + * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF) + * @param[in] vp_drv - vport driver instance, NULL if base port + * + * @return None + */ +void bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles, +			struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv); + + +#endif /* __BFA_FCB_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h new file mode 100644 index 00000000000..e0261bb6d1c --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcb_rport.h BFA FCS rport driver interfaces + */ + +#ifndef __BFA_FCB_RPORT_H__ +#define __BFA_FCB_RPORT_H__ + +/** + *  fcs_rport_fcb Remote port driver interfaces + */ + + +struct bfad_rport_s; + +/* + * Callback functions from BFA FCS to driver + */ + +/** + * 	Completion callback for bfa_fcs_rport_add(). + * + * @param[in] rport_drv - driver instance of rport + * + * @return None + */ +void bfa_fcb_rport_add(struct bfad_rport_s *rport_drv); + +/** + * 	Completion callback for bfa_fcs_rport_remove(). + * + * @param[in] rport_drv - driver instance of rport + * + * @return None + */ +void bfa_fcb_rport_remove(struct bfad_rport_s *rport_drv); + +/** + * 		Call to allocate a rport instance. + * + * @param[in] bfad - driver instance + * @param[out] rport - BFA FCS instance of rport + * @param[out] rport_drv - driver instance of rport + * + * @retval BFA_STATUS_OK - successfully allocated + * @retval BFA_STATUS_ENOMEM - cannot allocate + */ +bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad, +			struct bfa_fcs_rport_s **rport, +			struct bfad_rport_s **rport_drv); + +/** + * 	Call to free rport memory resources. + * + * @param[in] bfad - driver instance + * @param[in] rport_drv - driver instance of rport + * + * @return None + */ +void bfa_fcb_rport_free(struct bfad_s *bfad, struct bfad_rport_s **rport_drv); + + + +#endif /* __BFA_FCB_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h new file mode 100644 index 00000000000..cfd3fac0a4e --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcb_vf.h BFA FCS virtual fabric driver interfaces + */ + +#ifndef __BFA_FCB_VF_H__ +#define __BFA_FCB_VF_H__ + +/** + *  fcs_vf_fcb Virtual fabric driver intrefaces + */ + + +struct bfad_vf_s; + +/* + * Callback functions from BFA FCS to driver + */ + +/** + * 	Completion callback for bfa_fcs_vf_stop(). + * + * @param[in] vf_drv - driver instance of vf + * + * @return None + */ +void            bfa_fcb_vf_stop(struct bfad_vf_s *vf_drv); + + + +#endif /* __BFA_FCB_VF_H__ */ diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h new file mode 100644 index 00000000000..a39f474c2fc --- /dev/null +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcb_vport.h BFA FCS virtual port driver interfaces + */ + +#ifndef __BFA_FCB_VPORT_H__ +#define __BFA_FCB_VPORT_H__ + +/** + *  fcs_vport_fcb Virtual port driver interfaces + */ + + +struct bfad_vport_s; + +/* + * Callback functions from BFA FCS to driver + */ + +/** + * 	Completion callback for bfa_fcs_vport_delete(). + * + * @param[in] vport_drv - driver instance of vport + * + * @return None + */ +void            bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv); + + + +#endif /* __BFA_FCB_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h new file mode 100644 index 00000000000..627669c6554 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCS_H__ +#define __BFA_FCS_H__ + +#include <cs/bfa_debug.h> +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_version.h> +#include <bfa.h> +#include <fcs/bfa_fcs_fabric.h> + +#define BFA_FCS_OS_STR_LEN  		64 + +struct bfa_fcs_stats_s { +	struct { +		u32        untagged; /*  untagged receive frames */ +		u32        tagged;	/*  tagged receive frames */ +		u32        vfid_unknown;	/*  VF id is unknown */ +	} uf; +}; + +struct bfa_fcs_driver_info_s { +	u8  version[BFA_VERSION_LEN];		/*  Driver Version */ +	u8  host_machine_name[BFA_FCS_OS_STR_LEN]; +	u8  host_os_name[BFA_FCS_OS_STR_LEN]; /*  OS name and version */ +	u8  host_os_patch[BFA_FCS_OS_STR_LEN];/*  patch or service pack */ +	u8  os_device_name[BFA_FCS_OS_STR_LEN]; /*  Driver Device Name */ +}; + +struct bfa_fcs_s { +	struct bfa_s      *bfa;	/*  corresponding BFA bfa instance */ +	struct bfad_s         *bfad; /*  corresponding BDA driver instance */ +	struct bfa_log_mod_s  *logm;	/*  driver logging module instance */ +	struct bfa_trc_mod_s  *trcmod;	/*  tracing module */ +	struct bfa_aen_s      *aen;	/*  aen component */ +	bfa_boolean_t   vf_enabled;	/*  VF mode is enabled */ +	bfa_boolean_t min_cfg;		/* min cfg enabled/disabled */ +	u16        port_vfid;	/*  port default VF ID */ +	struct bfa_fcs_driver_info_s driver_info; +	struct bfa_fcs_fabric_s fabric; /*  base fabric state machine */ +	struct bfa_fcs_stats_s	stats;	/*  FCS statistics */ +	struct bfa_wc_s       	wc;	/*  waiting counter */ +}; + +/* + * bfa fcs API functions + */ +void bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, +			bfa_boolean_t min_cfg); +void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, +			struct bfa_fcs_driver_info_s *driver_info); +void bfa_fcs_exit(struct bfa_fcs_s *fcs); +void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod); +void bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod); +void bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen); +void 	  	bfa_fcs_start(struct bfa_fcs_s *fcs); + +#endif /* __BFA_FCS_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h new file mode 100644 index 00000000000..28c4c9ff08b --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCS_AUTH_H__ +#define __BFA_FCS_AUTH_H__ + +struct bfa_fcs_s; + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_auth.h> +#include <defs/bfa_defs_vf.h> +#include <cs/bfa_q.h> +#include <cs/bfa_sm.h> +#include <defs/bfa_defs_pport.h> +#include <fcs/bfa_fcs_lport.h> +#include <protocol/fc_sp.h> + +struct bfa_fcs_fabric_s; + + + +struct bfa_fcs_auth_s { +	bfa_sm_t	sm;	/*  state machine */ +	bfa_boolean_t   policy;	/*  authentication enabled/disabled */ +	enum bfa_auth_status status;	/*  authentication status */ +	enum auth_rjt_codes  rjt_code;	/*  auth reject status */ +	enum auth_rjt_code_exps  rjt_code_exp;	/*  auth reject reason */ +	enum bfa_auth_algo algo;	/*  Authentication algorithm */ +	struct bfa_auth_stats_s stats;	/*  Statistics */ +	enum auth_dh_gid   group;	/*  DH(diffie-hellman) Group */ +	enum bfa_auth_secretsource source;	/*  Secret source */ +	char            secret[BFA_AUTH_SECRET_STRING_LEN]; +				/*  secret string */ +	u8         secret_len; +				/*  secret string length */ +	u8         nretries; +				/*  number of retries */ +	struct bfa_fcs_fabric_s *fabric;/*  pointer to fabric */ +	u8         sentcode;	/*  pointer to response data */ +	u8        *response;	/*  pointer to response data */ +	struct bfa_timer_s delay_timer; 	/*  delay timer */ +	struct bfa_fcxp_s *fcxp;		/*  pointer to fcxp */ +	struct bfa_fcxp_wqe_s fcxp_wqe; +}; + +/** + * bfa fcs authentication public functions + */ +bfa_status_t    bfa_fcs_auth_get_attr(struct bfa_fcs_s *port, +				      struct bfa_auth_attr_s *attr); +bfa_status_t    bfa_fcs_auth_set_policy(struct bfa_fcs_s *port, +					bfa_boolean_t policy); +enum bfa_auth_status bfa_fcs_auth_get_status(struct bfa_fcs_s *port); +bfa_status_t    bfa_fcs_auth_set_algo(struct bfa_fcs_s *port, +				      enum bfa_auth_algo algo); +bfa_status_t    bfa_fcs_auth_get_stats(struct bfa_fcs_s *port, +				       struct bfa_auth_stats_s *stats); +bfa_status_t    bfa_fcs_auth_set_dh_group(struct bfa_fcs_s *port, int group); +bfa_status_t    bfa_fcs_auth_set_secretstring(struct bfa_fcs_s *port, +					      char *secret); +bfa_status_t    bfa_fcs_auth_set_secretstring_encrypt(struct bfa_fcs_s *port, +					      u32 secret[], u32 len); +bfa_status_t    bfa_fcs_auth_set_secretsource(struct bfa_fcs_s *port, +					      enum bfa_auth_secretsource src); +bfa_status_t    bfa_fcs_auth_reset_stats(struct bfa_fcs_s *port); +bfa_status_t    bfa_fcs_auth_reinit(struct bfa_fcs_s *port); + +#endif /* __BFA_FCS_AUTH_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h new file mode 100644 index 00000000000..4ffd2242d3d --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCS_FABRIC_H__ +#define __BFA_FCS_FABRIC_H__ + +struct bfa_fcs_s; + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_vf.h> +#include <cs/bfa_q.h> +#include <cs/bfa_sm.h> +#include <defs/bfa_defs_pport.h> +#include <fcs/bfa_fcs_lport.h> +#include <protocol/fc_sp.h> +#include <fcs/bfa_fcs_auth.h> + +/* + * forward declaration + */ +struct bfad_vf_s; + +enum bfa_fcs_fabric_type { +	BFA_FCS_FABRIC_UNKNOWN = 0, +	BFA_FCS_FABRIC_SWITCHED = 1, +	BFA_FCS_FABRIC_PLOOP = 2, +	BFA_FCS_FABRIC_N2N = 3, +}; + + +struct bfa_fcs_fabric_s { +	struct list_head   qe;		/*  queue element */ +	bfa_sm_t	 sm;		/*  state machine */ +	struct bfa_fcs_s *fcs;		/*  FCS instance */ +	struct bfa_fcs_port_s  bport;	/*  base logical port */ +	enum bfa_fcs_fabric_type fab_type; /*  fabric type */ +	enum bfa_pport_type oper_type;	/*  current link topology */ +	u8         is_vf;		/*  is virtual fabric? */ +	u8         is_npiv;	/*  is NPIV supported ? */ +	u8         is_auth;	/*  is Security/Auth supported ? */ +	u16        bb_credit;	/*  BB credit from fabric */ +	u16        vf_id;		/*  virtual fabric ID */ +	u16        num_vports;	/*  num vports */ +	u16        rsvd; +	struct list_head         vport_q;	/*  queue of virtual ports */ +	struct list_head         vf_q;	/*  queue of virtual fabrics */ +	struct bfad_vf_s      *vf_drv;	/*  driver vf structure */ +	struct bfa_timer_s link_timer;	/*  Link Failure timer. Vport */ +	wwn_t           fabric_name;	/*  attached fabric name */ +	bfa_boolean_t   auth_reqd;	/*  authentication required	*/ +	struct bfa_timer_s delay_timer;	/*  delay timer		*/ +	union { +		u16        swp_vfid;/*  switch port VF id		*/ +	} event_arg; +	struct bfa_fcs_auth_s  auth;	/*  authentication config	*/ +	struct bfa_wc_s        wc;	/*  wait counter for delete	*/ +	struct bfa_vf_stats_s  stats; 	/*  fabric/vf stats		*/ +	struct bfa_lps_s	*lps;	/*  lport login services	*/ +	u8	fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ];  /*  attached +							    * fabric's ip addr +							    */ +}; + +#define bfa_fcs_fabric_npiv_capable(__f)    (__f)->is_npiv +#define bfa_fcs_fabric_is_switched(__f)			\ +	((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED) + +/** + *   The design calls for a single implementation of base fabric and vf. + */ +#define bfa_fcs_vf_t struct bfa_fcs_fabric_s + +struct bfa_vf_event_s { +	u32        undefined; +}; + +/** + * bfa fcs vf public functions + */ +bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id); +bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs); +bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, +			       u16 vf_id, struct bfa_port_cfg_s *port_cfg, +			       struct bfad_vf_s *vf_drv); +bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf); +void bfa_fcs_vf_start(bfa_fcs_vf_t *vf); +bfa_status_t bfa_fcs_vf_stop(bfa_fcs_vf_t *vf); +void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); +void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs); +void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr); +void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, +			  struct bfa_vf_stats_s *vf_stats); +void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf); +void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); +bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); +struct bfad_vf_s *bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf); + +#endif /* __BFA_FCS_FABRIC_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h new file mode 100644 index 00000000000..e719f2c3eb3 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_fcpim.h BFA FCS FCP Initiator Mode interfaces/defines. + */ + +#ifndef __BFA_FCS_FCPIM_H__ +#define __BFA_FCS_FCPIM_H__ + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_itnim.h> +#include <fcs/bfa_fcs.h> +#include <fcs/bfa_fcs_rport.h> +#include <fcs/bfa_fcs_lport.h> +#include <bfa_fcpim.h> + +/* + * forward declarations + */ +struct bfad_itnim_s; + +struct bfa_fcs_itnim_s { +	bfa_sm_t		sm;		/*  state machine */ +	struct bfa_fcs_rport_s 	*rport;		/*  parent remote rport  */ +	struct bfad_itnim_s   	*itnim_drv;	/*  driver peer instance */ +	struct bfa_fcs_s      	*fcs;		/*  fcs instance         */ +	struct bfa_timer_s 	timer;		/*  timer functions      */ +	struct bfa_itnim_s 	*bfa_itnim;	/*  BFA itnim struct     */ +	bfa_boolean_t	 	seq_rec;	/*  seq recovery support */ +	bfa_boolean_t	 	rec_support;	/*  REC supported        */ +	bfa_boolean_t	 	conf_comp;	/*  FCP_CONF     support */ +	bfa_boolean_t	 	task_retry_id;	/*  task retry id supp   */ +	struct bfa_fcxp_wqe_s 	fcxp_wqe;	/*  wait qelem for fcxp  */ +	struct bfa_fcxp_s *fcxp;		/*  FCXP in use          */ +	struct bfa_itnim_stats_s 	stats;	/*  itn statistics       */ +}; + + +static inline struct bfad_port_s * +bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->port->bfad_port; +} + + +static inline struct bfa_fcs_port_s * +bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->port; +} + + +static inline wwn_t +bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->nwwn; +} + + +static inline wwn_t +bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->pwwn; +} + + +static inline u32 +bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->pid; +} + + +static inline   u32 +bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->maxfrsize; +} + + +static inline   enum fc_cos +bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->rport->fc_cos; +} + + +static inline struct bfad_itnim_s * +bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->itnim_drv; +} + + +static inline struct bfa_itnim_s * +bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim) +{ +	return itnim->bfa_itnim; +} + +/** + * bfa fcs FCP Initiator mode API functions + */ +void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim, +			struct bfa_itnim_attr_s *attr); +void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim, +			struct bfa_itnim_stats_s *stats); +struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, +			wwn_t rpwwn); +bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +			struct bfa_itnim_attr_s *attr); +bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, +			struct bfa_itnim_stats_s *stats); +bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, +			wwn_t rpwwn); +#endif /* __BFA_FCS_FCPIM_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h new file mode 100644 index 00000000000..4441fffc9c8 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_fdmi.h BFA fcs fdmi module public interface + */ + +#ifndef __BFA_FCS_FDMI_H__ +#define __BFA_FCS_FDMI_H__ +#include <bfa_os_inc.h> +#include <protocol/fdmi.h> + +#define	BFA_FCS_FDMI_SUPORTED_SPEEDS  (FDMI_TRANS_SPEED_1G  | \ +					FDMI_TRANS_SPEED_2G | \ +					FDMI_TRANS_SPEED_4G | \ +					FDMI_TRANS_SPEED_8G) + +/* +* HBA Attribute Block : BFA internal representation. Note : Some variable +* sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based + * on this the size has been reduced to 16 bytes from the standard's 64 bytes. + */ +struct bfa_fcs_fdmi_hba_attr_s { +	wwn_t           node_name; +	u8         manufacturer[64]; +	u8         serial_num[64]; +	u8         model[16]; +	u8         model_desc[256]; +	u8         hw_version[8]; +	u8         driver_version[8]; +	u8         option_rom_ver[BFA_VERSION_LEN]; +	u8         fw_version[8]; +	u8         os_name[256]; +	u32        max_ct_pyld; +}; + +/* + * Port Attribute Block + */ +struct bfa_fcs_fdmi_port_attr_s { +	u8         supp_fc4_types[32];	/* supported FC4 types */ +	u32        supp_speed;	/* supported speed */ +	u32        curr_speed;	/* current Speed */ +	u32        max_frm_size;	/* max frame size */ +	u8         os_device_name[256];	/* OS device Name */ +	u8         host_name[256];	/* host name */ +}; + +#endif /* __BFA_FCS_FDMI_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h new file mode 100644 index 00000000000..b85cba884b9 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_port.h BFA fcs port module public interface + */ + +#ifndef __BFA_FCS_PORT_H__ +#define __BFA_FCS_PORT_H__ + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_pport.h> +#include <defs/bfa_defs_rport.h> +#include <cs/bfa_q.h> +#include <bfa_svc.h> +#include <cs/bfa_wc.h> + +struct bfa_fcs_s; +struct bfa_fcs_fabric_s; + +/* +* @todo : need to move to a global config file. + * Maximum Vports supported per physical port or vf. + */ +#define BFA_FCS_MAX_VPORTS_SUPP_CB  255 +#define BFA_FCS_MAX_VPORTS_SUPP_CT  191 + +/* +* @todo : need to move to a global config file. + * Maximum Rports supported per port (physical/logical). + */ +#define BFA_FCS_MAX_RPORTS_SUPP  256	/* @todo : tentative value */ + + +struct bfa_fcs_port_ns_s { +	bfa_sm_t        sm;		/*  state machine */ +	struct bfa_timer_s timer; +	struct bfa_fcs_port_s *port;	/*  parent port */ +	struct bfa_fcxp_s *fcxp; +	struct bfa_fcxp_wqe_s fcxp_wqe; +}; + + +struct bfa_fcs_port_scn_s { +	bfa_sm_t        sm;		/*  state machine */ +	struct bfa_timer_s timer; +	struct bfa_fcs_port_s *port;	/*  parent port */ +	struct bfa_fcxp_s *fcxp; +	struct bfa_fcxp_wqe_s fcxp_wqe; +}; + + +struct bfa_fcs_port_fdmi_s { +	bfa_sm_t        sm;		/*  state machine */ +	struct bfa_timer_s timer; +	struct bfa_fcs_port_ms_s *ms;	/*  parent ms */ +	struct bfa_fcxp_s *fcxp; +	struct bfa_fcxp_wqe_s fcxp_wqe; +	u8         retry_cnt;	/*  retry count */ +	u8	 	   rsvd[3]; +}; + + +struct bfa_fcs_port_ms_s { +	bfa_sm_t        sm;		/*  state machine */ +	struct bfa_timer_s timer; +	struct bfa_fcs_port_s *port;	/*  parent port */ +	struct bfa_fcxp_s *fcxp; +	struct bfa_fcxp_wqe_s fcxp_wqe; +	struct bfa_fcs_port_fdmi_s fdmi;	/*  FDMI component of MS */ +	u8         retry_cnt;	/*  retry count */ +	u8	 	   rsvd[3]; +}; + + +struct bfa_fcs_port_fab_s { +	struct bfa_fcs_port_ns_s ns;	/*  NS component of port */ +	struct bfa_fcs_port_scn_s scn;	/*  scn component of port */ +	struct bfa_fcs_port_ms_s ms;	/*  MS component of port */ +}; + + + +#define 	MAX_ALPA_COUNT 		127 + +struct bfa_fcs_port_loop_s { +	u8         num_alpa;	/*  Num of ALPA entries in the map */ +	u8         alpa_pos_map[MAX_ALPA_COUNT];	/*  ALPA Positional +							 *Map */ +	struct bfa_fcs_port_s *port;	/*  parent port */ +}; + + + +struct bfa_fcs_port_n2n_s { +	u32        rsvd; +	u16        reply_oxid;	/*  ox_id from the req flogi to be +					 *used in flogi acc */ +	wwn_t           rem_port_wwn;	/*  Attached port's wwn */ +}; + + +union bfa_fcs_port_topo_u { +	struct bfa_fcs_port_fab_s pfab; +	struct bfa_fcs_port_loop_s ploop; +	struct bfa_fcs_port_n2n_s pn2n; +}; + + +struct bfa_fcs_port_s { +	struct list_head         qe;	/*  used by port/vport */ +	bfa_sm_t               sm;	/*  state machine */ +	struct bfa_fcs_fabric_s *fabric;	/*  parent fabric */ +	struct bfa_port_cfg_s  port_cfg;	/*  port configuration */ +	struct bfa_timer_s link_timer;	/*  timer for link offline */ +	u32        pid : 24;	/*  FC address */ +	u8         lp_tag;		/*  lport tag */ +	u16        num_rports;	/*  Num of r-ports */ +	struct list_head rport_q;	/*  queue of discovered r-ports */ +	struct bfa_fcs_s *fcs;	/*  FCS instance */ +	union bfa_fcs_port_topo_u port_topo;	/*  fabric/loop/n2n details */ +	struct bfad_port_s *bfad_port;	/*  driver peer instance */ +	struct bfa_fcs_vport_s *vport;	/*  NULL for base ports */ +	struct bfa_fcxp_s *fcxp; +	struct bfa_fcxp_wqe_s fcxp_wqe; +	struct bfa_port_stats_s stats; +	struct bfa_wc_s        wc;	/*  waiting counter for events */ +}; + +#define bfa_fcs_lport_t struct bfa_fcs_port_s + +/** + * Symbolic Name related defines + *  Total bytes 255. + *  Physical Port's symbolic name 128 bytes. + *  For Vports, Vport's symbolic name is appended to the Physical port's + *  Symbolic Name. + * + *  Physical Port's symbolic name Format : (Total 128 bytes) + *  Adapter Model number/name : 12 bytes + *  Driver Version     : 10 bytes + *  Host Machine Name  : 30 bytes + * 	Host OS Info	   : 48 bytes + * 	Host OS PATCH Info : 16 bytes + *  ( remaining 12 bytes reserved to be used for separator) + */ +#define BFA_FCS_PORT_SYMBNAME_SEPARATOR 		" | " + +#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ			12 +#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 		10 +#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 	30 +#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ			48 +#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ		16 + +/** + * Get FC port ID for a logical port. + */ +#define bfa_fcs_port_get_fcid(_lport)	((_lport)->pid) +#define bfa_fcs_port_get_pwwn(_lport)	((_lport)->port_cfg.pwwn) +#define bfa_fcs_port_get_nwwn(_lport)	((_lport)->port_cfg.nwwn) +#define bfa_fcs_port_get_psym_name(_lport)	((_lport)->port_cfg.sym_name) +#define bfa_fcs_port_is_initiator(_lport)	\ +			((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_IM) +#define bfa_fcs_port_is_target(_lport)	\ +			((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_TM) +#define bfa_fcs_port_get_nrports(_lport)	\ +			((_lport) ? (_lport)->num_rports : 0) + +static inline struct bfad_port_s * +bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port) +{ +	return port->bfad_port; +} + + +#define bfa_fcs_port_get_opertype(_lport)	(_lport)->fabric->oper_type + + +#define bfa_fcs_port_get_fabric_name(_lport)	(_lport)->fabric->fabric_name + + +#define bfa_fcs_port_get_fabric_ipaddr(_lport)	(_lport)->fabric->fabric_ip_addr + +/** + * bfa fcs port public functions + */ +void bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, +			struct bfa_port_cfg_s *port_cfg); +struct bfa_fcs_port_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs); +void bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, +			wwn_t rport_wwns[], int *nrports); + +wwn_t bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, +			int index, int nrports, bfa_boolean_t bwwn); + +struct bfa_fcs_port_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, +			u16 vf_id, wwn_t lpwwn); + +void bfa_fcs_port_get_info(struct bfa_fcs_port_s *port, +			struct bfa_port_info_s *port_info); +void bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port, +			struct bfa_port_attr_s *port_attr); +void bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port, +			struct bfa_port_stats_s *port_stats); +void bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port); +enum bfa_pport_speed bfa_fcs_port_get_rport_max_speed( +			struct bfa_fcs_port_s *port); +void bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port); +void bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port); + +#endif /* __BFA_FCS_PORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h new file mode 100644 index 00000000000..702b95b76c2 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __BFA_FCS_RPORT_H__ +#define __BFA_FCS_RPORT_H__ + +#include <defs/bfa_defs_status.h> +#include <cs/bfa_q.h> +#include <fcs/bfa_fcs.h> +#include <defs/bfa_defs_rport.h> + +#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 	90 	/* in secs */ +/* + * forward declarations + */ +struct bfad_rport_s; + +struct bfa_fcs_itnim_s; +struct bfa_fcs_tin_s; +struct bfa_fcs_iprp_s; + +/* Rport Features (RPF) */ +struct bfa_fcs_rpf_s { +	bfa_sm_t               sm;	/*  state machine */ +	struct bfa_fcs_rport_s *rport;	/*  parent rport */ +	struct bfa_timer_s 	timer;	/*  general purpose timer */ +	struct bfa_fcxp_s 	*fcxp;	/*  FCXP needed for discarding */ +	struct bfa_fcxp_wqe_s 	fcxp_wqe;	/*  fcxp wait queue element */ +	int             	rpsc_retries;	/*  max RPSC retry attempts */ +	enum bfa_pport_speed 	rpsc_speed;	/* Current Speed from RPSC. +						 * O if RPSC fails */ +	enum bfa_pport_speed	assigned_speed;	/* Speed assigned by the user. +						 * will be used if RPSC is not +						 * supported by the rport */ +}; + +struct bfa_fcs_rport_s { +	struct list_head         qe;	/*  used by port/vport */ +	struct bfa_fcs_port_s *port;	/*  parent FCS port */ +	struct bfa_fcs_s      *fcs;	/*  fcs instance */ +	struct bfad_rport_s   *rp_drv;	/*  driver peer instance */ +	u32        pid;	/*  port ID of rport */ +	u16        maxfrsize;	/*  maximum frame size */ +	u16        reply_oxid;	/*  OX_ID of inbound requests */ +	enum fc_cos        fc_cos;	/*  FC classes of service supp */ +	bfa_boolean_t   cisc;	/*  CISC capable device */ +	wwn_t           pwwn;	/*  port wwn of rport */ +	wwn_t           nwwn;	/*  node wwn of rport */ +	struct bfa_rport_symname_s psym_name; /*  port symbolic name  */ +	bfa_sm_t        sm;		/*  state machine */ +	struct bfa_timer_s timer;	/*  general purpose timer */ +	struct bfa_fcs_itnim_s *itnim;	/*  ITN initiator mode role */ +	struct bfa_fcs_tin_s *tin;	/*  ITN initiator mode role */ +	struct bfa_fcs_iprp_s *iprp;	/*  IP/FC role */ +	struct bfa_rport_s *bfa_rport;	/*  BFA Rport */ +	struct bfa_fcxp_s *fcxp;	/*  FCXP needed for discarding */ +	int             plogi_retries;	/*  max plogi retry attempts */ +	int             ns_retries;	/*  max NS query retry attempts */ +	struct bfa_fcxp_wqe_s 	fcxp_wqe; /*  fcxp wait queue element */ +	struct bfa_rport_stats_s stats;	/*  rport stats */ +	enum bfa_rport_function	scsi_function;  /*  Initiator/Target */ +	struct bfa_fcs_rpf_s rpf; 	/* Rport features module */ +}; + +static inline struct bfa_rport_s * +bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) +{ +	return rport->bfa_rport; +} + +/** + * bfa fcs rport API functions + */ +bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn, +			struct bfa_fcs_rport_s *rport, +			struct bfad_rport_s *rport_drv); +bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, +			struct bfa_rport_attr_s *attr); +void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, +			struct bfa_rport_stats_s *stats); +void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport); +struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, +			wwn_t rpwwn); +struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( +			struct bfa_fcs_port_s *port, wwn_t rnwwn); +void bfa_fcs_rport_set_del_timeout(u8 rport_tmo); +void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, +			enum bfa_pport_speed speed); +#endif /* __BFA_FCS_RPORT_H__ */ diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h new file mode 100644 index 00000000000..cd33f2cd5c3 --- /dev/null +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_vport.h BFA fcs vport module public interface + */ + +#ifndef __BFA_FCS_VPORT_H__ +#define __BFA_FCS_VPORT_H__ + +#include <defs/bfa_defs_status.h> +#include <defs/bfa_defs_port.h> +#include <defs/bfa_defs_vport.h> +#include <fcs/bfa_fcs.h> +#include <fcb/bfa_fcb_vport.h> + +struct bfa_fcs_vport_s { +	struct list_head		qe;		/*  queue elem	 */ +	bfa_sm_t		sm;		/*  state machine	*/ +	bfa_fcs_lport_t		lport;		/*  logical port	*/ +	struct bfa_timer_s	timer;		/*  general purpose timer */ +	struct bfad_vport_s	*vport_drv;	/*  Driver private	*/ +	struct bfa_vport_stats_s vport_stats;	/*  vport statistics	*/ +	struct bfa_lps_s	*lps;		/*  Lport login service */ +	int			fdisc_retries; +}; + +#define bfa_fcs_vport_get_port(vport) \ +			((struct bfa_fcs_port_s  *)(&vport->port)) + +/** + * bfa fcs vport public functions + */ +bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, +			struct bfa_fcs_s *fcs, u16 vf_id, +			struct bfa_port_cfg_s *port_cfg, +			struct bfad_vport_s *vport_drv); +bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport); +bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport); +bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, +			struct bfa_vport_attr_s *vport_attr); +void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, +			struct bfa_vport_stats_s *vport_stats); +void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport); +struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, +			u16 vf_id, wwn_t vpwwn); + +#endif /* __BFA_FCS_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/log/bfa_log_fcs.h b/drivers/scsi/bfa/include/log/bfa_log_fcs.h new file mode 100644 index 00000000000..b6f5df8827f --- /dev/null +++ b/drivers/scsi/bfa/include/log/bfa_log_fcs.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* + * messages define for FCS Module + */ +#ifndef	__BFA_LOG_FCS_H__ +#define	__BFA_LOG_FCS_H__ +#include  <cs/bfa_log.h> +#define BFA_LOG_FCS_FABRIC_NOSWITCH 	\ +	(((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 1) +#define BFA_LOG_FCS_FABRIC_ISOLATED 	\ +	(((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 2) +#endif diff --git a/drivers/scsi/bfa/include/log/bfa_log_hal.h b/drivers/scsi/bfa/include/log/bfa_log_hal.h new file mode 100644 index 00000000000..0412aea2ec3 --- /dev/null +++ b/drivers/scsi/bfa/include/log/bfa_log_hal.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for HAL Module */ +#ifndef	__BFA_LOG_HAL_H__ +#define	__BFA_LOG_HAL_H__ +#include  <cs/bfa_log.h> +#define BFA_LOG_HAL_ASSERT \ +	(((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 1) +#define BFA_LOG_HAL_HEARTBEAT_FAILURE \ +	(((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 2) +#define BFA_LOG_HAL_FCPIM_PARM_INVALID \ +	(((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 3) +#define BFA_LOG_HAL_SM_ASSERT \ +	(((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 4) +#endif diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h new file mode 100644 index 00000000000..317c0547ee1 --- /dev/null +++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* messages define for LINUX Module */ +#ifndef	__BFA_LOG_LINUX_H__ +#define	__BFA_LOG_LINUX_H__ +#include  <cs/bfa_log.h> +#define BFA_LOG_LINUX_DEVICE_CLAIMED \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 1) +#define BFA_LOG_LINUX_HASH_INIT_FAILED \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 2) +#define BFA_LOG_LINUX_SYSFS_FAILED \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 3) +#define BFA_LOG_LINUX_MEM_ALLOC_FAILED \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 4) +#define BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 5) +#define BFA_LOG_LINUX_ITNIM_FREE \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 6) +#define BFA_LOG_LINUX_ITNIM_ONLINE \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 7) +#define BFA_LOG_LINUX_ITNIM_OFFLINE \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 8) +#define BFA_LOG_LINUX_SCSI_HOST_FREE \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 9) +#define BFA_LOG_LINUX_SCSI_ABORT \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 10) +#define BFA_LOG_LINUX_SCSI_ABORT_COMP \ +		(((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 11) +#endif diff --git a/drivers/scsi/bfa/include/log/bfa_log_wdrv.h b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h new file mode 100644 index 00000000000..809a95f7afe --- /dev/null +++ b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/* + * messages define for WDRV Module + */ +#ifndef	__BFA_LOG_WDRV_H__ +#define	__BFA_LOG_WDRV_H__ +#include  <cs/bfa_log.h> +#define BFA_LOG_WDRV_IOC_INIT_ERROR 	\ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 1) +#define BFA_LOG_WDRV_IOC_INTERNAL_ERROR \ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 2) +#define BFA_LOG_WDRV_IOC_START_ERROR 	\ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 3) +#define BFA_LOG_WDRV_IOC_STOP_ERROR 	\ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 4) +#define BFA_LOG_WDRV_INSUFFICIENT_RESOURCES \ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 5) +#define BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR \ +	(((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 6) +#endif diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h new file mode 100644 index 00000000000..c59d6630b07 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/ct.h @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __CT_H__ +#define __CT_H__ + +#include <protocol/types.h> + +#pragma pack(1) + +struct ct_hdr_s{ +	u32	rev_id:8;	/* Revision of the CT */ +	u32	in_id:24;	/* Initiator Id */ +	u32	gs_type:8;	/* Generic service Type */ +	u32	gs_sub_type:8;	/* Generic service sub type */ +	u32	options:8;	/* options */ +	u32	rsvrd:8;	/* reserved */ +	u32	cmd_rsp_code:16;/* ct command/response code */ +	u32	max_res_size:16;/* maximum/residual size */ +	u32	frag_id:8;	/* fragment ID */ +	u32	reason_code:8;	/* reason code */ +	u32	exp_code:8;	/* explanation code */ +	u32	vendor_unq:8;	/* vendor unique */ +}; + +/* + * defines for the Revision + */ +enum { +	CT_GS3_REVISION = 0x01, +}; + +/* + * defines for gs_type + */ +enum { +	CT_GSTYPE_KEYSERVICE	= 0xF7, +	CT_GSTYPE_ALIASSERVICE	= 0xF8, +	CT_GSTYPE_MGMTSERVICE	= 0xFA, +	CT_GSTYPE_TIMESERVICE	= 0xFB, +	CT_GSTYPE_DIRSERVICE	= 0xFC, +}; + +/* + * defines for gs_sub_type for gs type directory service + */ +enum { +	CT_GSSUBTYPE_NAMESERVER = 0x02, +}; + +/* + * defines for gs_sub_type for gs type management service + */ +enum { +	CT_GSSUBTYPE_CFGSERVER	= 0x01, +	CT_GSSUBTYPE_UNZONED_NS = 0x02, +	CT_GSSUBTYPE_ZONESERVER = 0x03, +	CT_GSSUBTYPE_LOCKSERVER = 0x04, +	CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10,	/* for FDMI */ +}; + +/* + * defines for CT response code field + */ +enum { +	CT_RSP_REJECT = 0x8001, +	CT_RSP_ACCEPT = 0x8002, +}; + +/* + * defintions for CT reason code + */ +enum { +	CT_RSN_INV_CMD		= 0x01, +	CT_RSN_INV_VER		= 0x02, +	CT_RSN_LOGIC_ERR	= 0x03, +	CT_RSN_INV_SIZE		= 0x04, +	CT_RSN_LOGICAL_BUSY	= 0x05, +	CT_RSN_PROTO_ERR	= 0x07, +	CT_RSN_UNABLE_TO_PERF	= 0x09, +	CT_RSN_NOT_SUPP			= 0x0B, +	CT_RSN_SERVER_NOT_AVBL  = 0x0D, +	CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E, +	CT_RSN_VENDOR_SPECIFIC  = 0xFF, + +}; + +/* + * definitions for explanations code for Name server + */ +enum { +	CT_NS_EXP_NOADDITIONAL	= 0x00, +	CT_NS_EXP_ID_NOT_REG	= 0x01, +	CT_NS_EXP_PN_NOT_REG	= 0x02, +	CT_NS_EXP_NN_NOT_REG	= 0x03, +	CT_NS_EXP_CS_NOT_REG	= 0x04, +	CT_NS_EXP_IPN_NOT_REG	= 0x05, +	CT_NS_EXP_IPA_NOT_REG	= 0x06, +	CT_NS_EXP_FT_NOT_REG	= 0x07, +	CT_NS_EXP_SPN_NOT_REG	= 0x08, +	CT_NS_EXP_SNN_NOT_REG	= 0x09, +	CT_NS_EXP_PT_NOT_REG	= 0x0A, +	CT_NS_EXP_IPP_NOT_REG	= 0x0B, +	CT_NS_EXP_FPN_NOT_REG	= 0x0C, +	CT_NS_EXP_HA_NOT_REG	= 0x0D, +	CT_NS_EXP_FD_NOT_REG	= 0x0E, +	CT_NS_EXP_FF_NOT_REG	= 0x0F, +	CT_NS_EXP_ACCESSDENIED	= 0x10, +	CT_NS_EXP_UNACCEPTABLE_ID = 0x11, +	CT_NS_EXP_DATABASEEMPTY			= 0x12, +	CT_NS_EXP_NOT_REG_IN_SCOPE 		= 0x13, +	CT_NS_EXP_DOM_ID_NOT_PRESENT 	= 0x14, +	CT_NS_EXP_PORT_NUM_NOT_PRESENT  = 0x15, +	CT_NS_EXP_NO_DEVICE_ATTACHED 	= 0x16 +}; + +/* + * defintions for the explanation code for all servers + */ +enum { +	CT_EXP_AUTH_EXCEPTION			= 0xF1, +	CT_EXP_DB_FULL					= 0xF2, +	CT_EXP_DB_EMPTY					= 0xF3, +	CT_EXP_PROCESSING_REQ			= 0xF4, +	CT_EXP_UNABLE_TO_VERIFY_CONN	= 0xF5, +	CT_EXP_DEVICES_NOT_IN_CMN_ZONE  = 0xF6 +}; + +/* + * Command codes for Name server + */ +enum { +	GS_GID_PN	= 0x0121,	/* Get Id on port name */ +	GS_GPN_ID	= 0x0112,	/* Get port name on ID */ +	GS_GNN_ID	= 0x0113,	/* Get node name on ID */ +	GS_GID_FT	= 0x0171,	/* Get Id on FC4 type */ +	GS_GSPN_ID	= 0x0118,	/* Get symbolic PN on ID */ +	GS_RFT_ID	= 0x0217,	/* Register fc4type on ID */ +	GS_RSPN_ID	= 0x0218,	/* Register symbolic PN on ID */ +	GS_RPN_ID	= 0x0212,	/* Register port name */ +	GS_RNN_ID	= 0x0213,	/* Register node name */ +	GS_RCS_ID	= 0x0214,	/* Register class of service */ +	GS_RPT_ID	= 0x021A,	/* Register port type */ +	GS_GA_NXT	= 0x0100,	/* Get all next */ +	GS_RFF_ID	= 0x021F,	/* Register FC4 Feature		*/ +}; + +struct fcgs_id_req_s{ +	u32	rsvd:8; +	u32	dap:24;	/* port identifier */ +}; +#define fcgs_gpnid_req_t struct fcgs_id_req_s +#define fcgs_gnnid_req_t struct fcgs_id_req_s +#define fcgs_gspnid_req_t struct fcgs_id_req_s + +struct fcgs_gidpn_req_s{ +	wwn_t	port_name;	/* port wwn */ +}; + +struct fcgs_gidpn_resp_s{ +	u32	rsvd:8; +	u32	dap:24;	/* port identifier */ +}; + +/** + * RFT_ID + */ +struct fcgs_rftid_req_s { +	u32	rsvd:8; +	u32	dap:24;		/* port identifier */ +	u32	fc4_type[8];	/* fc4 types */ +}; + +/** + * RFF_ID : Register FC4 features. + */ + +#define FC_GS_FCP_FC4_FEATURE_INITIATOR  0x02 +#define FC_GS_FCP_FC4_FEATURE_TARGET	 0x01 + +struct fcgs_rffid_req_s{ +    u32    rsvd          :8; +    u32    dap        	  :24;		/* port identifier	*/ +    u32    rsvd1         :16; +    u32    fc4ftr_bits   :8;		/* fc4 feature bits	*/ +    u32    fc4_type      :8;		/* corresponding FC4 Type */ +}; + +/** + * GID_FT Request + */ +struct fcgs_gidft_req_s{ +	u8	reserved; +	u8	domain_id;	/* domain, 0 - all fabric */ +	u8	area_id;	/* area, 0 - whole domain */ +	u8	fc4_type;	/* FC_TYPE_FCP for SCSI devices */ +};				/* GID_FT Request */ + +/** + * GID_FT Response + */ +struct fcgs_gidft_resp_s { +	u8		last:1;	/* last port identifier flag */ +	u8		reserved:7; +	u32	pid:24;	/* port identifier */ +};				/* GID_FT Response */ + +/** + * RSPN_ID + */ +struct fcgs_rspnid_req_s{ +	u32	rsvd:8; +	u32	dap:24;		/* port identifier */ +	u8		spn_len;	/* symbolic port name length */ +	u8		spn[256];	/* symbolic port name */ +}; + +/** + * RPN_ID + */ +struct fcgs_rpnid_req_s{ +	u32	rsvd:8; +	u32	port_id:24; +	wwn_t		port_name; +}; + +/** + * RNN_ID + */ +struct fcgs_rnnid_req_s{ +	u32	rsvd:8; +	u32	port_id:24; +	wwn_t		node_name; +}; + +/** + * RCS_ID + */ +struct fcgs_rcsid_req_s{ +	u32	rsvd:8; +	u32	port_id:24; +	u32	cos; +}; + +/** + * RPT_ID + */ +struct fcgs_rptid_req_s{ +	u32	rsvd:8; +	u32	port_id:24; +	u32	port_type:8; +	u32	rsvd1:24; +}; + +/** + * GA_NXT Request + */ +struct fcgs_ganxt_req_s{ +	u32	rsvd:8; +	u32	port_id:24; +}; + +/** + * GA_NXT Response + */ +struct fcgs_ganxt_rsp_s{ +	u32	port_type:8;	/* Port Type */ +	u32	port_id:24;	/* Port Identifier */ +	wwn_t		port_name;	/* Port Name */ +	u8		spn_len;	/* Length of Symbolic Port Name */ +	char		spn[255];	/* Symbolic Port Name */ +	wwn_t		node_name;	/* Node Name */ +	u8		snn_len;	/* Length of Symbolic Node Name */ +	char		snn[255];	/* Symbolic Node Name */ +	u8		ipa[8];		/* Initial Process Associator */ +	u8		ip[16];		/* IP Address */ +	u32	cos;		/* Class of Service */ +	u32	fc4types[8];	/* FC-4 TYPEs */ +	wwn_t		fabric_port_name; +					/* Fabric Port Name */ +	u32	rsvd:8;		/* Reserved */ +	u32	hard_addr:24;	/* Hard Address */ +}; + +/* + * Fabric Config Server + */ + +/* + * Command codes for Fabric Configuration Server + */ +enum { +	GS_FC_GFN_CMD	= 0x0114,	/* GS FC Get Fabric Name  */ +	GS_FC_GMAL_CMD	= 0x0116,	/* GS FC GMAL  */ +	GS_FC_TRACE_CMD	= 0x0400,	/* GS FC Trace Route */ +	GS_FC_PING_CMD	= 0x0401,	/* GS FC Ping */ +}; + +/* + * Source or Destination Port Tags. + */ +enum { +	GS_FTRACE_TAG_NPORT_ID		= 1, +	GS_FTRACE_TAG_NPORT_NAME	= 2, +}; + +/* +* Port Value : Could be a Port id or wwn + */ +union fcgs_port_val_u{ +	u32	nport_id; +	wwn_t		nport_wwn; +}; + +#define GS_FTRACE_MAX_HOP_COUNT	20 +#define GS_FTRACE_REVISION	1 + +/* + * Ftrace Related Structures. + */ + +/* + * STR (Switch Trace) Reject Reason Codes. From FC-SW. + */ +enum { +	GS_FTRACE_STR_CMD_COMPLETED_SUCC	= 0, +	GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH, +	GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH, +	GS_FTRACE_STR_MAX_HOP_CNT_REACHED, +	GS_FTRACE_STR_SRC_PORT_NOT_FOUND, +	GS_FTRACE_STR_DST_PORT_NOT_FOUND, +	GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE, +	GS_FTRACE_STR_NO_ROUTE_BW_PORTS, +	GS_FTRACE_STR_NO_ADDL_EXPLN, +	GS_FTRACE_STR_FABRIC_BUSY, +	GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS, +	GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0, +	GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff, +}; + +/* + * Ftrace Request + */ +struct fcgs_ftrace_req_s{ +	u32	revision; +	u16	src_port_tag;	/* Source Port tag */ +	u16	src_port_len;	/* Source Port len */ +	union fcgs_port_val_u src_port_val;	/* Source Port value */ +	u16	dst_port_tag;	/* Destination Port tag */ +	u16	dst_port_len;	/* Destination Port len */ +	union fcgs_port_val_u dst_port_val;	/* Destination Port value */ +	u32	token; +	u8		vendor_id[8];	/* T10 Vendor Identifier */ +	u8		vendor_info[8];	/* Vendor specific Info */ +	u32	max_hop_cnt;	/* Max Hop Count */ +}; + +/* + * Path info structure + */ +struct fcgs_ftrace_path_info_s{ +	wwn_t		switch_name;		/* Switch WWN */ +	u32	domain_id; +	wwn_t		ingress_port_name;	/* Ingress ports wwn */ +	u32	ingress_phys_port_num;	/* Ingress ports physical port +						 * number +						 */ +	wwn_t		egress_port_name;	/* Ingress ports wwn */ +	u32	egress_phys_port_num;	/* Ingress ports physical port +						 * number +						 */ +}; + +/* + * Ftrace Acc Response + */ +struct fcgs_ftrace_resp_s{ +	u32	revision; +	u32	token; +	u8		vendor_id[8];		/* T10 Vendor Identifier */ +	u8		vendor_info[8];		/* Vendor specific Info */ +	u32	str_rej_reason_code;	/* STR Reject Reason Code */ +	u32	num_path_info_entries;	/* No. of path info entries */ +	/* +	 * path info entry/entries. +	 */ +	struct fcgs_ftrace_path_info_s path_info[1]; + +}; + +/* +* Fabric Config Server : FCPing + */ + +/* + * FC Ping Request + */ +struct fcgs_fcping_req_s{ +	u32	revision; +	u16	port_tag; +	u16	port_len;	/* Port len */ +	union fcgs_port_val_u port_val;	/* Port value */ +	u32	token; +}; + +/* + * FC Ping Response + */ +struct fcgs_fcping_resp_s{ +	u32	token; +}; + +/* + * Command codes for zone server query. + */ +enum { +	ZS_GZME = 0x0124,	/* Get zone member extended */ +}; + +/* + * ZS GZME request + */ +#define ZS_GZME_ZNAMELEN	32 +struct zs_gzme_req_s{ +	u8	znamelen; +	u8	rsvd[3]; +	u8	zname[ZS_GZME_ZNAMELEN]; +}; + +enum zs_mbr_type{ +	ZS_MBR_TYPE_PWWN	= 1, +	ZS_MBR_TYPE_DOMPORT	= 2, +	ZS_MBR_TYPE_PORTID	= 3, +	ZS_MBR_TYPE_NWWN	= 4, +}; + +struct zs_mbr_wwn_s{ +	u8	mbr_type; +	u8	rsvd[3]; +	wwn_t	wwn; +}; + +struct zs_query_resp_s{ +	u32	nmbrs;	/*  number of zone members */ +	struct zs_mbr_wwn_s	mbr[1]; +}; + +/* + * GMAL Command ( Get ( interconnect Element) Management Address List) + * To retrieve the IP Address of a Switch. + */ + +#define CT_GMAL_RESP_PREFIX_TELNET	 "telnet://" +#define CT_GMAL_RESP_PREFIX_HTTP	 "http://" + +/*  GMAL/GFN request */ +struct fcgs_req_s { +	wwn_t    wwn; 	/* PWWN/NWWN */ +}; + +#define fcgs_gmal_req_t struct fcgs_req_s +#define fcgs_gfn_req_t struct fcgs_req_s + +/* Accept Response to GMAL */ +struct fcgs_gmal_resp_s { +	u32 		ms_len;   /* Num of entries */ +	u8     	ms_ma[256]; +}; + +struct fc_gmal_entry_s { +	u8  len; +	u8  prefix[7]; /* like "http://" */ +	u8  ip_addr[248]; +}; + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h new file mode 100644 index 00000000000..3e39ba58cfb --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/fc.h @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FC_H__ +#define __FC_H__ + +#include <protocol/types.h> + +#pragma pack(1) + +/* + * Fibre Channel Header Structure (FCHS) definition + */ +struct fchs_s { +#ifdef __BIGENDIAN +	u32        routing:4;	/* routing bits */ +	u32        cat_info:4;	/* category info */ +#else +	u32        cat_info:4;	/* category info */ +	u32        routing:4;	/* routing bits */ +#endif +	u32        d_id:24;	/* destination identifier */ + +	u32        cs_ctl:8;	/* class specific control */ +	u32        s_id:24;	/* source identifier */ + +	u32        type:8;		/* data structure type */ +	u32        f_ctl:24;	/* initial frame control */ + +	u8         seq_id;		/* sequence identifier */ +	u8         df_ctl;		/* data field control */ +	u16        seq_cnt;	/* sequence count */ + +	u16        ox_id;		/* originator exchange ID */ +	u16        rx_id;		/* responder exchange ID */ + +	u32        ro;		/* relative offset */ +}; +/* + * Fibre Channel BB_E Header Structure + */ +struct fcbbehs_s { +	u16	ver_rsvd; +	u32	rsvd[2]; +	u32	rsvd__sof; +}; + +#define FC_SEQ_ID_MAX		256 + +/* + * routing bit definitions + */ +enum { +	FC_RTG_FC4_DEV_DATA	= 0x0,	/* FC-4 Device Data */ +	FC_RTG_EXT_LINK		= 0x2,	/* Extended Link Data */ +	FC_RTG_FC4_LINK_DATA	= 0x3,	/* FC-4 Link Data */ +	FC_RTG_VIDEO_DATA	= 0x4,	/* Video Data */ +	FC_RTG_EXT_HDR		= 0x5,	/* VFT, IFR or Encapsuled */ +	FC_RTG_BASIC_LINK	= 0x8,	/* Basic Link data */ +	FC_RTG_LINK_CTRL	= 0xC,	/* Link Control */ +}; + +/* + * information category for extended link data and FC-4 Link Data + */ +enum { +	FC_CAT_LD_REQUEST	= 0x2,	/* Request */ +	FC_CAT_LD_REPLY		= 0x3,	/* Reply */ +	FC_CAT_LD_DIAG		= 0xF,	/* for DIAG use only */ +}; + +/* + * information category for extended headers (VFT, IFR or encapsulation) + */ +enum { +	FC_CAT_VFT_HDR = 0x0,	/* Virtual fabric tagging header */ +	FC_CAT_IFR_HDR = 0x1,	/* Inter-Fabric routing header */ +	FC_CAT_ENC_HDR = 0x2,	/* Encapsulation header */ +}; + +/* + * information category for FC-4 device data + */ +enum { +	FC_CAT_UNCATEG_INFO	= 0x0,	/* Uncategorized information */ +	FC_CAT_SOLICIT_DATA	= 0x1,	/* Solicited Data */ +	FC_CAT_UNSOLICIT_CTRL	= 0x2,	/* Unsolicited Control */ +	FC_CAT_SOLICIT_CTRL	= 0x3,	/* Solicited Control */ +	FC_CAT_UNSOLICIT_DATA	= 0x4,	/* Unsolicited Data */ +	FC_CAT_DATA_DESC	= 0x5,	/* Data Descriptor */ +	FC_CAT_UNSOLICIT_CMD	= 0x6,	/* Unsolicited Command */ +	FC_CAT_CMD_STATUS	= 0x7,	/* Command Status */ +}; + +/* + * information category for Link Control + */ +enum { +	FC_CAT_ACK_1		= 0x00, +	FC_CAT_ACK_0_N		= 0x01, +	FC_CAT_P_RJT		= 0x02, +	FC_CAT_F_RJT		= 0x03, +	FC_CAT_P_BSY		= 0x04, +	FC_CAT_F_BSY_DATA	= 0x05, +	FC_CAT_F_BSY_LINK_CTL	= 0x06, +	FC_CAT_F_LCR		= 0x07, +	FC_CAT_NTY		= 0x08, +	FC_CAT_END		= 0x09, +}; + +/* + * Type Field Definitions. FC-PH Section 18.5 pg. 165 + */ +enum { +	FC_TYPE_BLS		= 0x0,	/* Basic Link Service */ +	FC_TYPE_ELS		= 0x1,	/* Extended Link Service */ +	FC_TYPE_IP		= 0x5,	/* IP */ +	FC_TYPE_FCP		= 0x8,	/* SCSI-FCP */ +	FC_TYPE_GPP		= 0x9,	/* SCSI_GPP */ +	FC_TYPE_SERVICES	= 0x20,	/* Fibre Channel Services */ +	FC_TYPE_FC_FSS		= 0x22,	/* Fabric Switch Services */ +	FC_TYPE_FC_AL		= 0x23,	/* FC-AL */ +	FC_TYPE_FC_SNMP		= 0x24,	/* FC-SNMP */ +	FC_TYPE_MAX		= 256,	/* 256 FC-4 types */ +}; + +struct fc_fc4types_s{ +	u8         bits[FC_TYPE_MAX / 8]; +}; + +/* + * Frame Control Definitions. FC-PH Table-45. pg. 168 + */ +enum { +	FCTL_EC_ORIG = 0x000000,	/* exchange originator */ +	FCTL_EC_RESP = 0x800000,	/* exchange responder */ +	FCTL_SEQ_INI = 0x000000,	/* sequence initiator */ +	FCTL_SEQ_REC = 0x400000,	/* sequence recipient */ +	FCTL_FS_EXCH = 0x200000,	/* first sequence of xchg */ +	FCTL_LS_EXCH = 0x100000,	/* last sequence of xchg */ +	FCTL_END_SEQ = 0x080000,	/* last frame of sequence */ +	FCTL_SI_XFER = 0x010000,	/* seq initiative transfer */ +	FCTL_RO_PRESENT = 0x000008,	/* relative offset present */ +	FCTL_FILLBYTE_MASK = 0x000003	/* , fill byte mask */ +}; + +/* + * Fabric Well Known Addresses + */ +enum { +	FC_MIN_WELL_KNOWN_ADDR		= 0xFFFFF0, +	FC_DOMAIN_CONTROLLER_MASK 	= 0xFFFC00, +	FC_ALIAS_SERVER			= 0xFFFFF8, +	FC_MGMT_SERVER			= 0xFFFFFA, +	FC_TIME_SERVER			= 0xFFFFFB, +	FC_NAME_SERVER			= 0xFFFFFC, +	FC_FABRIC_CONTROLLER		= 0xFFFFFD, +	FC_FABRIC_PORT			= 0xFFFFFE, +	FC_BROADCAST_SERVER		= 0xFFFFFF +}; + +/* + * domain/area/port defines + */ +#define FC_DOMAIN_MASK  0xFF0000 +#define FC_DOMAIN_SHIFT 16 +#define FC_AREA_MASK    0x00FF00 +#define FC_AREA_SHIFT   8 +#define FC_PORT_MASK    0x0000FF +#define FC_PORT_SHIFT   0 + +#define FC_GET_DOMAIN(p)	(((p) & FC_DOMAIN_MASK) >> FC_DOMAIN_SHIFT) +#define FC_GET_AREA(p)		(((p) & FC_AREA_MASK) >> FC_AREA_SHIFT) +#define FC_GET_PORT(p)		(((p) & FC_PORT_MASK) >> FC_PORT_SHIFT) + +#define FC_DOMAIN_CTRLR(p)	(FC_DOMAIN_CONTROLLER_MASK | (FC_GET_DOMAIN(p))) + +enum { +	FC_RXID_ANY = 0xFFFFU, +}; + +/* + * generic ELS command + */ +struct fc_els_cmd_s{ +	u32        els_code:8;	/* ELS Command Code */ +	u32        reserved:24; +}; + +/* + * ELS Command Codes. FC-PH Table-75. pg. 223 + */ +enum { +	FC_ELS_LS_RJT = 0x1,	/* Link Service Reject. */ +	FC_ELS_ACC = 0x02,	/* Accept */ +	FC_ELS_PLOGI = 0x03,	/* N_Port Login. */ +	FC_ELS_FLOGI = 0x04,	/* F_Port Login. */ +	FC_ELS_LOGO = 0x05,	/* Logout. */ +	FC_ELS_ABTX = 0x06,	/* Abort Exchange */ +	FC_ELS_RES = 0x08,	/* Read Exchange status */ +	FC_ELS_RSS = 0x09,	/* Read sequence status block */ +	FC_ELS_RSI = 0x0A,	/* Request Sequence Initiative */ +	FC_ELS_ESTC = 0x0C,	/* Estimate Credit. */ +	FC_ELS_RTV = 0x0E,	/* Read Timeout Value. */ +	FC_ELS_RLS = 0x0F,	/* Read Link Status. */ +	FC_ELS_ECHO = 0x10,	/* Echo */ +	FC_ELS_TEST = 0x11,	/* Test */ +	FC_ELS_RRQ = 0x12,	/* Reinstate Recovery Qualifier. */ +	FC_ELS_REC = 0x13,	/* Add this for TAPE support in FCR */ +	FC_ELS_PRLI = 0x20,	/* Process Login */ +	FC_ELS_PRLO = 0x21,	/* Process Logout. */ +	FC_ELS_SCN = 0x22,	/* State Change Notification. */ +	FC_ELS_TPRLO = 0x24,	/* Third Party Process Logout. */ +	FC_ELS_PDISC = 0x50,	/* Discover N_Port Parameters. */ +	FC_ELS_FDISC = 0x51,	/* Discover F_Port Parameters. */ +	FC_ELS_ADISC = 0x52,	/* Discover Address. */ +	FC_ELS_FAN = 0x60,	/* Fabric Address Notification */ +	FC_ELS_RSCN = 0x61,	/* Reg State Change Notification */ +	FC_ELS_SCR = 0x62,	/* State Change Registration. */ +	FC_ELS_RTIN = 0x77,	/* Mangement server request */ +	FC_ELS_RNID = 0x78,	/* Mangement server request */ +	FC_ELS_RLIR = 0x79,	/* Registered Link Incident Record */ + +	FC_ELS_RPSC = 0x7D,	/* Report Port Speed Capabilities */ +	FC_ELS_QSA = 0x7E,	/* Query Security Attributes. Ref FC-SP */ +	FC_ELS_E2E_LBEACON = 0x81, +				/* End-to-End Link Beacon */ +	FC_ELS_AUTH = 0x90,	/* Authentication. Ref FC-SP */ +	FC_ELS_RFCN = 0x97,	/* Request Fabric Change Notification. Ref +				 *FC-SP */ + +}; + +/* + *  Version numbers for FC-PH standards, + *  used in login to indicate what port + *  supports. See FC-PH-X table 158. + */ +enum { +	FC_PH_VER_4_3 = 0x09, +	FC_PH_VER_PH_3 = 0x20, +}; + +/* + * PDU size defines + */ +enum { +	FC_MIN_PDUSZ = 512, +	FC_MAX_PDUSZ = 2112, +}; + +/* + * N_Port PLOGI Common Service Parameters. + * FC-PH-x. Figure-76. pg. 308. + */ +struct fc_plogi_csp_s{ +	u8         verhi;	/* FC-PH high version */ +	u8         verlo;	/* FC-PH low version */ +	u16        bbcred;	/* BB_Credit */ + +#ifdef __BIGENDIAN +	u8         ciro:1,		/* continuously increasing RO */ +			rro:1,		/* random relative offset */ +			npiv_supp:1,	/* NPIV supported */ +			port_type:1,	/* N_Port/F_port */ +			altbbcred:1,	/* alternate BB_Credit */ +			resolution:1,	/* ms/ns ED_TOV resolution */ +			vvl_info:1,	/* VVL Info included */ +			reserved1:1; + +	u8         hg_supp:1, +			query_dbc:1, +			security:1, +			sync_cap:1, +			r_t_tov:1, +			dh_dup_supp:1, +			cisc:1,		/* continuously increasing seq count */ +			payload:1; +#else +	u8         reserved2:2, +			resolution:1,	/* ms/ns ED_TOV resolution */ +			altbbcred:1,	/* alternate BB_Credit */ +			port_type:1,	/* N_Port/F_port */ +			npiv_supp:1,	/* NPIV supported */ +			rro:1,		/* random relative offset */ +			ciro:1;		/* continuously increasing RO */ + +	u8         payload:1, +			cisc:1,		/* continuously increasing seq count */ +			dh_dup_supp:1, +			r_t_tov:1, +			sync_cap:1, +			security:1, +			query_dbc:1, +			hg_supp:1; +#endif + +	u16        rxsz;		/* recieve data_field size */ + +	u16        conseq; +	u16        ro_bitmap; + +	u32        e_d_tov; +}; + +/* + * N_Port PLOGI Class Specific Parameters. + * FC-PH-x. Figure 78. pg. 318. + */ +struct fc_plogi_clp_s{ +#ifdef __BIGENDIAN +	u32        class_valid:1; +	u32        intermix:1;	/* class intermix supported if set =1. +					 * valid only for class1. Reserved for +					 * class2 & class3 +					 */ +	u32        reserved1:2; +	u32        sequential:1; +	u32        reserved2:3; +#else +	u32        reserved2:3; +	u32        sequential:1; +	u32        reserved1:2; +	u32        intermix:1;	/* class intermix supported if set =1. +					 * valid only for class1. Reserved for +					 * class2 & class3 +					 */ +	u32        class_valid:1; +#endif + +	u32        reserved3:24; + +	u32        reserved4:16; +	u32        rxsz:16;	/* Receive data_field size */ + +	u32        reserved5:8; +	u32        conseq:8; +	u32        e2e_credit:16;	/* end to end credit */ + +	u32        reserved7:8; +	u32        ospx:8; +	u32        reserved8:16; +}; + +#define FLOGI_VVL_BRCD    0x42524344 /* ASCII value for each character in +				      * string "BRCD" */ + +/* + * PLOGI els command and reply payload + */ +struct fc_logi_s{ +	struct fc_els_cmd_s els_cmd;	/* ELS command code */ +	struct fc_plogi_csp_s  csp;		/* common service params */ +	wwn_t           port_name; +	wwn_t           node_name; +	struct fc_plogi_clp_s  class1;		/* class 1 service parameters */ +	struct fc_plogi_clp_s  class2;		/* class 2 service parameters */ +	struct fc_plogi_clp_s  class3;		/* class 3 service parameters */ +	struct fc_plogi_clp_s  class4;		/* class 4 service parameters */ +	u8         vvl[16];	/* vendor version level */ +}; + +/* + * LOGO els command payload + */ +struct fc_logo_s{ +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        res1:8; +	u32        nport_id:24;	/* N_Port identifier of source */ +	wwn_t           orig_port_name;	/* Port name of the LOGO originator */ +}; + +/* + * ADISC els command payload + */ +struct fc_adisc_s { +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        res1:8; +	u32        orig_HA:24;	/* originator hard address */ +	wwn_t           orig_port_name;	/* originator port name */ +	wwn_t           orig_node_name;	/* originator node name */ +	u32        res2:8; +	u32        nport_id:24;	/* originator NPortID */ +}; + +/* + * Exchange status block + */ +struct fc_exch_status_blk_s{ +	u32        oxid:16; +	u32        rxid:16; +	u32        res1:8; +	u32        orig_np:24;	/* originator NPortID */ +	u32        res2:8; +	u32        resp_np:24;	/* responder NPortID */ +	u32        es_bits; +	u32        res3; +	/* +	 * un modified section of the fields +	 */ +}; + +/* + * RES els command payload + */ +struct fc_res_s { +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        res1:8; +	u32        nport_id:24;	/* N_Port identifier of source */ +	u32        oxid:16; +	u32        rxid:16; +	u8         assoc_hdr[32]; +}; + +/* + * RES els accept payload + */ +struct fc_res_acc_s{ +	struct fc_els_cmd_s els_cmd;	/* ELS command code */ +	struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */ +}; + +/* + * REC els command payload + */ +struct fc_rec_s { +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        res1:8; +	u32        nport_id:24;	/* N_Port identifier of source */ +	u32        oxid:16; +	u32        rxid:16; +}; + +#define FC_REC_ESB_OWN_RSP	0x80000000	/* responder owns */ +#define FC_REC_ESB_SI		0x40000000	/* SI is owned 	*/ +#define FC_REC_ESB_COMP		0x20000000	/* exchange is complete	*/ +#define FC_REC_ESB_ENDCOND_ABN	0x10000000	/* abnormal ending 	*/ +#define FC_REC_ESB_RQACT	0x04000000	/* recovery qual active	*/ +#define FC_REC_ESB_ERRP_MSK	0x03000000 +#define FC_REC_ESB_OXID_INV	0x00800000	/* invalid OXID		*/ +#define FC_REC_ESB_RXID_INV	0x00400000	/* invalid RXID		*/ +#define FC_REC_ESB_PRIO_INUSE	0x00200000 + +/* + * REC els accept payload + */ +struct fc_rec_acc_s { +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        oxid:16; +	u32        rxid:16; +	u32        res1:8; +	u32        orig_id:24;	/* N_Port id of exchange originator */ +	u32        res2:8; +	u32        resp_id:24;	/* N_Port id of exchange responder */ +	u32        count;		/* data transfer count */ +	u32        e_stat;		/* exchange status */ +}; + +/* + * RSI els payload + */ +struct fc_rsi_s { +	struct fc_els_cmd_s    els_cmd; +	u32        res1:8; +	u32        orig_sid:24; +	u32        oxid:16; +	u32        rxid:16; +}; + +/* + * structure for PRLI paramater pages, both request & response + * see FC-PH-X table 113 & 115 for explanation also FCP table 8 + */ +struct fc_prli_params_s{ +	u32        reserved: 16; +#ifdef __BIGENDIAN +	u32        reserved1: 5; +	u32        rec_support : 1; +	u32        task_retry_id : 1; +	u32        retry : 1; + +	u32        confirm : 1; +	u32        doverlay:1; +	u32        initiator:1; +	u32        target:1; +	u32        cdmix:1; +	u32        drmix:1; +	u32        rxrdisab:1; +	u32        wxrdisab:1; +#else +	u32        retry : 1; +	u32        task_retry_id : 1; +	u32        rec_support : 1; +	u32        reserved1: 5; + +	u32        wxrdisab:1; +	u32        rxrdisab:1; +	u32        drmix:1; +	u32        cdmix:1; +	u32        target:1; +	u32        initiator:1; +	u32        doverlay:1; +	u32        confirm : 1; +#endif +}; + +/* + * valid values for rspcode in PRLI ACC payload + */ +enum { +	FC_PRLI_ACC_XQTD = 0x1,		/* request executed */ +	FC_PRLI_ACC_PREDEF_IMG = 0x5,	/* predefined image - no prli needed */ +}; + +struct fc_prli_params_page_s{ +	u32        type:8; +	u32        codext:8; +#ifdef __BIGENDIAN +	u32        origprocasv:1; +	u32        rsppav:1; +	u32        imagepair:1; +	u32        reserved1:1; +	u32        rspcode:4; +#else +	u32        rspcode:4; +	u32        reserved1:1; +	u32        imagepair:1; +	u32        rsppav:1; +	u32        origprocasv:1; +#endif +	u32        reserved2:8; + +	u32        origprocas; +	u32        rspprocas; +	struct fc_prli_params_s  servparams; +}; + +/* + * PRLI request and accept payload, FC-PH-X tables 112 & 114 + */ +struct fc_prli_s{ +	u32        command:8; +	u32        pglen:8; +	u32        pagebytes:16; +	struct fc_prli_params_page_s parampage; +}; + +/* + * PRLO logout params page + */ +struct fc_prlo_params_page_s{ +	u32        type:8; +	u32        type_ext:8; +#ifdef __BIGENDIAN +	u32        opa_valid:1;	/* originator process associator +					 * valid +					 */ +	u32        rpa_valid:1;	/* responder process associator valid */ +	u32        res1:14; +#else +	u32        res1:14; +	u32        rpa_valid:1;	/* responder process associator valid */ +	u32        opa_valid:1;	/* originator process associator +					 * valid +					 */ +#endif +	u32        orig_process_assc; +	u32        resp_process_assc; + +	u32        res2; +}; + +/* + * PRLO els command payload + */ +struct fc_prlo_s{ +	u32        	command:8; +	u32        	page_len:8; +	u32        	payload_len:16; +	struct fc_prlo_params_page_s 	prlo_params[1]; +}; + +/* + * PRLO Logout response parameter page + */ +struct fc_prlo_acc_params_page_s{ +	u32        type:8; +	u32        type_ext:8; + +#ifdef __BIGENDIAN +	u32        opa_valid:1;	/* originator process associator +					 * valid +					 */ +	u32        rpa_valid:1;	/* responder process associator valid */ +	u32        res1:14; +#else +	u32        res1:14; +	u32        rpa_valid:1;	/* responder process associator valid */ +	u32        opa_valid:1;	/* originator process associator +					 * valid +					 */ +#endif +	u32        orig_process_assc; +	u32        resp_process_assc; + +	u32        fc4type_csp; +}; + +/* + * PRLO els command ACC payload + */ +struct fc_prlo_acc_s{ +	u32        command:8; +	u32        page_len:8; +	u32        payload_len:16; +	struct fc_prlo_acc_params_page_s prlo_acc_params[1]; +}; + +/* + * SCR els command payload + */ +enum { +	FC_SCR_REG_FUNC_FABRIC_DETECTED = 0x01, +	FC_SCR_REG_FUNC_N_PORT_DETECTED = 0x02, +	FC_SCR_REG_FUNC_FULL = 0x03, +	FC_SCR_REG_FUNC_CLEAR_REG = 0xFF, +}; + +/* SCR VU registrations */ +enum { +	FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE = 0x01 +}; + +struct fc_scr_s{ +	u32 command:8; +	u32 res:24; +	u32 vu_reg_func:8; /* Vendor Unique Registrations */ +	u32 res1:16; +	u32 reg_func:8; +}; + +/* + * Information category for Basic link data + */ +enum { +	FC_CAT_NOP	= 0x0, +	FC_CAT_ABTS	= 0x1, +	FC_CAT_RMC	= 0x2, +	FC_CAT_BA_ACC	= 0x4, +	FC_CAT_BA_RJT	= 0x5, +	FC_CAT_PRMT	= 0x6, +}; + +/* + * LS_RJT els reply payload + */ +struct fc_ls_rjt_s { +	struct fc_els_cmd_s    els_cmd;		/* ELS command code */ +	u32        res1:8; +	u32        reason_code:8;		/* Reason code for reject */ +	u32        reason_code_expl:8;	/* Reason code explanation */ +	u32        vendor_unique:8;	/* Vendor specific */ +}; + +/* + * LS_RJT reason codes + */ +enum { +	FC_LS_RJT_RSN_INV_CMD_CODE	= 0x01, +	FC_LS_RJT_RSN_LOGICAL_ERROR	= 0x03, +	FC_LS_RJT_RSN_LOGICAL_BUSY	= 0x05, +	FC_LS_RJT_RSN_PROTOCOL_ERROR	= 0x07, +	FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD = 0x09, +	FC_LS_RJT_RSN_CMD_NOT_SUPP	= 0x0B, +}; + +/* + * LS_RJT reason code explanation + */ +enum { +	FC_LS_RJT_EXP_NO_ADDL_INFO		= 0x00, +	FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS	= 0x01, +	FC_LS_RJT_EXP_SPARMS_ERR_INI_CTL	= 0x03, +	FC_LS_RJT_EXP_SPARMS_ERR_REC_CTL	= 0x05, +	FC_LS_RJT_EXP_SPARMS_ERR_RXSZ		= 0x07, +	FC_LS_RJT_EXP_SPARMS_ERR_CONSEQ		= 0x09, +	FC_LS_RJT_EXP_SPARMS_ERR_CREDIT		= 0x0B, +	FC_LS_RJT_EXP_INV_PORT_NAME		= 0x0D, +	FC_LS_RJT_EXP_INV_NODE_FABRIC_NAME	= 0x0E, +	FC_LS_RJT_EXP_INV_CSP			= 0x0F, +	FC_LS_RJT_EXP_INV_ASSOC_HDR		= 0x11, +	FC_LS_RJT_EXP_ASSOC_HDR_REQD		= 0x13, +	FC_LS_RJT_EXP_INV_ORIG_S_ID		= 0x15, +	FC_LS_RJT_EXP_INV_OXID_RXID_COMB	= 0x17, +	FC_LS_RJT_EXP_CMD_ALREADY_IN_PROG	= 0x19, +	FC_LS_RJT_EXP_LOGIN_REQUIRED		= 0x1E, +	FC_LS_RJT_EXP_INVALID_NPORT_ID		= 0x1F, +	FC_LS_RJT_EXP_INSUFF_RES		= 0x29, +	FC_LS_RJT_EXP_CMD_NOT_SUPP		= 0x2C, +	FC_LS_RJT_EXP_INV_PAYLOAD_LEN		= 0x2D, +}; + +/* + * RRQ els command payload + */ +struct fc_rrq_s{ +	struct fc_els_cmd_s    els_cmd;	/* ELS command code */ +	u32        res1:8; +	u32        s_id:24;	/* exchange originator S_ID */ + +	u32        ox_id:16;	/* originator exchange ID */ +	u32        rx_id:16;	/* responder exchange ID */ + +	u32        res2[8];	/* optional association header */ +}; + +/* + * ABTS BA_ACC reply payload + */ +struct fc_ba_acc_s{ +	u32        seq_id_valid:8;	/* set to 0x00 for Abort Exchange */ +	u32        seq_id:8;	/* invalid for Abort Exchange */ +	u32        res2:16; +	u32        ox_id:16;	/* OX_ID from ABTS frame */ +	u32        rx_id:16;	/* RX_ID from ABTS frame */ +	u32        low_seq_cnt:16;	/* set to 0x0000 for Abort Exchange */ +	u32        high_seq_cnt:16;/* set to 0xFFFF for Abort Exchange */ +}; + +/* + * ABTS BA_RJT reject payload + */ +struct fc_ba_rjt_s{ +	u32        res1:8;		/* Reserved */ +	u32        reason_code:8;	/* reason code for reject */ +	u32        reason_expl:8;	/* reason code explanation */ +	u32        vendor_unique:8;/* vendor unique reason code,set to 0 */ +}; + +/* + * TPRLO logout parameter page + */ +struct fc_tprlo_params_page_s{ +	u32        type:8; +	u32        type_ext:8; + +#ifdef __BIGENDIAN +	u32        opa_valid:1; +	u32        rpa_valid:1; +	u32        tpo_nport_valid:1; +	u32        global_process_logout:1; +	u32        res1:12; +#else +	u32        res1:12; +	u32        global_process_logout:1; +	u32        tpo_nport_valid:1; +	u32        rpa_valid:1; +	u32        opa_valid:1; +#endif + +	u32        orig_process_assc; +	u32        resp_process_assc; + +	u32        res2:8; +	u32        tpo_nport_id; +}; + +/* + * TPRLO ELS command payload + */ +struct fc_tprlo_s{ +	u32        command:8; +	u32        page_len:8; +	u32        payload_len:16; + +	struct fc_tprlo_params_page_s tprlo_params[1]; +}; + +enum fc_tprlo_type{ +	FC_GLOBAL_LOGO = 1, +	FC_TPR_LOGO +}; + +/* + * TPRLO els command ACC payload + */ +struct fc_tprlo_acc_s{ +	u32	command:8; +	u32	page_len:8; +	u32	payload_len:16; +	struct fc_prlo_acc_params_page_s tprlo_acc_params[1]; +}; + +/* + * RSCN els command req payload + */ +#define FC_RSCN_PGLEN	0x4 + +enum fc_rscn_format{ +	FC_RSCN_FORMAT_PORTID	= 0x0, +	FC_RSCN_FORMAT_AREA	= 0x1, +	FC_RSCN_FORMAT_DOMAIN	= 0x2, +	FC_RSCN_FORMAT_FABRIC	= 0x3, +}; + +struct fc_rscn_event_s{ +	u32        format:2; +	u32        qualifier:4; +	u32        resvd:2; +	u32        portid:24; +}; + +struct fc_rscn_pl_s{ +	u8         command; +	u8         pagelen; +	u16        payldlen; +	struct fc_rscn_event_s event[1]; +}; + +/* + * ECHO els command req payload + */ +struct fc_echo_s { +	struct fc_els_cmd_s    els_cmd; +}; + +/* + * RNID els command + */ + +#define RNID_NODEID_DATA_FORMAT_COMMON    		 0x00 +#define RNID_NODEID_DATA_FORMAT_FCP3        		 0x08 +#define RNID_NODEID_DATA_FORMAT_DISCOVERY     		0xDF + +#define RNID_ASSOCIATED_TYPE_UNKNOWN                    0x00000001 +#define RNID_ASSOCIATED_TYPE_OTHER                      0x00000002 +#define RNID_ASSOCIATED_TYPE_HUB                        0x00000003 +#define RNID_ASSOCIATED_TYPE_SWITCH                     0x00000004 +#define RNID_ASSOCIATED_TYPE_GATEWAY                    0x00000005 +#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE             0x00000009 +#define RNID_ASSOCIATED_TYPE_HOST                       0x0000000A +#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM          0x0000000B +#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE      0x0000000E +#define RNID_ASSOCIATED_TYPE_NAS_SERVER                 0x00000011 +#define RNID_ASSOCIATED_TYPE_BRIDGE                     0x00000002 +#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE      0x00000003 +#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE      0x000000FF + +/* + * RNID els command payload + */ +struct fc_rnid_cmd_s{ +	struct fc_els_cmd_s    els_cmd; +	u32        node_id_data_format:8; +	u32        reserved:24; +}; + +/* + * RNID els response payload + */ + +struct fc_rnid_common_id_data_s{ +	wwn_t           port_name; +	wwn_t           node_name; +}; + +struct fc_rnid_general_topology_data_s{ +	u32        vendor_unique[4]; +	u32        asso_type; +	u32        phy_port_num; +	u32        num_attached_nodes; +	u32        node_mgmt:8; +	u32        ip_version:8; +	u32        udp_tcp_port_num:16; +	u32        ip_address[4]; +	u32        reserved:16; +	u32        vendor_specific:16; +}; + +struct fc_rnid_acc_s{ +	struct fc_els_cmd_s    els_cmd; +	u32        node_id_data_format:8; +	u32        common_id_data_length:8; +	u32        reserved:8; +	u32        specific_id_data_length:8; +	struct fc_rnid_common_id_data_s common_id_data; +	struct fc_rnid_general_topology_data_s gen_topology_data; +}; + +#define RNID_ASSOCIATED_TYPE_UNKNOWN                    0x00000001 +#define RNID_ASSOCIATED_TYPE_OTHER                      0x00000002 +#define RNID_ASSOCIATED_TYPE_HUB                        0x00000003 +#define RNID_ASSOCIATED_TYPE_SWITCH                     0x00000004 +#define RNID_ASSOCIATED_TYPE_GATEWAY                    0x00000005 +#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE             0x00000009 +#define RNID_ASSOCIATED_TYPE_HOST                       0x0000000A +#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM          0x0000000B +#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE      0x0000000E +#define RNID_ASSOCIATED_TYPE_NAS_SERVER                 0x00000011 +#define RNID_ASSOCIATED_TYPE_BRIDGE                     0x00000002 +#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE      0x00000003 +#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE      0x000000FF + +enum fc_rpsc_speed_cap{ +	RPSC_SPEED_CAP_1G = 0x8000, +	RPSC_SPEED_CAP_2G = 0x4000, +	RPSC_SPEED_CAP_4G = 0x2000, +	RPSC_SPEED_CAP_10G = 0x1000, +	RPSC_SPEED_CAP_8G = 0x0800, +	RPSC_SPEED_CAP_16G = 0x0400, + +	RPSC_SPEED_CAP_UNKNOWN = 0x0001, +}; + +enum fc_rpsc_op_speed_s{ +	RPSC_OP_SPEED_1G = 0x8000, +	RPSC_OP_SPEED_2G = 0x4000, +	RPSC_OP_SPEED_4G = 0x2000, +	RPSC_OP_SPEED_10G = 0x1000, +	RPSC_OP_SPEED_8G = 0x0800, +	RPSC_OP_SPEED_16G = 0x0400, + +	RPSC_OP_SPEED_NOT_EST = 0x0001,	/*! speed not established */ +}; + +struct fc_rpsc_speed_info_s{ +	u16        port_speed_cap;	/*! see fc_rpsc_speed_cap_t */ +	u16        port_op_speed;	/*! see fc_rpsc_op_speed_t */ +}; + +enum link_e2e_beacon_subcmd{ +	LINK_E2E_BEACON_ON = 1, +	LINK_E2E_BEACON_OFF = 2 +}; + +enum beacon_type{ +	BEACON_TYPE_NORMAL	= 1,	/*! Normal Beaconing. Green */ +	BEACON_TYPE_WARN	= 2,	/*! Warning Beaconing. Yellow/Amber */ +	BEACON_TYPE_CRITICAL	= 3	/*! Critical Beaconing. Red */ +}; + +struct link_e2e_beacon_param_s { +	u8         beacon_type;	/* Beacon Type. See beacon_type_t */ +	u8         beacon_frequency; +					/* Beacon frequency. Number of blinks +					 * per 10 seconds +					 */ +	u16        beacon_duration;/* Beacon duration (in Seconds). The +					 * command operation should be +					 * terminated at the end of this +					 * timeout value. +					 * +					 * Ignored if diag_sub_cmd is +					 * LINK_E2E_BEACON_OFF. +					 * +					 * If 0, beaconing will continue till a +					 * BEACON OFF request is received +					 */ +}; + +/* + * Link E2E beacon request/good response format. For LS_RJTs use fc_ls_rjt_t + */ +struct link_e2e_beacon_req_s{ +	u32        ls_code;	/*! FC_ELS_E2E_LBEACON in requests * +					 *or FC_ELS_ACC in good replies */ +	u32        ls_sub_cmd;	/*! See link_e2e_beacon_subcmd_t */ +	struct link_e2e_beacon_param_s beacon_parm; +}; + +/** + * If RPSC request is sent to the Domain Controller, the request is for + * all the ports within that domain (TODO - I don't think FOS implements + * this...). + */ +struct fc_rpsc_cmd_s{ +	struct fc_els_cmd_s    els_cmd; +}; + +/* + * RPSC Acc + */ +struct fc_rpsc_acc_s{ +	u32        command:8; +	u32        rsvd:8; +	u32        num_entries:16; + +	struct fc_rpsc_speed_info_s speed_info[1]; +}; + +/** + * If RPSC2 request is sent to the Domain Controller, + */ +#define FC_BRCD_TOKEN    0x42524344 + +struct fc_rpsc2_cmd_s{ +	struct fc_els_cmd_s    els_cmd; +	u32       	token; +	u16     	resvd; +	u16     	num_pids;       /* Number of pids in the request */ +	struct  { +		u32	rsvd1:8; +		u32	pid:24;	/* port identifier */ +	} pid_list[1]; +}; + +enum fc_rpsc2_port_type{ +	RPSC2_PORT_TYPE_UNKNOWN = 0, +	RPSC2_PORT_TYPE_NPORT   = 1, +	RPSC2_PORT_TYPE_NLPORT  = 2, +	RPSC2_PORT_TYPE_NPIV_PORT  = 0x5f, +	RPSC2_PORT_TYPE_NPORT_TRUNK  = 0x6f, +}; + +/* + * RPSC2 portInfo entry structure + */ +struct fc_rpsc2_port_info_s{ +    u32    pid;        /* PID */ +    u16    resvd1; +    u16    index;      /* port number / index */ +    u8     resvd2; +    u8    	type;        /* port type N/NL/... */ +    u16    speed;      /* port Operating Speed */ +}; + +/* + * RPSC2 Accept payload + */ +struct fc_rpsc2_acc_s{ +	u8        els_cmd; +	u8        resvd; +	u16       num_pids;  /* Number of pids in the request */ +	struct fc_rpsc2_port_info_s  port_info[1];    /* port information */ +}; + +/** + * bit fields so that multiple classes can be specified + */ +enum fc_cos{ +	FC_CLASS_2	= 0x04, +	FC_CLASS_3	= 0x08, +	FC_CLASS_2_3	= 0x0C, +}; + +/* + * symbolic name + */ +struct fc_symname_s{ +	u8         symname[FC_SYMNAME_MAX]; +}; + +struct fc_alpabm_s{ +	u8         alpa_bm[FC_ALPA_MAX / 8]; +}; + +/* + * protocol default timeout values + */ +#define FC_ED_TOV		2 +#define FC_REC_TOV		(FC_ED_TOV + 1) +#define FC_RA_TOV		10 +#define FC_ELS_TOV		(2 * FC_RA_TOV) + +/* + * virtual fabric related defines + */ +#define FC_VF_ID_NULL    0	/*  must not be used as VF_ID */ +#define FC_VF_ID_MIN     1 +#define FC_VF_ID_MAX     0xEFF +#define FC_VF_ID_CTL     0xFEF	/*  control VF_ID */ + +/** + * Virtual Fabric Tagging header format + * @caution This is defined only in BIG ENDIAN format. + */ +struct fc_vft_s{ +	u32        r_ctl:8; +	u32        ver:2; +	u32        type:4; +	u32        res_a:2; +	u32        priority:3; +	u32        vf_id:12; +	u32        res_b:1; +	u32        hopct:8; +	u32        res_c:24; +}; + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/include/protocol/fc_sp.h b/drivers/scsi/bfa/include/protocol/fc_sp.h new file mode 100644 index 00000000000..55bb0b31d04 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/fc_sp.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FC_SP_H__ +#define __FC_SP_H__ + +#include <protocol/types.h> + +#pragma pack(1) + +enum auth_els_flags{ +	FC_AUTH_ELS_MORE_FRAGS_FLAG 	= 0x80,	/*! bit-7. More Fragments +						 * Follow +						 */ +	FC_AUTH_ELS_CONCAT_FLAG 	= 0x40,	/*! bit-6. Concatenation Flag */ +	FC_AUTH_ELS_SEQ_NUM_FLAG 	= 0x01 	/*! bit-0. Sequence Number */ +}; + +enum auth_msg_codes{ +	FC_AUTH_MC_AUTH_RJT		= 0x0A,	/*! Auth Reject */ +	FC_AUTH_MC_AUTH_NEG 		= 0x0B, /*! Auth Negotiate */ +	FC_AUTH_MC_AUTH_DONE 		= 0x0C, /*! Auth Done */ + +	FC_AUTH_MC_DHCHAP_CHAL 		= 0x10, /*! DHCHAP Challenge */ +	FC_AUTH_MC_DHCHAP_REPLY 	= 0x11, /*! DHCHAP Reply */ +	FC_AUTH_MC_DHCHAP_SUCC 		= 0x12, /*! DHCHAP Success */ + +	FC_AUTH_MC_FCAP_REQ 		= 0x13, /*! FCAP Request */ +	FC_AUTH_MC_FCAP_ACK 		= 0x14, /*! FCAP Acknowledge */ +	FC_AUTH_MC_FCAP_CONF 		= 0x15, /*! FCAP Confirm */ + +	FC_AUTH_MC_FCPAP_INIT 		= 0x16, /*! FCPAP Init */ +	FC_AUTH_MC_FCPAP_ACC 		= 0x17, /*! FCPAP Accept */ +	FC_AUTH_MC_FCPAP_COMP 		= 0x18, /*! FCPAP Complete */ + +	FC_AUTH_MC_IKE_SA_INIT 		= 0x22, /*! IKE SA INIT */ +	FC_AUTH_MC_IKE_SA_AUTH 		= 0x23, /*! IKE SA Auth */ +	FC_AUTH_MC_IKE_CREATE_CHILD_SA	= 0x24, /*! IKE Create Child SA */ +	FC_AUTH_MC_IKE_INFO 		= 0x25, /*! IKE informational */ +}; + +enum auth_proto_version{ +	FC_AUTH_PROTO_VER_1 	= 1,	/*! Protocol Version 1 */ +}; + +enum { +	FC_AUTH_ELS_COMMAND_CODE = 0x90,/*! Authentication ELS Command code  */ +	FC_AUTH_PROTO_PARAM_LEN_SZ = 4,	/*! Size of Proto Parameter Len Field */ +	FC_AUTH_PROTO_PARAM_VAL_SZ = 4,	/*! Size of Proto Parameter Val Field */ +	FC_MAX_AUTH_SECRET_LEN     = 256, +					/*! Maximum secret string length */ +	FC_AUTH_NUM_USABLE_PROTO_LEN_SZ = 4, +					/*! Size of usable protocols field */ +	FC_AUTH_RESP_VALUE_LEN_SZ	= 4, +					/*! Size of response value length */ +	FC_MAX_CHAP_KEY_LEN	= 256,	/*! Maximum md5 digest length */ +	FC_MAX_AUTH_RETRIES     = 3,	/*! Maximum number of retries */ +	FC_MD5_DIGEST_LEN       = 16,	/*! MD5 digest length */ +	FC_SHA1_DIGEST_LEN      = 20,	/*! SHA1 digest length */ +	FC_MAX_DHG_SUPPORTED    = 1,	/*! Maximum DH Groups supported */ +	FC_MAX_ALG_SUPPORTED    = 1,	/*! Maximum algorithms supported */ +	FC_MAX_PROTO_SUPPORTED  = 1,	/*! Maximum protocols supported */ +	FC_START_TXN_ID         = 2,	/*! Starting transaction ID */ +}; + +enum auth_proto_id{ +	FC_AUTH_PROTO_DHCHAP		= 0x00000001, +	FC_AUTH_PROTO_FCAP 		= 0x00000002, +	FC_AUTH_PROTO_FCPAP 		= 0x00000003, +	FC_AUTH_PROTO_IKEv2 		= 0x00000004, +	FC_AUTH_PROTO_IKEv2_AUTH 	= 0x00000005, +}; + +struct auth_name_s{ +	u16	name_tag;	/*! Name Tag = 1 for Authentication */ +	u16	name_len;	/*! Name Length = 8 for Authentication +					 */ +	wwn_t		name;  		/*! Name. TODO - is this PWWN */ +}; + + +enum auth_hash_func{ +	FC_AUTH_HASH_FUNC_MD5 		= 0x00000005, +	FC_AUTH_HASH_FUNC_SHA_1 	= 0x00000006, +}; + +enum auth_dh_gid{ +	FC_AUTH_DH_GID_0_DHG_NULL	= 0x00000000, +	FC_AUTH_DH_GID_1_DHG_1024	= 0x00000001, +	FC_AUTH_DH_GID_2_DHG_1280	= 0x00000002, +	FC_AUTH_DH_GID_3_DHG_1536	= 0x00000003, +	FC_AUTH_DH_GID_4_DHG_2048	= 0x00000004, +	FC_AUTH_DH_GID_6_DHG_3072	= 0x00000006, +	FC_AUTH_DH_GID_7_DHG_4096	= 0x00000007, +	FC_AUTH_DH_GID_8_DHG_6144	= 0x00000008, +	FC_AUTH_DH_GID_9_DHG_8192	= 0x00000009, +}; + +struct auth_els_msg_s { +	u8		auth_els_code;	/*  Authentication ELS Code (0x90) */ +	u8 	auth_els_flag; 	/*  Authentication ELS Flags */ +	u8 	auth_msg_code; 	/*  Authentication Message Code */ +	u8 	proto_version; 	/*  Protocol Version */ +	u32	msg_len; 	/*  Message Length */ +	u32	trans_id; 	/*  Transaction Identifier (T_ID) */ + +	/* Msg payload follows... */ +}; + + +enum auth_neg_param_tags { +	FC_AUTH_NEG_DHCHAP_HASHLIST 	= 0x0001, +	FC_AUTH_NEG_DHCHAP_DHG_ID_LIST 	= 0x0002, +}; + + +struct dhchap_param_format_s { +	u16	tag;		/*! Parameter Tag. See +					 * auth_neg_param_tags_t +					 */ +	u16	word_cnt; + +	/* followed by variable length parameter value... */ +}; + +struct auth_proto_params_s { +	u32	proto_param_len; +	u32	proto_id; + +	/* +	 * Followed by variable length Protocol specific parameters. DH-CHAP +	 * uses dhchap_param_format_t +	 */ +}; + +struct auth_neg_msg_s { +	struct auth_name_s	auth_ini_name; +	u32		usable_auth_protos; +	struct auth_proto_params_s proto_params[1]; /*! (1..usable_auth_proto) +						     * protocol params +						     */ +}; + +struct auth_dh_val_s { +	u32 dh_val_len; +	u32 dh_val[1]; +}; + +struct auth_dhchap_chal_msg_s { +	struct auth_els_msg_s	hdr; +	struct auth_name_s auth_responder_name;	/* TODO VRK - is auth_name_t +						 * type OK? +						 */ +	u32 	hash_id; +	u32 	dh_grp_id; +	u32 	chal_val_len; +	char		chal_val[1]; + +	/* ...followed by variable Challenge length/value and DH length/value */ +}; + + +enum auth_rjt_codes { +	FC_AUTH_RJT_CODE_AUTH_FAILURE 	= 0x01, +	FC_AUTH_RJT_CODE_LOGICAL_ERR	= 0x02, +}; + +enum auth_rjt_code_exps { +	FC_AUTH_CEXP_AUTH_MECH_NOT_USABLE	= 0x01, +	FC_AUTH_CEXP_DH_GROUP_NOT_USABLE 	= 0x02, +	FC_AUTH_CEXP_HASH_FUNC_NOT_USABLE 	= 0x03, +	FC_AUTH_CEXP_AUTH_XACT_STARTED		= 0x04, +	FC_AUTH_CEXP_AUTH_FAILED 		= 0x05, +	FC_AUTH_CEXP_INCORRECT_PLD 		= 0x06, +	FC_AUTH_CEXP_INCORRECT_PROTO_MSG 	= 0x07, +	FC_AUTH_CEXP_RESTART_AUTH_PROTO 	= 0x08, +	FC_AUTH_CEXP_AUTH_CONCAT_NOT_SUPP 	= 0x09, +	FC_AUTH_CEXP_PROTO_VER_NOT_SUPP 	= 0x0A, +}; + +enum auth_status { +	FC_AUTH_STATE_INPROGRESS = 0, 	/*! authentication in progress 	*/ +	FC_AUTH_STATE_FAILED	= 1, 	/*! authentication failed */ +	FC_AUTH_STATE_SUCCESS	= 2 	/*! authentication successful	*/ +}; + +struct auth_rjt_msg_s { +	struct auth_els_msg_s	hdr; +	u8		reason_code; +	u8		reason_code_exp; +	u8		rsvd[2]; +}; + + +struct auth_dhchap_neg_msg_s { +	struct auth_els_msg_s hdr; +	struct auth_neg_msg_s nego; +}; + +struct auth_dhchap_reply_msg_s { +	struct auth_els_msg_s	hdr; + +	/* +	 * followed by response value length & Value + DH Value Length & Value +	 */ +}; + +#pragma pack() + +#endif /* __FC_SP_H__ */ diff --git a/drivers/scsi/bfa/include/protocol/fcp.h b/drivers/scsi/bfa/include/protocol/fcp.h new file mode 100644 index 00000000000..9ade68ad285 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/fcp.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FCPPROTO_H__ +#define __FCPPROTO_H__ + +#include <protocol/scsi.h> + +#pragma pack(1) + +enum { +	FCP_RJT		= 0x01000000,	/* SRR reject */ +	FCP_SRR_ACCEPT	= 0x02000000,	/* SRR accept */ +	FCP_SRR		= 0x14000000,	/* Sequence Retransmission Request */ +}; + +/* + * SRR FC-4 LS payload + */ +struct fc_srr_s{ +	u32	ls_cmd; +	u32        ox_id:16;	/* ox-id */ +	u32        rx_id:16;	/* rx-id */ +	u32        ro;		/* relative offset */ +	u32        r_ctl:8;		/* R_CTL for I.U. */ +	u32        res:24; +}; + + +/* + * FCP_CMND definitions + */ +#define FCP_CMND_CDB_LEN    16 +#define FCP_CMND_LUN_LEN    8 + +struct fcp_cmnd_s{ +	lun_t           lun;		/* 64-bit LU number */ +	u8         crn;		/* command reference number */ +#ifdef __BIGENDIAN +	u8         resvd:1, +			priority:4,	/* FCP-3: SAM-3 priority */ +			taskattr:3;	/* scsi task attribute */ +#else +	u8         taskattr:3,	/* scsi task attribute */ +			priority:4,	/* FCP-3: SAM-3 priority */ +			resvd:1; +#endif +	u8         tm_flags;	/* task management flags */ +#ifdef __BIGENDIAN +	u8         addl_cdb_len:6,	/* additional CDB length words */ +			iodir:2;	/* read/write FCP_DATA IUs */ +#else +	u8         iodir:2,	/* read/write FCP_DATA IUs */ +			addl_cdb_len:6;	/* additional CDB length */ +#endif +	struct scsi_cdb_s      cdb; + +	/* +	 * !!! additional cdb bytes follows here!!! +	 */ +	u32        fcp_dl;	/* bytes to be transferred */ +}; + +#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN) +#define fcp_cmnd_fcpdl(_cmnd)	((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len]) + +/* + * fcp_cmnd_t.iodir field values + */ +enum fcp_iodir{ +	FCP_IODIR_NONE	= 0, +	FCP_IODIR_WRITE = 1, +	FCP_IODIR_READ	= 2, +	FCP_IODIR_RW	= 3, +}; + +/* + * Task attribute field + */ +enum { +	FCP_TASK_ATTR_SIMPLE	= 0, +	FCP_TASK_ATTR_HOQ	= 1, +	FCP_TASK_ATTR_ORDERED	= 2, +	FCP_TASK_ATTR_ACA	= 4, +	FCP_TASK_ATTR_UNTAGGED	= 5,	/* obsolete in FCP-3 */ +}; + +/* + * Task management flags field - only one bit shall be set + */ +#ifndef BIT +#define BIT(_x)	(1 << (_x)) +#endif +enum fcp_tm_cmnd{ +	FCP_TM_ABORT_TASK_SET	= BIT(1), +	FCP_TM_CLEAR_TASK_SET	= BIT(2), +	FCP_TM_LUN_RESET	= BIT(4), +	FCP_TM_TARGET_RESET	= BIT(5),	/* obsolete in FCP-3 */ +	FCP_TM_CLEAR_ACA	= BIT(6), +}; + +/* + * FCP_XFER_RDY IU defines + */ +struct fcp_xfer_rdy_s{ +	u32        data_ro; +	u32        burst_len; +	u32        reserved; +}; + +/* + * FCP_RSP residue flags + */ +enum fcp_residue{ +	FCP_NO_RESIDUE = 0,	/* no residue */ +	FCP_RESID_OVER = 1,	/* more data left that was not sent */ +	FCP_RESID_UNDER = 2,	/* less data than requested */ +}; + +enum { +	FCP_RSPINFO_GOOD = 0, +	FCP_RSPINFO_DATALEN_MISMATCH = 1, +	FCP_RSPINFO_CMND_INVALID = 2, +	FCP_RSPINFO_ROLEN_MISMATCH = 3, +	FCP_RSPINFO_TM_NOT_SUPP = 4, +	FCP_RSPINFO_TM_FAILED = 5, +}; + +struct fcp_rspinfo_s{ +	u32        res0:24; +	u32        rsp_code:8;	/* response code (as above) */ +	u32        res1; +}; + +struct fcp_resp_s{ +	u32        reserved[2];	/* 2 words reserved */ +	u16        reserved2; +#ifdef __BIGENDIAN +	u8         reserved3:3; +	u8         fcp_conf_req:1;	/* FCP_CONF is requested */ +	u8         resid_flags:2;	/* underflow/overflow */ +	u8         sns_len_valid:1;/* sense len is valid */ +	u8         rsp_len_valid:1;/* response len is valid */ +#else +	u8         rsp_len_valid:1;/* response len is valid */ +	u8         sns_len_valid:1;/* sense len is valid */ +	u8         resid_flags:2;	/* underflow/overflow */ +	u8         fcp_conf_req:1;	/* FCP_CONF is requested */ +	u8         reserved3:3; +#endif +	u8         scsi_status;	/* one byte SCSI status */ +	u32        residue;	/* residual data bytes */ +	u32        sns_len;	/* length od sense info */ +	u32        rsp_len;	/* length of response info */ +}; + +#define fcp_snslen(__fcprsp)	((__fcprsp)->sns_len_valid ? 		\ +					(__fcprsp)->sns_len : 0) +#define fcp_rsplen(__fcprsp)	((__fcprsp)->rsp_len_valid ? 		\ +					(__fcprsp)->rsp_len : 0) +#define fcp_rspinfo(__fcprsp)	((struct fcp_rspinfo_s *)((__fcprsp) + 1)) +#define fcp_snsinfo(__fcprsp)	(((u8 *)fcp_rspinfo(__fcprsp)) + 	\ +						fcp_rsplen(__fcprsp)) + +struct fcp_cmnd_fr_s{ +	struct fchs_s          fchs; +	struct fcp_cmnd_s      fcp; +}; + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/include/protocol/fdmi.h b/drivers/scsi/bfa/include/protocol/fdmi.h new file mode 100644 index 00000000000..6c05c268c71 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/fdmi.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __FDMI_H__ +#define __FDMI_H__ + +#include <protocol/types.h> +#include <protocol/fc.h> +#include <protocol/ct.h> + +#pragma pack(1) + +/* + * FDMI Command Codes + */ +#define	FDMI_GRHL		0x0100 +#define	FDMI_GHAT		0x0101 +#define	FDMI_GRPL		0x0102 +#define	FDMI_GPAT		0x0110 +#define	FDMI_RHBA		0x0200 +#define	FDMI_RHAT		0x0201 +#define	FDMI_RPRT		0x0210 +#define	FDMI_RPA		0x0211 +#define	FDMI_DHBA		0x0300 +#define	FDMI_DPRT		0x0310 + +/* + * FDMI reason codes + */ +#define	FDMI_NO_ADDITIONAL_EXP		0x00 +#define	FDMI_HBA_ALREADY_REG		0x10 +#define	FDMI_HBA_ATTRIB_NOT_REG		0x11 +#define	FDMI_HBA_ATTRIB_MULTIPLE	0x12 +#define	FDMI_HBA_ATTRIB_LENGTH_INVALID	0x13 +#define	FDMI_HBA_ATTRIB_NOT_PRESENT	0x14 +#define	FDMI_PORT_ORIG_NOT_IN_LIST	0x15 +#define	FDMI_PORT_HBA_NOT_IN_LIST	0x16 +#define	FDMI_PORT_ATTRIB_NOT_REG	0x20 +#define	FDMI_PORT_NOT_REG		0x21 +#define	FDMI_PORT_ATTRIB_MULTIPLE	0x22 +#define	FDMI_PORT_ATTRIB_LENGTH_INVALID	0x23 +#define	FDMI_PORT_ALREADY_REGISTEREED	0x24 + +/* + * FDMI Transmission Speed Mask values + */ +#define	FDMI_TRANS_SPEED_1G		0x00000001 +#define	FDMI_TRANS_SPEED_2G		0x00000002 +#define	FDMI_TRANS_SPEED_10G		0x00000004 +#define	FDMI_TRANS_SPEED_4G		0x00000008 +#define	FDMI_TRANS_SPEED_8G		0x00000010 +#define	FDMI_TRANS_SPEED_16G		0x00000020 +#define	FDMI_TRANS_SPEED_UNKNOWN	0x00008000 + +/* + * FDMI HBA attribute types + */ +enum fdmi_hba_attribute_type { +	FDMI_HBA_ATTRIB_NODENAME = 1,	/* 0x0001 */ +	FDMI_HBA_ATTRIB_MANUFACTURER,	/* 0x0002 */ +	FDMI_HBA_ATTRIB_SERIALNUM,	/* 0x0003 */ +	FDMI_HBA_ATTRIB_MODEL,		/* 0x0004 */ +	FDMI_HBA_ATTRIB_MODEL_DESC,	/* 0x0005 */ +	FDMI_HBA_ATTRIB_HW_VERSION,	/* 0x0006 */ +	FDMI_HBA_ATTRIB_DRIVER_VERSION,	/* 0x0007 */ +	FDMI_HBA_ATTRIB_ROM_VERSION,	/* 0x0008 */ +	FDMI_HBA_ATTRIB_FW_VERSION,	/* 0x0009 */ +	FDMI_HBA_ATTRIB_OS_NAME,	/* 0x000A */ +	FDMI_HBA_ATTRIB_MAX_CT,		/* 0x000B */ + +	FDMI_HBA_ATTRIB_MAX_TYPE +}; + +/* + * FDMI Port attribute types + */ +enum fdmi_port_attribute_type { +	FDMI_PORT_ATTRIB_FC4_TYPES = 1,	/* 0x0001 */ +	FDMI_PORT_ATTRIB_SUPP_SPEED,	/* 0x0002 */ +	FDMI_PORT_ATTRIB_PORT_SPEED,	/* 0x0003 */ +	FDMI_PORT_ATTRIB_FRAME_SIZE,	/* 0x0004 */ +	FDMI_PORT_ATTRIB_DEV_NAME,	/* 0x0005 */ +	FDMI_PORT_ATTRIB_HOST_NAME,	/* 0x0006 */ + +	FDMI_PORT_ATTR_MAX_TYPE +}; + +/* + * FDMI attribute + */ +struct fdmi_attr_s { +	u16        type; +	u16        len; +	u8         value[1]; +}; + +/* + * HBA Attribute Block + */ +struct fdmi_hba_attr_s { +	u32        attr_count;	/* # of attributes */ +	struct fdmi_attr_s     hba_attr;	/* n attributes */ +}; + +/* + * Registered Port List + */ +struct fdmi_port_list_s { +	u32        num_ports;	/* number Of Port Entries */ +	wwn_t           port_entry;	/* one or more */ +}; + +/* + * Port Attribute Block + */ +struct fdmi_port_attr_s { +	u32        attr_count;	/* # of attributes */ +	struct fdmi_attr_s     port_attr;	/* n attributes */ +}; + +/* + * FDMI Register HBA Attributes + */ +struct fdmi_rhba_s { +	wwn_t           hba_id;		/* HBA Identifier */ +	struct fdmi_port_list_s port_list;	/* Registered Port List */ +	struct fdmi_hba_attr_s hba_attr_blk;	/* HBA attribute block */ +}; + +/* + * FDMI Register Port + */ +struct fdmi_rprt_s { +	wwn_t           hba_id;		/* HBA Identifier */ +	wwn_t           port_name;	/* Port wwn */ +	struct fdmi_port_attr_s port_attr_blk;	/* Port Attr Block */ +}; + +/* + * FDMI Register Port Attributes + */ +struct fdmi_rpa_s { +	wwn_t           port_name;	/* port wwn */ +	struct fdmi_port_attr_s port_attr_blk;	/* Port Attr Block */ +}; + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/include/protocol/pcifw.h b/drivers/scsi/bfa/include/protocol/pcifw.h new file mode 100644 index 00000000000..6830dc3ee58 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/pcifw.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  pcifw.h PCI FW related headers + */ + +#ifndef __PCIFW_H__ +#define __PCIFW_H__ + +#pragma pack(1) + +struct pnp_hdr_s{ +  u32	signature;	/* "$PnP" */ +  u8	rev;		/* Struct revision */ +  u8 	len;		/* Header structure len in multiples +				 * of 16 bytes */ +  u16  off;		/* Offset to next header 00 if none */ +  u8	rsvd;		/* Reserved byte */ +  u8	cksum;		/* 8-bit checksum for this header */ +  u32	pnp_dev_id;	/* PnP Device Id */ +  u16  mfstr;		/* Pointer to manufacturer string */ +  u16	prstr;		/* Pointer to product string */ +  u8	devtype[3];	/* Device Type Code */ +  u8	devind;		/* Device Indicator */ +  u16	bcventr;	/* Bootstrap entry vector */ +  u16	rsvd2;		/* Reserved */ +  u16  sriv;		/* Static resource information vector */ +}; + +struct pci_3_0_ds_s{ + u32	sig;   		/* Signature "PCIR" */ + u16	vendid;		/* Vendor ID */ + u16	devid;		/* Device ID */ + u16	devlistoff;	/* Device List Offset */ + u16	len;		/* PCI Data Structure Length */ + u8	rev;		/* PCI Data Structure Revision */ + u8	clcode[3];	/* Class Code */ + u16	imglen;		/* Code image length in multiples of +				 * 512 bytes */ + u16	coderev;	/* Revision level of code/data */ + u8	codetype;	/* Code type 0x00 - BIOS */ + u8	indr;		/* Last image indicator */ + u16	mrtimglen;	/* Max Run Time Image Length */ + u16	cuoff;		/* Config Utility Code Header Offset */ + u16	dmtfclp;	/* DMTF CLP entry point offset */ +}; + +struct pci_optrom_hdr_s{ + u16	sig;		/* Signature 0x55AA */ + u8	len;		/* Option ROM length in units of 512 bytes */ + u8	inivec[3];	/* Initialization vector */ + u8	rsvd[16];	/* Reserved field */ + u16	verptr;		/* Pointer to version string - private */ + u16	pcids;		/* Pointer to PCI data structure */ + u16	pnphdr;		/* Pointer to PnP expansion header */ +}; + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/include/protocol/scsi.h b/drivers/scsi/bfa/include/protocol/scsi.h new file mode 100644 index 00000000000..b220e6b4f6e --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/scsi.h @@ -0,0 +1,1648 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __SCSI_H__ +#define __SCSI_H__ + +#include <protocol/types.h> + +#pragma pack(1) + +/* + * generic SCSI cdb definition + */ +#define SCSI_MAX_CDBLEN     16 +struct scsi_cdb_s{ +	u8         scsi_cdb[SCSI_MAX_CDBLEN]; +}; + +/* + * scsi lun serial number definition + */ +#define SCSI_LUN_SN_LEN     32 +struct scsi_lun_sn_s{ +	u8         lun_sn[SCSI_LUN_SN_LEN]; +}; + +/* + * SCSI Direct Access Commands + */ +enum { +	SCSI_OP_TEST_UNIT_READY		= 0x00, +	SCSI_OP_REQUEST_SENSE		= 0x03, +	SCSI_OP_FORMAT_UNIT		= 0x04, +	SCSI_OP_READ6			= 0x08, +	SCSI_OP_WRITE6			= 0x0A, +	SCSI_OP_WRITE_FILEMARKS		= 0x10, +	SCSI_OP_INQUIRY			= 0x12, +	SCSI_OP_MODE_SELECT6		= 0x15, +	SCSI_OP_RESERVE6		= 0x16, +	SCSI_OP_RELEASE6		= 0x17, +	SCSI_OP_MODE_SENSE6		= 0x1A, +	SCSI_OP_START_STOP_UNIT		= 0x1B, +	SCSI_OP_SEND_DIAGNOSTIC		= 0x1D, +	SCSI_OP_READ_CAPACITY		= 0x25, +	SCSI_OP_READ10			= 0x28, +	SCSI_OP_WRITE10			= 0x2A, +	SCSI_OP_VERIFY10		= 0x2F, +	SCSI_OP_READ_DEFECT_DATA	= 0x37, +	SCSI_OP_LOG_SELECT		= 0x4C, +	SCSI_OP_LOG_SENSE		= 0x4D, +	SCSI_OP_MODE_SELECT10		= 0x55, +	SCSI_OP_RESERVE10		= 0x56, +	SCSI_OP_RELEASE10		= 0x57, +	SCSI_OP_MODE_SENSE10		= 0x5A, +	SCSI_OP_PER_RESERVE_IN		= 0x5E, +	SCSI_OP_PER_RESERVE_OUR		= 0x5E, +	SCSI_OP_READ16			= 0x88, +	SCSI_OP_WRITE16			= 0x8A, +	SCSI_OP_VERIFY16		= 0x8F, +	SCSI_OP_READ_CAPACITY16		= 0x9E, +	SCSI_OP_REPORT_LUNS		= 0xA0, +	SCSI_OP_READ12			= 0xA8, +	SCSI_OP_WRITE12			= 0xAA, +	SCSI_OP_UNDEF			= 0xFF, +}; + +/* + * SCSI START_STOP_UNIT command + */ +struct scsi_start_stop_unit_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         reserved1:4; +	u8         immed:1; +#else +	u8         immed:1; +	u8         reserved1:4; +	u8         lun:3; +#endif +	u8         reserved2; +	u8         reserved3; +#ifdef __BIGENDIAN +	u8         power_conditions:4; +	u8         reserved4:2; +	u8         loEj:1; +	u8         start:1; +#else +	u8         start:1; +	u8         loEj:1; +	u8         reserved4:2; +	u8         power_conditions:4; +#endif +	u8         control; +}; + +/* + * SCSI SEND_DIAGNOSTIC command + */ +struct scsi_send_diagnostic_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         self_test_code:3; +	u8         pf:1; +	u8         reserved1:1; +	u8         self_test:1; +	u8         dev_offl:1; +	u8         unit_offl:1; +#else +	u8         unit_offl:1; +	u8         dev_offl:1; +	u8         self_test:1; +	u8         reserved1:1; +	u8         pf:1; +	u8         self_test_code:3; +#endif +	u8         reserved2; + +	u8         param_list_length[2];	/* MSB first */ +	u8         control; + +}; + +/* + * SCSI READ10/WRITE10 commands + */ +struct scsi_rw10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         dpo:1;	/* Disable Page Out */ +	u8         fua:1;	/* Force Unit Access */ +	u8         reserved1:2; +	u8         rel_adr:1;	/* relative address */ +#else +	u8         rel_adr:1; +	u8         reserved1:2; +	u8         fua:1; +	u8         dpo:1; +	u8         lun:3; +#endif +	u8         lba0;	/* logical block address - MSB */ +	u8         lba1; +	u8         lba2; +	u8         lba3;	/* LSB */ +	u8         reserved3; +	u8         xfer_length0;	/* transfer length in blocks - MSB */ +	u8         xfer_length1;	/* LSB */ +	u8         control; +}; + +#define SCSI_CDB10_GET_LBA(cdb)                     \ +    (((cdb)->lba0 << 24) | ((cdb)->lba1 << 16) |    \ +     ((cdb)->lba2 << 8) | (cdb)->lba3) + +#define SCSI_CDB10_SET_LBA(cdb, lba) {      \ +    (cdb)->lba0 = lba >> 24;            \ +    (cdb)->lba1 = (lba >> 16) & 0xFF;   \ +    (cdb)->lba2 = (lba >> 8) & 0xFF;    \ +    (cdb)->lba3 = lba & 0xFF;           \ +} + +#define SCSI_CDB10_GET_TL(cdb)  \ +    ((cdb)->xfer_length0 << 8 | (cdb)->xfer_length1) +#define SCSI_CDB10_SET_TL(cdb, tl) {      \ +    (cdb)->xfer_length0 = tl >> 8;       \ +    (cdb)->xfer_length1 = tl & 0xFF;     \ +} + +/* + * SCSI READ6/WRITE6 commands + */ +struct scsi_rw6_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         lba0:5;		/* MSb */ +#else +	u8         lba0:5;		/* MSb */ +	u8         lun:3; +#endif +	u8         lba1; +	u8         lba2;		/* LSB */ +	u8         xfer_length; +	u8         control; +}; + +#define SCSI_TAPE_CDB6_GET_TL(cdb)              \ +    (((cdb)->tl0 << 16) | ((cdb)->tl1 << 8) | (cdb)->tl2) + +#define SCSI_TAPE_CDB6_SET_TL(cdb, tl) {      \ +    (cdb)->tl0 = tl >> 16;            \ +    (cdb)->tl1 = (tl >> 8) & 0xFF;    \ +    (cdb)->tl2 = tl & 0xFF;           \ +} + +/* + * SCSI sequential (TAPE) wrtie command + */ +struct scsi_tape_wr_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         rsvd:7; +	u8         fixed:1;	/* MSb */ +#else +	u8         fixed:1;	/* MSb */ +	u8         rsvd:7; +#endif +	u8         tl0;		/* Msb */ +	u8         tl1; +	u8         tl2;		/* Lsb */ + +	u8         control; +}; + +#define SCSI_CDB6_GET_LBA(cdb)              \ +    (((cdb)->lba0 << 16) | ((cdb)->lba1 << 8) | (cdb)->lba2) + +#define SCSI_CDB6_SET_LBA(cdb, lba) {      \ +    (cdb)->lba0 = lba >> 16;            \ +    (cdb)->lba1 = (lba >> 8) & 0xFF;    \ +    (cdb)->lba2 = lba & 0xFF;           \ +} + +#define SCSI_CDB6_GET_TL(cdb) ((cdb)->xfer_length) +#define SCSI_CDB6_SET_TL(cdb, tl) {      \ +    (cdb)->xfer_length = tl;         \ +} + +/* + * SCSI sense data format + */ +struct scsi_sense_s{ +#ifdef __BIGENDIAN +	u8         valid:1; +	u8         rsp_code:7; +#else +	u8         rsp_code:7; +	u8         valid:1; +#endif +	u8         seg_num; +#ifdef __BIGENDIAN +	u8         file_mark:1; +	u8         eom:1;		/* end of media */ +	u8         ili:1;		/* incorrect length indicator */ +	u8         reserved:1; +	u8         sense_key:4; +#else +	u8         sense_key:4; +	u8         reserved:1; +	u8         ili:1;		/* incorrect length indicator */ +	u8         eom:1;		/* end of media */ +	u8         file_mark:1; +#endif +	u8         information[4];	/* device-type or command specific info +					 */ +	u8         add_sense_length; +					/* additional sense length */ +	u8         command_info[4];/* command specific information +						 */ +	u8         asc;		/* additional sense code */ +	u8         ascq;		/* additional sense code qualifier */ +	u8         fru_code;	/* field replaceable unit code */ +#ifdef __BIGENDIAN +	u8         sksv:1;		/* sense key specific valid */ +	u8         c_d:1;		/* command/data bit */ +	u8         res1:2; +	u8         bpv:1;		/* bit pointer valid */ +	u8         bpointer:3;	/* bit pointer */ +#else +	u8         bpointer:3;	/* bit pointer */ +	u8         bpv:1;		/* bit pointer valid */ +	u8         res1:2; +	u8         c_d:1;		/* command/data bit */ +	u8         sksv:1;		/* sense key specific valid */ +#endif +	u8         fpointer[2];	/* field pointer */ +}; + +#define SCSI_SENSE_CUR_ERR          0x70 +#define SCSI_SENSE_DEF_ERR          0x71 + +/* + * SCSI sense key values + */ +#define SCSI_SK_NO_SENSE        0x0 +#define SCSI_SK_REC_ERR         0x1	/* recovered error */ +#define SCSI_SK_NOT_READY       0x2 +#define SCSI_SK_MED_ERR         0x3	/* medium error */ +#define SCSI_SK_HW_ERR          0x4	/* hardware error */ +#define SCSI_SK_ILLEGAL_REQ     0x5 +#define SCSI_SK_UNIT_ATT        0x6	/* unit attention */ +#define SCSI_SK_DATA_PROTECT    0x7 +#define SCSI_SK_BLANK_CHECK     0x8 +#define SCSI_SK_VENDOR_SPEC     0x9 +#define SCSI_SK_COPY_ABORTED    0xA +#define SCSI_SK_ABORTED_CMND    0xB +#define SCSI_SK_VOL_OVERFLOW    0xD +#define SCSI_SK_MISCOMPARE      0xE + +/* + * SCSI additional sense codes + */ +#define SCSI_ASC_NO_ADD_SENSE           0x00 +#define SCSI_ASC_LUN_NOT_READY          0x04 +#define SCSI_ASC_LUN_COMMUNICATION      0x08 +#define SCSI_ASC_WRITE_ERROR            0x0C +#define SCSI_ASC_INVALID_CMND_CODE      0x20 +#define SCSI_ASC_BAD_LBA                0x21 +#define SCSI_ASC_INVALID_FIELD_IN_CDB   0x24 +#define SCSI_ASC_LUN_NOT_SUPPORTED      0x25 +#define SCSI_ASC_LUN_WRITE_PROTECT      0x27 +#define SCSI_ASC_POWERON_BDR            0x29	/* power on reset, bus reset, +						 * bus device reset +						 */ +#define SCSI_ASC_PARAMS_CHANGED         0x2A +#define SCSI_ASC_CMND_CLEARED_BY_A_I    0x2F +#define SCSI_ASC_SAVING_PARAM_NOTSUPP   0x39 +#define SCSI_ASC_TOCC                   0x3F	/* target operating condtions +						 * changed +						 */ +#define SCSI_ASC_PARITY_ERROR           0x47 +#define SCSI_ASC_CMND_PHASE_ERROR       0x4A +#define SCSI_ASC_DATA_PHASE_ERROR       0x4B +#define SCSI_ASC_VENDOR_SPEC            0x7F + +/* + * SCSI additional sense code qualifiers + */ +#define SCSI_ASCQ_CAUSE_NOT_REPORT      0x00 +#define SCSI_ASCQ_BECOMING_READY        0x01 +#define SCSI_ASCQ_INIT_CMD_REQ          0x02 +#define SCSI_ASCQ_FORMAT_IN_PROGRESS    0x04 +#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07 +#define SCSI_ASCQ_SELF_TEST_IN_PROGRESS 0x09 +#define SCSI_ASCQ_WR_UNEXP_UNSOL_DATA   0x0C +#define SCSI_ASCQ_WR_NOTENG_UNSOL_DATA  0x0D + +#define SCSI_ASCQ_LBA_OUT_OF_RANGE      0x00 +#define SCSI_ASCQ_INVALID_ELEMENT_ADDR  0x01 + +#define SCSI_ASCQ_LUN_WRITE_PROTECTED       0x00 +#define SCSI_ASCQ_LUN_HW_WRITE_PROTECTED    0x01 +#define SCSI_ASCQ_LUN_SW_WRITE_PROTECTED    0x02 + +#define SCSI_ASCQ_POR   0x01	/* power on reset */ +#define SCSI_ASCQ_SBR   0x02	/* scsi bus reset */ +#define SCSI_ASCQ_BDR   0x03	/* bus device reset */ +#define SCSI_ASCQ_DIR   0x04	/* device internal reset */ + +#define SCSI_ASCQ_MODE_PARAMS_CHANGED       0x01 +#define SCSI_ASCQ_LOG_PARAMS_CHANGED        0x02 +#define SCSI_ASCQ_RESERVATIONS_PREEMPTED    0x03 +#define SCSI_ASCQ_RESERVATIONS_RELEASED     0x04 +#define SCSI_ASCQ_REGISTRATIONS_PREEMPTED   0x05 + +#define SCSI_ASCQ_MICROCODE_CHANGED 0x01 +#define SCSI_ASCQ_CHANGED_OPER_COND 0x02 +#define SCSI_ASCQ_INQ_CHANGED       0x03	/* inquiry data changed */ +#define SCSI_ASCQ_DI_CHANGED        0x05	/* device id changed */ +#define SCSI_ASCQ_RL_DATA_CHANGED   0x0E	/* report luns data changed */ + +#define SCSI_ASCQ_DP_CRC_ERR            0x01	/* data phase crc error */ +#define SCSI_ASCQ_DP_SCSI_PARITY_ERR    0x02	/* data phase scsi parity error +						 */ +#define SCSI_ASCQ_IU_CRC_ERR            0x03	/* information unit crc error */ +#define SCSI_ASCQ_PROTO_SERV_CRC_ERR    0x05 + +#define SCSI_ASCQ_LUN_TIME_OUT          0x01 + +/* ------------------------------------------------------------ + * SCSI INQUIRY + * ------------------------------------------------------------*/ + +struct scsi_inquiry_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         reserved1:3; +	u8         cmd_dt:1; +	u8         evpd:1; +#else +	u8         evpd:1; +	u8         cmd_dt:1; +	u8         reserved1:3; +	u8         lun:3; +#endif +	u8         page_code; +	u8         reserved2; +	u8         alloc_length; +	u8         control; +}; + +struct scsi_inquiry_vendor_s{ +	u8         vendor_id[8]; +}; + +struct scsi_inquiry_prodid_s{ +	u8         product_id[16]; +}; + +struct scsi_inquiry_prodrev_s{ +	u8         product_rev[4]; +}; + +struct scsi_inquiry_data_s{ +#ifdef __BIGENDIAN +	u8         peripheral_qual:3;	/* peripheral qualifier */ +	u8         device_type:5;		/* peripheral device type */ + +	u8         rmb:1;			/* removable medium bit */ +	u8         device_type_mod:7;	/* device type modifier */ + +	u8         version; + +	u8         aenc:1;		/* async event notification capability +					 */ +	u8         trm_iop:1;	/* terminate I/O process */ +	u8         norm_aca:1;	/* normal ACA supported */ +	u8         hi_support:1;	/* SCSI-3: supports REPORT LUNS */ +	u8         rsp_data_format:4; + +	u8         additional_len; +	u8         sccs:1; +	u8         reserved1:7; + +	u8         reserved2:1; +	u8         enc_serv:1;	/* enclosure service component */ +	u8         reserved3:1; +	u8         multi_port:1;	/* multi-port device */ +	u8         m_chngr:1;	/* device in medium transport element */ +	u8         ack_req_q:1;	/* SIP specific bit */ +	u8         addr32:1;	/* SIP specific bit */ +	u8         addr16:1;	/* SIP specific bit */ + +	u8         rel_adr:1;	/* relative address */ +	u8         w_bus32:1; +	u8         w_bus16:1; +	u8         synchronous:1; +	u8         linked_commands:1; +	u8         trans_dis:1; +	u8         cmd_queue:1;	/* command queueing supported */ +	u8         soft_reset:1;	/* soft reset alternative (VS) */ +#else +	u8         device_type:5;	/* peripheral device type */ +	u8         peripheral_qual:3; +					/* peripheral qualifier */ + +	u8         device_type_mod:7; +					/* device type modifier */ +	u8         rmb:1;		/* removable medium bit */ + +	u8         version; + +	u8         rsp_data_format:4; +	u8         hi_support:1;	/* SCSI-3: supports REPORT LUNS */ +	u8         norm_aca:1;	/* normal ACA supported */ +	u8         terminate_iop:1;/* terminate I/O process */ +	u8         aenc:1;		/* async event notification capability +					 */ + +	u8         additional_len; +	u8         reserved1:7; +	u8         sccs:1; + +	u8         addr16:1;	/* SIP specific bit */ +	u8         addr32:1;	/* SIP specific bit */ +	u8         ack_req_q:1;	/* SIP specific bit */ +	u8         m_chngr:1;	/* device in medium transport element */ +	u8         multi_port:1;	/* multi-port device */ +	u8         reserved3:1;	/* TBD - Vendor Specific */ +	u8         enc_serv:1;	/* enclosure service component */ +	u8         reserved2:1; + +	u8         soft_seset:1;	/* soft reset alternative (VS) */ +	u8         cmd_queue:1;	/* command queueing supported */ +	u8         trans_dis:1; +	u8         linked_commands:1; +	u8         synchronous:1; +	u8         w_bus16:1; +	u8         w_bus32:1; +	u8         rel_adr:1;	/* relative address */ +#endif +	struct scsi_inquiry_vendor_s vendor_id; +	struct scsi_inquiry_prodid_s product_id; +	struct scsi_inquiry_prodrev_s product_rev; +	u8         vendor_specific[20]; +	u8         reserved4[40]; +}; + +/* + * inquiry.peripheral_qual field values + */ +#define SCSI_DEVQUAL_DEFAULT        0 +#define SCSI_DEVQUAL_NOT_CONNECTED  1 +#define SCSI_DEVQUAL_NOT_SUPPORTED  3 + +/* + * inquiry.device_type field values + */ +#define SCSI_DEVICE_DIRECT_ACCESS       0x00 +#define SCSI_DEVICE_SEQ_ACCESS          0x01 +#define SCSI_DEVICE_ARRAY_CONTROLLER    0x0C +#define SCSI_DEVICE_UNKNOWN             0x1F + +/* + * inquiry.version + */ +#define SCSI_VERSION_ANSI_X3131     2	/* ANSI X3.131 SCSI-2 */ +#define SCSI_VERSION_SPC            3	/* SPC (SCSI-3), ANSI X3.301:1997 */ +#define SCSI_VERSION_SPC_2          4	/* SPC-2 */ + +/* + * response data format + */ +#define SCSI_RSP_DATA_FORMAT        2	/* SCSI-2 & SPC */ + +/* + * SCSI inquiry page codes + */ +#define SCSI_INQ_PAGE_VPD_PAGES     0x00	/* supported vpd pages */ +#define SCSI_INQ_PAGE_USN_PAGE      0x80	/* unit serial number page */ +#define SCSI_INQ_PAGE_DEV_IDENT     0x83	/* device indentification page +						 */ +#define SCSI_INQ_PAGES_MAX          3 + +/* + * supported vital product data pages + */ +struct scsi_inq_page_vpd_pages_s{ +#ifdef __BIGENDIAN +	u8         peripheral_qual:3; +	u8         device_type:5; +#else +	u8         device_type:5; +	u8         peripheral_qual:3; +#endif +	u8         page_code; +	u8         reserved; +	u8         page_length; +	u8         pages[SCSI_INQ_PAGES_MAX]; +}; + +/* + * Unit serial number page + */ +#define SCSI_INQ_USN_LEN 32 + +struct scsi_inq_usn_s{ +	char            usn[SCSI_INQ_USN_LEN]; +}; + +struct scsi_inq_page_usn_s{ +#ifdef __BIGENDIAN +	u8         peripheral_qual:3; +	u8         device_type:5; +#else +	u8         device_type:5; +	u8         peripheral_qual:3; +#endif +	u8         page_code; +	u8         reserved1; +	u8         page_length; +	struct scsi_inq_usn_s  usn; +}; + +enum { +	SCSI_INQ_DIP_CODE_BINARY = 1,	/* identifier has binary value */ +	SCSI_INQ_DIP_CODE_ASCII = 2,	/* identifier has ascii value */ +}; + +enum { +	SCSI_INQ_DIP_ASSOC_LUN = 0,	/* id is associated with device */ +	SCSI_INQ_DIP_ASSOC_PORT = 1,	/* id is associated with port that +					 * received the request +					 */ +}; + +enum { +	SCSI_INQ_ID_TYPE_VENDOR = 1, +	SCSI_INQ_ID_TYPE_IEEE = 2, +	SCSI_INQ_ID_TYPE_FC_FS = 3, +	SCSI_INQ_ID_TYPE_OTHER = 4, +}; + +struct scsi_inq_dip_desc_s{ +#ifdef __BIGENDIAN +	u8         res0:4; +	u8         code_set:4; +	u8         res1:2; +	u8         association:2; +	u8         id_type:4; +#else +	u8         code_set:4; +	u8         res0:4; +	u8         id_type:4; +	u8         association:2; +	u8         res1:2; +#endif +	u8         res2; +	u8         id_len; +	struct scsi_lun_sn_s   id; +}; + +/* + * Device indentification page + */ +struct scsi_inq_page_dev_ident_s{ +#ifdef __BIGENDIAN +	u8         peripheral_qual:3; +	u8         device_type:5; +#else +	u8         device_type:5; +	u8         peripheral_qual:3; +#endif +	u8         page_code; +	u8         reserved1; +	u8         page_length; +	struct scsi_inq_dip_desc_s desc; +}; + +/* ------------------------------------------------------------ + * READ CAPACITY + * ------------------------------------------------------------ + */ + +struct scsi_read_capacity_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         reserved1:4; +	u8         rel_adr:1; +#else +	u8         rel_adr:1; +	u8         reserved1:4; +	u8         lun:3; +#endif +	u8         lba0;	/* MSB */ +	u8         lba1; +	u8         lba2; +	u8         lba3;	/* LSB */ +	u8         reserved2; +	u8         reserved3; +#ifdef __BIGENDIAN +	u8         reserved4:7; +	u8         pmi:1;	/* partial medium indicator */ +#else +	u8         pmi:1;	/* partial medium indicator */ +	u8         reserved4:7; +#endif +	u8         control; +}; + +struct scsi_read_capacity_data_s{ +	u32        max_lba;	/* maximum LBA available */ +	u32        block_length;	/* in bytes */ +}; + +struct scsi_read_capacity16_data_s{ +	u64        lba;	/* maximum LBA available */ +	u32        block_length;	/* in bytes */ +#ifdef __BIGENDIAN +	u8         reserved1:4, +			p_type:3, +			prot_en:1; +	u8		reserved2:4, +			lb_pbe:4;	/* logical blocks per physical block +					 * exponent */ +	u16	reserved3:2, +			lba_align:14;	/* lowest aligned logical block +					 * address */ +#else +	u16	lba_align:14,	/* lowest aligned logical block +					 * address */ +			reserved3:2; +	u8		lb_pbe:4,	/* logical blocks per physical block +					 * exponent */ +			reserved2:4; +	u8		prot_en:1, +			p_type:3, +			reserved1:4; +#endif +	u64	reserved4; +	u64	reserved5; +}; + +/* ------------------------------------------------------------ + * REPORT LUNS command + * ------------------------------------------------------------ + */ + +struct scsi_report_luns_s{ +	u8         opcode;		/* A0h - REPORT LUNS opCode */ +	u8         reserved1[5]; +	u8         alloc_length[4];/* allocation length MSB first */ +	u8         reserved2; +	u8         control; +}; + +#define SCSI_REPORT_LUN_ALLOC_LENGTH(rl)                		\ +    ((rl->alloc_length[0] << 24) | (rl->alloc_length[1] << 16) | 	\ +     (rl->alloc_length[2] << 8) | (rl->alloc_length[3])) + +#define SCSI_REPORT_LUNS_SET_ALLOCLEN(rl, alloc_len) {      \ +    (rl)->alloc_length[0] = (alloc_len) >> 24;      			\ +    (rl)->alloc_length[1] = ((alloc_len) >> 16) & 0xFF; 		\ +    (rl)->alloc_length[2] = ((alloc_len) >> 8) & 0xFF;  		\ +    (rl)->alloc_length[3] = (alloc_len) & 0xFF;     			\ +} + +struct scsi_report_luns_data_s{ +	u32        lun_list_length;	/* length of LUN list length */ +	u32        reserved; +	lun_t           lun[1];			/* first LUN in lun list */ +}; + +/* ------------------------------------------------------------- + * SCSI mode  parameters + * ----------------------------------------------------------- + */ +enum { +	SCSI_DA_MEDIUM_DEF = 0,	/* direct access default medium type */ +	SCSI_DA_MEDIUM_SS = 1,	/* direct access single sided */ +	SCSI_DA_MEDIUM_DS = 2,	/* direct access double sided */ +}; + +/* + * SCSI Mode Select(6) cdb + */ +struct scsi_mode_select6_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         pf:1;		/* page format */ +	u8         reserved2:3; +	u8         sp:1;		/* save pages if set to 1 */ +#else +	u8         sp:1;	/* save pages if set to 1 */ +	u8         reserved2:3; +	u8         pf:1;	/* page format */ +	u8         reserved1:3; +#endif +	u8         reserved3[2]; +	u8         alloc_len; +	u8         control; +}; + +/* + * SCSI Mode Select(10) cdb + */ +struct scsi_mode_select10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         pf:1;	/* page format */ +	u8         reserved2:3; +	u8         sp:1;	/* save pages if set to 1 */ +#else +	u8         sp:1;	/* save pages if set to 1 */ +	u8         reserved2:3; +	u8         pf:1;	/* page format */ +	u8         reserved1:3; +#endif +	u8         reserved3[5]; +	u8         alloc_len_msb; +	u8         alloc_len_lsb; +	u8         control; +}; + +/* + * SCSI Mode Sense(6) cdb + */ +struct scsi_mode_sense6_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:4; +	u8         dbd:1;	/* disable block discriptors if set to 1 */ +	u8         reserved2:3; + +	u8         pc:2;	/* page control */ +	u8         page_code:6; +#else +	u8         reserved2:3; +	u8         dbd:1;	/* disable block descriptors if set to 1 */ +	u8         reserved1:4; + +	u8         page_code:6; +	u8         pc:2;	/* page control */ +#endif +	u8         reserved3; +	u8         alloc_len; +	u8         control; +}; + +/* + * SCSI Mode Sense(10) cdb + */ +struct scsi_mode_sense10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         LLBAA:1;	/* long LBA accepted if set to 1 */ +	u8         dbd:1;		/* disable block descriptors if set +					 * to 1 +					 */ +	u8         reserved2:3; + +	u8         pc:2;		/* page control */ +	u8         page_code:6; +#else +	u8         reserved2:3; +	u8         dbd:1;		/* disable block descriptors if set to +					 * 1 +					 */ +	u8         LLBAA:1;	/* long LBA accepted if set to 1 */ +	u8         reserved1:3; + +	u8         page_code:6; +	u8         pc:2;		/* page control */ +#endif +	u8         reserved3[4]; +	u8         alloc_len_msb; +	u8         alloc_len_lsb; +	u8         control; +}; + +#define SCSI_CDB10_GET_AL(cdb)  					\ +    ((cdb)->alloc_len_msb << 8 | (cdb)->alloc_len_lsb) + +#define SCSI_CDB10_SET_AL(cdb, al) {      \ +    (cdb)->alloc_len_msb = al >> 8;       				\ +    (cdb)->alloc_len_lsb = al & 0xFF;     				\ +} + +#define SCSI_CDB6_GET_AL(cdb) ((cdb)->alloc_len) + +#define SCSI_CDB6_SET_AL(cdb, al) {      \ +    (cdb)->alloc_len = al;         					\ +} + +/* + * page control field values + */ +#define SCSI_PC_CURRENT_VALUES       0x0 +#define SCSI_PC_CHANGEABLE_VALUES    0x1 +#define SCSI_PC_DEFAULT_VALUES       0x2 +#define SCSI_PC_SAVED_VALUES         0x3 + +/* + * SCSI mode page codes + */ +#define SCSI_MP_VENDOR_SPEC     0x00 +#define SCSI_MP_DISC_RECN       0x02	/* disconnect-reconnect page */ +#define SCSI_MP_FORMAT_DEVICE   0x03 +#define SCSI_MP_RDG             0x04	/* rigid disk geometry page */ +#define SCSI_MP_FDP             0x05	/* flexible disk page */ +#define SCSI_MP_CACHING         0x08	/* caching page */ +#define SCSI_MP_CONTROL         0x0A	/* control mode page */ +#define SCSI_MP_MED_TYPES_SUP   0x0B	/* medium types supported page */ +#define SCSI_MP_INFO_EXCP_CNTL  0x1C	/* informational exception control */ +#define SCSI_MP_ALL             0x3F	/* return all pages - mode sense only */ + +/* + * mode parameter header + */ +struct scsi_mode_param_header6_s{ +	u8         mode_datalen; +	u8         medium_type; + +	/* +	 * device specific parameters expanded for direct access devices +	 */ +#ifdef __BIGENDIAN +	u32        wp:1;		/* write protected */ +	u32        reserved1:2; +	u32        dpofua:1;	/* disable page out + force unit access +					 */ +	u32        reserved2:4; +#else +	u32        reserved2:4; +	u32        dpofua:1;	/* disable page out + force unit access +					 */ +	u32        reserved1:2; +	u32        wp:1;		/* write protected */ +#endif + +	u8         block_desclen; +}; + +struct scsi_mode_param_header10_s{ +	u32        mode_datalen:16; +	u32        medium_type:8; + +	/* +	 * device specific parameters expanded for direct access devices +	 */ +#ifdef __BIGENDIAN +	u32        wp:1;		/* write protected */ +	u32        reserved1:2; +	u32        dpofua:1;	/* disable page out + force unit access +					 */ +	u32        reserved2:4; +#else +	u32        reserved2:4; +	u32        dpofua:1;	/* disable page out + force unit access +					 */ +	u32        reserved1:2; +	u32        wp:1;		/* write protected */ +#endif + +#ifdef __BIGENDIAN +	u32        reserved3:7; +	u32        longlba:1; +#else +	u32        longlba:1; +	u32        reserved3:7; +#endif +	u32        reserved4:8; +	u32        block_desclen:16; +}; + +/* + * mode parameter block descriptor + */ +struct scsi_mode_param_desc_s{ +	u32        nblks; +	u32        density_code:8; +	u32        block_length:24; +}; + +/* + * Disconnect-reconnect mode page format + */ +struct scsi_mp_disc_recn_s{ +#ifdef __BIGENDIAN +	u8         ps:1; +	u8         reserved1:1; +	u8         page_code:6; +#else +	u8         page_code:6; +	u8         reserved1:1; +	u8         ps:1; +#endif +	u8         page_len; +	u8         buf_full_ratio; +	u8         buf_empty_ratio; + +	u8         bil_msb;	/* bus inactivity limit -MSB */ +	u8         bil_lsb;	/* bus inactivity limit -LSB */ + +	u8         dtl_msb;	/* disconnect time limit - MSB */ +	u8         dtl_lsb;	/* disconnect time limit - LSB */ + +	u8         ctl_msb;	/* connect time limit - MSB */ +	u8         ctl_lsb;	/* connect time limit - LSB */ + +	u8         max_burst_len_msb; +	u8         max_burst_len_lsb; +#ifdef __BIGENDIAN +	u8         emdp:1;	/* enable modify data pointers */ +	u8         fa:3;	/* fair arbitration */ +	u8         dimm:1;	/* disconnect immediate */ +	u8         dtdc:3;	/* data transfer disconnect control */ +#else +	u8         dtdc:3;	/* data transfer disconnect control */ +	u8         dimm:1;	/* disconnect immediate */ +	u8         fa:3;	/* fair arbitration */ +	u8         emdp:1;	/* enable modify data pointers */ +#endif + +	u8         reserved3; + +	u8         first_burst_len_msb; +	u8         first_burst_len_lsb; +}; + +/* + * SCSI format device mode page + */ +struct scsi_mp_format_device_s{ +#ifdef __BIGENDIAN +	u32        ps:1; +	u32        reserved1:1; +	u32        page_code:6; +#else +	u32        page_code:6; +	u32        reserved1:1; +	u32        ps:1; +#endif +	u32        page_len:8; +	u32        tracks_per_zone:16; + +	u32        a_sec_per_zone:16; +	u32        a_tracks_per_zone:16; + +	u32        a_tracks_per_lun:16;	/* alternate tracks/lun-MSB */ +	u32        sec_per_track:16;	/* sectors/track-MSB */ + +	u32        bytes_per_sector:16; +	u32        interleave:16; + +	u32        tsf:16;			/* track skew factor-MSB */ +	u32        csf:16;			/* cylinder skew factor-MSB */ + +#ifdef __BIGENDIAN +	u32        ssec:1;	/* soft sector formatting */ +	u32        hsec:1;	/* hard sector formatting */ +	u32        rmb:1;	/* removable media */ +	u32        surf:1;	/* surface */ +	u32        reserved2:4; +#else +	u32        reserved2:4; +	u32        surf:1;	/* surface */ +	u32        rmb:1;	/* removable media */ +	u32        hsec:1;	/* hard sector formatting */ +	u32        ssec:1;	/* soft sector formatting */ +#endif +	u32        reserved3:24; +}; + +/* + * SCSI rigid disk device geometry page + */ +struct scsi_mp_rigid_device_geometry_s{ +#ifdef __BIGENDIAN +	u32        ps:1; +	u32        reserved1:1; +	u32        page_code:6; +#else +	u32        page_code:6; +	u32        reserved1:1; +	u32        ps:1; +#endif +	u32        page_len:8; +	u32        num_cylinders0:8; +	u32        num_cylinders1:8; + +	u32        num_cylinders2:8; +	u32        num_heads:8; +	u32        scwp0:8; +	u32        scwp1:8; + +	u32        scwp2:8; +	u32        scrwc0:8; +	u32        scrwc1:8; +	u32        scrwc2:8; + +	u32        dsr:16; +	u32        lscyl0:8; +	u32        lscyl1:8; + +	u32        lscyl2:8; +#ifdef __BIGENDIAN +	u32        reserved2:6; +	u32        rpl:2;	/* rotational position locking */ +#else +	u32        rpl:2;	/* rotational position locking */ +	u32        reserved2:6; +#endif +	u32        rot_off:8; +	u32        reserved3:8; + +	u32        med_rot_rate:16; +	u32        reserved4:16; +}; + +/* + * SCSI caching mode page + */ +struct scsi_mp_caching_s{ +#ifdef __BIGENDIAN +	u8         ps:1; +	u8         res1:1; +	u8         page_code:6; +#else +	u8         page_code:6; +	u8         res1:1; +	u8         ps:1; +#endif +	u8         page_len; +#ifdef __BIGENDIAN +	u8         ic:1;	/* initiator control */ +	u8         abpf:1;	/* abort pre-fetch */ +	u8         cap:1;	/* caching analysis permitted */ +	u8         disc:1;	/* discontinuity */ +	u8         size:1;	/* size enable */ +	u8         wce:1;	/* write cache enable */ +	u8         mf:1;	/* multiplication factor */ +	u8         rcd:1;	/* read cache disable */ + +	u8         drrp:4;	/* demand read retention priority */ +	u8         wrp:4;	/* write retention priority */ +#else +	u8         rcd:1;	/* read cache disable */ +	u8         mf:1;	/* multiplication factor */ +	u8         wce:1;	/* write cache enable */ +	u8         size:1;	/* size enable */ +	u8         disc:1;	/* discontinuity */ +	u8         cap:1;	/* caching analysis permitted */ +	u8         abpf:1;	/* abort pre-fetch */ +	u8         ic:1;	/* initiator control */ + +	u8         wrp:4;	/* write retention priority */ +	u8         drrp:4;	/* demand read retention priority */ +#endif +	u8         dptl[2];/* disable pre-fetch transfer length */ +	u8         min_prefetch[2]; +	u8         max_prefetch[2]; +	u8         max_prefetch_limit[2]; +#ifdef __BIGENDIAN +	u8         fsw:1;	/* force sequential write */ +	u8         lbcss:1;/* logical block cache segment size */ +	u8         dra:1;	/* disable read ahead */ +	u8         vs:2;	/* vendor specific */ +	u8         res2:3; +#else +	u8         res2:3; +	u8         vs:2;	/* vendor specific */ +	u8         dra:1;	/* disable read ahead */ +	u8         lbcss:1;/* logical block cache segment size */ +	u8         fsw:1;	/* force sequential write */ +#endif +	u8         num_cache_segs; + +	u8         cache_seg_size[2]; +	u8         res3; +	u8         non_cache_seg_size[3]; +}; + +/* + * SCSI control mode page + */ +struct scsi_mp_control_page_s{ +#ifdef __BIGENDIAN +u8         ps:1; +u8         reserved1:1; +u8         page_code:6; +#else +u8         page_code:6; +u8         reserved1:1; +u8         ps:1; +#endif +	u8         page_len; +#ifdef __BIGENDIAN +	u8         tst:3;		/* task set type */ +	u8         reserved3:3; +	u8         gltsd:1;	/* global logging target save disable */ +	u8         rlec:1;		/* report log exception condition */ + +	u8         qalgo_mod:4;	/* queue alogorithm modifier */ +	u8         reserved4:1; +	u8         qerr:2;		/* queue error management */ +	u8         dque:1;		/* disable queuing */ + +	u8         reserved5:1; +	u8         rac:1;		/* report a check */ +	u8         reserved6:2; +	u8         swp:1;		/* software write protect */ +	u8         raerp:1;	/* ready AER permission */ +	u8         uaaerp:1;	/* unit attenstion AER permission */ +	u8         eaerp:1;	/* error AER permission */ + +	u8         reserved7:5; +	u8         autoload_mod:3; +#else +	u8         rlec:1;		/* report log exception condition */ +	u8         gltsd:1;	/* global logging target save disable */ +	u8         reserved3:3; +	u8         tst:3;		/* task set type */ + +	u8         dque:1;		/* disable queuing */ +	u8         qerr:2;		/* queue error management */ +	u8         reserved4:1; +	u8         qalgo_mod:4;	/* queue alogorithm modifier */ + +	u8         eaerp:1;	/* error AER permission */ +	u8         uaaerp:1;	/* unit attenstion AER permission */ +	u8         raerp:1;	/* ready AER permission */ +	u8         swp:1;		/* software write protect */ +	u8         reserved6:2; +	u8         rac:1;		/* report a check */ +	u8         reserved5:1; + +	u8         autoload_mod:3; +	u8         reserved7:5; +#endif +	u8         rahp_msb;	/* ready AER holdoff period - MSB */ +	u8         rahp_lsb;	/* ready AER holdoff period - LSB */ + +	u8         busy_timeout_period_msb; +	u8         busy_timeout_period_lsb; + +	u8         ext_selftest_compl_time_msb; +	u8         ext_selftest_compl_time_lsb; +}; + +/* + * SCSI medium types supported mode page + */ +struct scsi_mp_medium_types_sup_s{ +#ifdef __BIGENDIAN +	u8         ps:1; +	u8         reserved1:1; +	u8         page_code:6; +#else +	u8         page_code:6; +	u8         reserved1:1; +	u8         ps:1; +#endif +	u8         page_len; + +	u8         reserved3[2]; +	u8         med_type1_sup;	/* medium type one supported */ +	u8         med_type2_sup;	/* medium type two supported */ +	u8         med_type3_sup;	/* medium type three supported */ +	u8         med_type4_sup;	/* medium type four supported */ +}; + +/* + * SCSI informational exception control mode page + */ +struct scsi_mp_info_excpt_cntl_s{ +#ifdef __BIGENDIAN +	u8         ps:1; +	u8         reserved1:1; +	u8         page_code:6; +#else +	u8         page_code:6; +	u8         reserved1:1; +	u8         ps:1; +#endif +	u8         page_len; +#ifdef __BIGENDIAN +	u8         perf:1;		/* performance */ +	u8         reserved3:1; +	u8         ebf:1;		/* enable background fucntion */ +	u8         ewasc:1;	/* enable warning */ +	u8         dexcpt:1;	/* disable exception control */ +	u8         test:1;		/* enable test device failure +					 * notification +					 */ +	u8         reserved4:1; +	u8         log_error:1; + +	u8         reserved5:4; +	u8         mrie:4;		/* method of reporting info +					 * exceptions +					 */ +#else +	u8         log_error:1; +	u8         reserved4:1; +	u8         test:1;		/* enable test device failure +					 * notification +					 */ +	u8         dexcpt:1;	/* disable exception control */ +	u8         ewasc:1;	/* enable warning */ +	u8         ebf:1;		/* enable background fucntion */ +	u8         reserved3:1; +	u8         perf:1;		/* performance */ + +	u8         mrie:4;		/* method of reporting info +					 * exceptions +					 */ +	u8         reserved5:4; +#endif +	u8         interval_timer_msb; +	u8         interval_timer_lsb; + +	u8         report_count_msb; +	u8         report_count_lsb; +}; + +/* + * Methods of reporting informational exceptions + */ +#define SCSI_MP_IEC_NO_REPORT       0x0	/* no reporting of exceptions */ +#define SCSI_MP_IEC_AER             0x1	/* async event reporting */ +#define SCSI_MP_IEC_UNIT_ATTN       0x2	/* generate unit attenstion */ +#define SCSI_MO_IEC_COND_REC_ERR    0x3	/* conditionally generate recovered +					 * error +					 */ +#define SCSI_MP_IEC_UNCOND_REC_ERR  0x4	/* unconditionally generate recovered +					 * error +					 */ +#define SCSI_MP_IEC_NO_SENSE        0x5	/* generate no sense */ +#define SCSI_MP_IEC_ON_REQUEST      0x6	/* only report exceptions on request */ + +/* + * SCSI flexible disk page + */ +struct scsi_mp_flexible_disk_s{ +#ifdef __BIGENDIAN +	u8         ps:1; +	u8         reserved1:1; +	u8         page_code:6; +#else +	u8         page_code:6; +	u8         reserved1:1; +	u8         ps:1; +#endif +	u8         page_len; + +	u8         transfer_rate_msb; +	u8         transfer_rate_lsb; + +	u8         num_heads; +	u8         num_sectors; + +	u8         bytes_per_sector_msb; +	u8         bytes_per_sector_lsb; + +	u8         num_cylinders_msb; +	u8         num_cylinders_lsb; + +	u8         sc_wpc_msb;	/* starting cylinder-write +					 * precompensation msb +					 */ +	u8         sc_wpc_lsb;	/* starting cylinder-write +					 * precompensation lsb +					 */ +	u8         sc_rwc_msb;	/* starting cylinder-reduced write +					 * current msb +					 */ +	u8         sc_rwc_lsb;	/* starting cylinder-reduced write +					 * current lsb +					 */ + +	u8         dev_step_rate_msb; +	u8         dev_step_rate_lsb; + +	u8         dev_step_pulse_width; + +	u8         head_sd_msb;	/* head settle delay msb */ +	u8         head_sd_lsb;	/* head settle delay lsb */ + +	u8         motor_on_delay; +	u8         motor_off_delay; +#ifdef __BIGENDIAN +	u8         trdy:1;		/* true ready bit */ +	u8         ssn:1;		/* start sector number bit */ +	u8         mo:1;		/* motor on bit */ +	u8         reserved3:5; + +	u8         reserved4:4; +	u8         spc:4;		/* step pulse per cylinder */ +#else +	u8         reserved3:5; +	u8         mo:1;		/* motor on bit */ +	u8         ssn:1;		/* start sector number bit */ +	u8         trdy:1;		/* true ready bit */ + +	u8         spc:4;		/* step pulse per cylinder */ +	u8         reserved4:4; +#endif +	u8         write_comp; +	u8         head_load_delay; +	u8         head_unload_delay; +#ifdef __BIGENDIAN +	u8         pin34:4;	/* pin34 usage */ +	u8         pin2:4;		/* pin2 usage */ + +	u8         pin4:4;		/* pin4 usage */ +	u8         pin1:4;		/* pin1 usage */ +#else +	u8         pin2:4;		/* pin2 usage */ +	u8         pin34:4;	/* pin34 usage */ + +	u8         pin1:4;		/* pin1 usage */ +	u8         pin4:4;		/* pin4 usage */ +#endif +	u8         med_rot_rate_msb; +	u8         med_rot_rate_lsb; + +	u8         reserved5[2]; +}; + +struct scsi_mode_page_format_data6_s{ +	struct scsi_mode_param_header6_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_format_device_s format;	/* format device data */ +}; + +struct scsi_mode_page_format_data10_s{ +	struct scsi_mode_param_header10_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_format_device_s format;	/* format device data */ +}; + +struct scsi_mode_page_rdg_data6_s{ +	struct scsi_mode_param_header6_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_rigid_device_geometry_s rdg; +					/* rigid geometry data */ +}; + +struct scsi_mode_page_rdg_data10_s{ +	struct scsi_mode_param_header10_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_rigid_device_geometry_s rdg; +					/* rigid geometry data */ +}; + +struct scsi_mode_page_cache6_s{ +	struct scsi_mode_param_header6_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_caching_s cache;	/* cache page data */ +}; + +struct scsi_mode_page_cache10_s{ +	struct scsi_mode_param_header10_s mph;	/* mode page header */ +	struct scsi_mode_param_desc_s desc;	/* block descriptor */ +	struct scsi_mp_caching_s cache;	/* cache page data */ +}; + +/* -------------------------------------------------------------- + * Format Unit command + * ------------------------------------------------------------ + */ + +/* + * Format Unit CDB + */ +struct scsi_format_unit_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         res1:3; +	u8         fmtdata:1;	/* if set, data out phase has format +					 * data +					 */ +	u8         cmplst:1;	/* if set, defect list is complete */ +	u8         def_list:3;	/* format of defect descriptor is +					 * fmtdata =1 +					 */ +#else +	u8         def_list:3;	/* format of defect descriptor is +					 * fmtdata = 1 +					 */ +	u8         cmplst:1;	/* if set, defect list is complete */ +	u8         fmtdata:1;	/* if set, data out phase has format +					 * data +					 */ +	u8         res1:3; +#endif +	u8         interleave_msb; +	u8         interleave_lsb; +	u8         vendor_spec; +	u8         control; +}; + +/* + * h + */ +struct scsi_reserve6_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved:3; +	u8         obsolete:4; +	u8         extent:1; +#else +	u8         extent:1; +	u8         obsolete:4; +	u8         reserved:3; +#endif +	u8         reservation_id; +	u16        param_list_len; +	u8         control; +}; + +/* + * h + */ +struct scsi_release6_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         obsolete:4; +	u8         extent:1; +#else +	u8         extent:1; +	u8         obsolete:4; +	u8         reserved1:3; +#endif +	u8         reservation_id; +	u16        reserved2; +	u8         control; +}; + +/* + * h + */ +struct scsi_reserve10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         third_party:1; +	u8         reserved2:2; +	u8         long_id:1; +	u8         extent:1; +#else +	u8         extent:1; +	u8         long_id:1; +	u8         reserved2:2; +	u8         third_party:1; +	u8         reserved1:3; +#endif +	u8         reservation_id; +	u8         third_pty_dev_id; +	u8         reserved3; +	u8         reserved4; +	u8         reserved5; +	u16        param_list_len; +	u8         control; +}; + +struct scsi_release10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         third_party:1; +	u8         reserved2:2; +	u8         long_id:1; +	u8         extent:1; +#else +	u8         extent:1; +	u8         long_id:1; +	u8         reserved2:2; +	u8         third_party:1; +	u8         reserved1:3; +#endif +	u8         reservation_id; +	u8         third_pty_dev_id; +	u8         reserved3; +	u8         reserved4; +	u8         reserved5; +	u16        param_list_len; +	u8         control; +}; + +struct scsi_verify10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         dpo:1; +	u8         reserved:2; +	u8         bytchk:1; +	u8         reladdr:1; +#else +	u8         reladdr:1; +	u8         bytchk:1; +	u8         reserved:2; +	u8         dpo:1; +	u8         lun:3; +#endif +	u8         lba0; +	u8         lba1; +	u8         lba2; +	u8         lba3; +	u8         reserved1; +	u8         verification_len0; +	u8         verification_len1; +	u8         control_byte; +}; + +struct scsi_request_sense_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         lun:3; +	u8         reserved:5; +#else +	u8         reserved:5; +	u8         lun:3; +#endif +	u8         reserved0; +	u8         reserved1; +	u8         alloc_len; +	u8         control_byte; +}; + +/* ------------------------------------------------------------ + * SCSI status byte values + * ------------------------------------------------------------ + */ +#define SCSI_STATUS_GOOD                   0x00 +#define SCSI_STATUS_CHECK_CONDITION        0x02 +#define SCSI_STATUS_CONDITION_MET          0x04 +#define SCSI_STATUS_BUSY                   0x08 +#define SCSI_STATUS_INTERMEDIATE           0x10 +#define SCSI_STATUS_ICM                    0x14	/* intermediate condition met */ +#define SCSI_STATUS_RESERVATION_CONFLICT   0x18 +#define SCSI_STATUS_COMMAND_TERMINATED     0x22 +#define SCSI_STATUS_QUEUE_FULL             0x28 +#define SCSI_STATUS_ACA_ACTIVE             0x30 + +#define SCSI_MAX_ALLOC_LEN		0xFF	/* maximum allocarion length +						 * in CDBs +						 */ + +#define SCSI_OP_WRITE_VERIFY10      0x2E +#define SCSI_OP_WRITE_VERIFY12      0xAE +#define SCSI_OP_UNDEF               0xFF + +/* + * SCSI WRITE-VERIFY(10) command + */ +struct scsi_write_verify10_s{ +	u8         opcode; +#ifdef __BIGENDIAN +	u8         reserved1:3; +	u8         dpo:1;		/* Disable Page Out */ +	u8         reserved2:1; +	u8         ebp:1;		/* erse by-pass */ +	u8         bytchk:1;	/* byte check */ +	u8         rel_adr:1;	/* relative address */ +#else +	u8         rel_adr:1;	/* relative address */ +	u8         bytchk:1;	/* byte check */ +	u8         ebp:1;		/* erse by-pass */ +	u8         reserved2:1; +	u8         dpo:1;		/* Disable Page Out */ +	u8         reserved1:3; +#endif +	u8         lba0;		/* logical block address - MSB */ +	u8         lba1; +	u8         lba2; +	u8         lba3;		/* LSB */ +	u8         reserved3; +	u8         xfer_length0;	/* transfer length in blocks - MSB */ +	u8         xfer_length1;	/* LSB */ +	u8         control; +}; + +#pragma pack() + +#endif /* __SCSI_H__ */ diff --git a/drivers/scsi/bfa/include/protocol/types.h b/drivers/scsi/bfa/include/protocol/types.h new file mode 100644 index 00000000000..2875a6cced3 --- /dev/null +++ b/drivers/scsi/bfa/include/protocol/types.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  types.h Protocol defined base types + */ + +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include <bfa_os_inc.h> + +#define wwn_t u64 +#define lun_t u64 + +#define WWN_NULL	(0) +#define FC_SYMNAME_MAX	256	/*  max name server symbolic name size */ +#define FC_ALPA_MAX	128 + +#pragma pack(1) + +#define MAC_ADDRLEN	(6) +struct mac_s { u8 mac[MAC_ADDRLEN]; }; +#define mac_t struct mac_s + +#pragma pack() + +#endif diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c new file mode 100644 index 00000000000..a418dedebe9 --- /dev/null +++ b/drivers/scsi/bfa/loop.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  port_loop.c vport private loop implementation. + */ +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_trcmod.h" +#include "lport_priv.h" + +BFA_TRC_FILE(FCS, LOOP); + +/** + *   ALPA to LIXA bitmap mapping + * + *   ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31 + * is for L_bit (login required) and is filled as ALPA 0x00 here. + */ +static const u8   port_loop_alpa_map[] = { +	0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA,	/* Word 3 Bits 0..7 */ +	0xD9, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE,	/* Word 3 Bits 8..15 */ +	0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, 0xC6, 0xC5,	/* Word 3 Bits 16..23 */ +	0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 0xB4, 0xB3,	/* Word 3 Bits 24..31 */ + +	0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9,	/* Word 2 Bits 0..7 */ +	0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B,	/* Word 2 Bits 8..15 */ +	0x98, 0x97, 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81,	/* Word 2 Bits 16..23 */ +	0x80, 0x7C, 0x7A, 0x79, 0x76, 0x75, 0x74, 0x73,	/* Word 2 Bits 24..31 */ + +	0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69,	/* Word 1 Bits 0..7 */ +	0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56,	/* Word 1 Bits 8..15 */ +	0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C,	/* Word 1 Bits 16..23 */ +	0x4B, 0x4A, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C,	/* Word 1 Bits 24..31 */ + +	0x3A, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31,	/* Word 0 Bits 0..7 */ +	0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x26,	/* Word 0 Bits 8..15 */ +	0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17,	/* Word 0 Bits 16..23 */ +	0x10, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00,	/* Word 0 Bits 24..31 */ +}; + +/* + * Local Functions + */ +bfa_status_t    bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, +					     u8 alpa); + +void            bfa_fcs_port_loop_plogi_response(void *fcsarg, +						 struct bfa_fcxp_s *fcxp, +						 void *cbarg, +						 bfa_status_t req_status, +						 u32 rsp_len, +						 u32 resid_len, +						 struct fchs_s *rsp_fchs); + +bfa_status_t    bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port, +					     u8 alpa); + +void            bfa_fcs_port_loop_adisc_response(void *fcsarg, +						 struct bfa_fcxp_s *fcxp, +						 void *cbarg, +						 bfa_status_t req_status, +						 u32 rsp_len, +						 u32 resid_len, +						 struct fchs_s *rsp_fchs); + +bfa_status_t    bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port, +						 u8 alpa); + +void            bfa_fcs_port_loop_plogi_acc_response(void *fcsarg, +						     struct bfa_fcxp_s *fcxp, +						     void *cbarg, +						     bfa_status_t req_status, +						     u32 rsp_len, +						     u32 resid_len, +						     struct fchs_s *rsp_fchs); + +bfa_status_t    bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port, +						 u8 alpa); + +void            bfa_fcs_port_loop_adisc_acc_response(void *fcsarg, +						     struct bfa_fcxp_s *fcxp, +						     void *cbarg, +						     bfa_status_t req_status, +						     u32 rsp_len, +						     u32 resid_len, +						     struct fchs_s *rsp_fchs); +/** + *   Called by port to initializar in provate LOOP topology. + */ +void +bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port) +{ +} + +/** + *   Called by port to notify transition to online state. + */ +void +bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port) +{ + +	u8         num_alpa = port->port_topo.ploop.num_alpa; +	u8        *alpa_pos_map = port->port_topo.ploop.alpa_pos_map; +	struct bfa_fcs_rport_s *r_port; +	int             ii = 0; + +	/* +	 * If the port role is Initiator Mode, create Rports. +	 */ +	if (port->port_cfg.roles == BFA_PORT_ROLE_FCP_IM) { +		/* +		 * Check if the ALPA positional bitmap is available. +		 * if not, we send PLOGI to all possible ALPAs. +		 */ +		if (num_alpa > 0) { +			for (ii = 0; ii < num_alpa; ii++) { +				/* +				 * ignore ALPA of bfa port +				 */ +				if (alpa_pos_map[ii] != port->pid) { +					r_port = bfa_fcs_rport_create(port, +						alpa_pos_map[ii]); +				} +			} +		} else { +			for (ii = 0; ii < MAX_ALPA_COUNT; ii++) { +				/* +				 * ignore ALPA of bfa port +				 */ +				if ((port_loop_alpa_map[ii] > 0) +				    && (port_loop_alpa_map[ii] != port->pid)) +					bfa_fcs_port_loop_send_plogi(port, +						port_loop_alpa_map[ii]); +				/**TBD */ +			} +		} +	} else { +		/* +		 * TBD Target Mode ?? +		 */ +	} + +} + +/** + *   Called by port to notify transition to offline state. + */ +void +bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port) +{ + +} + +/** + *   Called by port to notify a LIP on the loop. + */ +void +bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port) +{ +} + +/** + * Local Functions. + */ +bfa_status_t +bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp = NULL; +	int             len; + +	bfa_trc(port->fcs, alpa); + +	fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL, +				  NULL); +	bfa_assert(fcxp); + +	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa, +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn, +				 bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +			  FC_CLASS_3, len, &fchs, +			  bfa_fcs_port_loop_plogi_response, (void *)port, +			  FC_MAX_PDUSZ, FC_RA_TOV); + +	return BFA_STATUS_OK; +} + +/** + *   Called by fcxp to notify the Plogi response + */ +void +bfa_fcs_port_loop_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				 void *cbarg, bfa_status_t req_status, +				 u32 rsp_len, u32 resid_len, +				 struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg; +	struct fc_logi_s     *plogi_resp; +	struct fc_els_cmd_s   *els_cmd; + +	bfa_trc(port->fcs, req_status); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		/* +		 * @todo +		 * This could mean that the device with this APLA does not +		 * exist on the loop. +		 */ + +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); +	plogi_resp = (struct fc_logi_s *) els_cmd; + +	if (els_cmd->els_code == FC_ELS_ACC) { +		bfa_fcs_rport_start(port, rsp_fchs, plogi_resp); +	} else { +		bfa_trc(port->fcs, plogi_resp->els_cmd.els_code); +		bfa_assert(0); +	} +} + +bfa_status_t +bfa_fcs_port_loop_send_plogi_acc(struct bfa_fcs_port_s *port, u8 alpa) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(port->fcs, alpa); + +	fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL, +				  NULL); +	bfa_assert(fcxp); + +	len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa, +				 bfa_fcs_port_get_fcid(port), 0, +				 port->port_cfg.pwwn, port->port_cfg.nwwn, +				 bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +				 FC_CLASS_3, len, &fchs, +				 bfa_fcs_port_loop_plogi_acc_response, +				 (void *)port, FC_MAX_PDUSZ, 0); /* No response +								  * expected +								  */ + +	return BFA_STATUS_OK; +} + +/* + *  Plogi Acc Response + * We donot do any processing here. + */ +void +bfa_fcs_port_loop_plogi_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				     void *cbarg, bfa_status_t req_status, +				     u32 rsp_len, u32 resid_len, +				     struct fchs_s *rsp_fchs) +{ + +	struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg; + +	bfa_trc(port->fcs, port->pid); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		return; +	} +} + +bfa_status_t +bfa_fcs_port_loop_send_adisc(struct bfa_fcs_port_s *port, u8 alpa) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(port->fcs, alpa); + +	fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL, +				  NULL); +	bfa_assert(fcxp); + +	len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa, +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +			  FC_CLASS_3, len, &fchs, +			  bfa_fcs_port_loop_adisc_response, (void *)port, +			  FC_MAX_PDUSZ, FC_RA_TOV); + +	return BFA_STATUS_OK; +} + +/** + *   Called by fcxp to notify the ADISC response + */ +void +bfa_fcs_port_loop_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				 void *cbarg, bfa_status_t req_status, +				 u32 rsp_len, u32 resid_len, +				 struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg; +	struct bfa_fcs_rport_s *rport; +	struct fc_adisc_s     *adisc_resp; +	struct fc_els_cmd_s   *els_cmd; +	u32        pid = rsp_fchs->s_id; + +	bfa_trc(port->fcs, req_status); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		/* +		 * TBD : we may need to retry certain requests +		 */ +		bfa_fcxp_free(fcxp); +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); +	adisc_resp = (struct fc_adisc_s *) els_cmd; + +	if (els_cmd->els_code == FC_ELS_ACC) { +	} else { +		bfa_trc(port->fcs, adisc_resp->els_cmd.els_code); + +		/* +		 * TBD: we may need to check for reject codes and retry +		 */ +		rport = bfa_fcs_port_get_rport_by_pid(port, pid); +		if (rport) { +			list_del(&rport->qe); +			bfa_fcs_rport_delete(rport); +		} + +	} +	return; +} + +bfa_status_t +bfa_fcs_port_loop_send_adisc_acc(struct bfa_fcs_port_s *port, u8 alpa) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(port->fcs, alpa); + +	fcxp = bfa_fcxp_alloc(NULL, port->fcs->bfa, 0, 0, NULL, NULL, NULL, +				  NULL); +	bfa_assert(fcxp); + +	len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), alpa, +				 bfa_fcs_port_get_fcid(port), 0, +				 port->port_cfg.pwwn, port->port_cfg.nwwn); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +				FC_CLASS_3, len, &fchs, +				bfa_fcs_port_loop_adisc_acc_response, +				(void *)port, FC_MAX_PDUSZ, 0); /* no reponse +								 * expected +								 */ + +	return BFA_STATUS_OK; +} + +/* + *  Adisc Acc Response + * We donot do any processing here. + */ +void +bfa_fcs_port_loop_adisc_acc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				     void *cbarg, bfa_status_t req_status, +				     u32 rsp_len, u32 resid_len, +				     struct fchs_s *rsp_fchs) +{ + +	struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg; + +	bfa_trc(port->fcs, port->pid); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		return; +	} +} diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c new file mode 100644 index 00000000000..8f51a83f183 --- /dev/null +++ b/drivers/scsi/bfa/lport_api.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  port_api.c BFA FCS port + */ + +#include <fcs/bfa_fcs.h> +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_rport.h> +#include "fcs_rport.h" +#include "fcs_fabric.h" +#include "fcs_trcmod.h" +#include "fcs_vport.h" + +BFA_TRC_FILE(FCS, PORT_API); + + + +/** + *  fcs_port_api BFA FCS port API + */ + +void +bfa_fcs_cfg_base_port(struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg) +{ +} + +struct bfa_fcs_port_s * +bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) +{ +	return (&fcs->fabric.bport); +} + +wwn_t +bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index, +		       int nrports, bfa_boolean_t bwwn) +{ +	struct list_head *qh, *qe; +	struct bfa_fcs_rport_s *rport = NULL; +	int             i; +	struct bfa_fcs_s *fcs; + +	if (port == NULL || nrports == 0) +		return (wwn_t) 0; + +	fcs = port->fcs; +	bfa_trc(fcs, (u32) nrports); + +	i = 0; +	qh = &port->rport_q; +	qe = bfa_q_first(qh); + +	while ((qe != qh) && (i < nrports)) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { +			qe = bfa_q_next(qe); +			bfa_trc(fcs, (u32) rport->pwwn); +			bfa_trc(fcs, rport->pid); +			bfa_trc(fcs, i); +			continue; +		} + +		if (bwwn) { +			if (!memcmp(&wwn, &rport->pwwn, 8)) +				break; +		} else { +			if (i == index) +				break; +		} + +		i++; +		qe = bfa_q_next(qe); +	} + +	bfa_trc(fcs, i); +	if (rport) { +		return rport->pwwn; +	} else { +		return (wwn_t) 0; +	} +} + +void +bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[], +			int *nrports) +{ +	struct list_head *qh, *qe; +	struct bfa_fcs_rport_s *rport = NULL; +	int             i; +	struct bfa_fcs_s *fcs; + +	if (port == NULL || rport_wwns == NULL || *nrports == 0) +		return; + +	fcs = port->fcs; +	bfa_trc(fcs, (u32) *nrports); + +	i = 0; +	qh = &port->rport_q; +	qe = bfa_q_first(qh); + +	while ((qe != qh) && (i < *nrports)) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) { +			qe = bfa_q_next(qe); +			bfa_trc(fcs, (u32) rport->pwwn); +			bfa_trc(fcs, rport->pid); +			bfa_trc(fcs, i); +			continue; +		} + +		rport_wwns[i] = rport->pwwn; + +		i++; +		qe = bfa_q_next(qe); +	} + +	bfa_trc(fcs, i); +	*nrports = i; +	return; +} + +/* + * Iterate's through all the rport's in the given port to + * determine the maximum operating speed. + */ +enum bfa_pport_speed +bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) +{ +	struct list_head *qh, *qe; +	struct bfa_fcs_rport_s *rport = NULL; +	struct bfa_fcs_s *fcs; +	enum bfa_pport_speed max_speed = 0; +	struct bfa_pport_attr_s pport_attr; +	enum bfa_pport_speed pport_speed; + +	if (port == NULL) +		return 0; + +	fcs = port->fcs; + +	/* +	 * Get Physical port's current speed +	 */ +	bfa_pport_get_attr(port->fcs->bfa, &pport_attr); +	pport_speed = pport_attr.speed; +	bfa_trc(fcs, pport_speed); + +	qh = &port->rport_q; +	qe = bfa_q_first(qh); + +	while (qe != qh) { +		rport = (struct bfa_fcs_rport_s *)qe; +		if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) +		    || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) { +			qe = bfa_q_next(qe); +			continue; +		} + +		if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS) +		    || (rport->rpf.rpsc_speed > pport_speed)) { +			max_speed = rport->rpf.rpsc_speed; +			break; +		} else if (rport->rpf.rpsc_speed > max_speed) { +			max_speed = rport->rpf.rpsc_speed; +		} + +		qe = bfa_q_next(qe); +	} + +	bfa_trc(fcs, max_speed); +	return max_speed; +} + +struct bfa_fcs_port_s * +bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) +{ +	struct bfa_fcs_vport_s *vport; +	bfa_fcs_vf_t   *vf; + +	bfa_assert(fcs != NULL); + +	vf = bfa_fcs_vf_lookup(fcs, vf_id); +	if (vf == NULL) { +		bfa_trc(fcs, vf_id); +		return (NULL); +	} + +	if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn)) +		return (&vf->bport); + +	vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn); +	if (vport) +		return (&vport->lport); + +	return (NULL); +} + +/* + *  API corresponding to VmWare's NPIV_VPORT_GETINFO. + */ +void +bfa_fcs_port_get_info(struct bfa_fcs_port_s *port, +		      struct bfa_port_info_s *port_info) +{ + +	bfa_trc(port->fcs, port->fabric->fabric_name); + +	if (port->vport == NULL) { +		/* +		 * This is a Physical port +		 */ +		port_info->port_type = BFA_PORT_TYPE_PHYSICAL; + +		/* +		 * @todo : need to fix the state & reason +		 */ +		port_info->port_state = 0; +		port_info->offline_reason = 0; + +		port_info->port_wwn = bfa_fcs_port_get_pwwn(port); +		port_info->node_wwn = bfa_fcs_port_get_nwwn(port); + +		port_info->max_vports_supp = bfa_fcs_vport_get_max(port->fcs); +		port_info->num_vports_inuse = +			bfa_fcs_fabric_vport_count(port->fabric); +		port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; +		port_info->num_rports_inuse = port->num_rports; +	} else { +		/* +		 * This is a virtual port +		 */ +		port_info->port_type = BFA_PORT_TYPE_VIRTUAL; + +		/* +		 * @todo : need to fix the state & reason +		 */ +		port_info->port_state = 0; +		port_info->offline_reason = 0; + +		port_info->port_wwn = bfa_fcs_port_get_pwwn(port); +		port_info->node_wwn = bfa_fcs_port_get_nwwn(port); +	} +} + +void +bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port, +		       struct bfa_port_stats_s *port_stats) +{ +	bfa_os_memcpy(port_stats, &fcs_port->stats, +		      sizeof(struct bfa_port_stats_s)); +	return; +} + +void +bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port) +{ +	bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_port_stats_s)); +	return; +} + +void +bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) +{ +	fcs_port->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC; +	return; +} + +void +bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port) +{ +	fcs_port->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC; +	return; +} + + diff --git a/drivers/scsi/bfa/lport_priv.h b/drivers/scsi/bfa/lport_priv.h new file mode 100644 index 00000000000..dbae370a599 --- /dev/null +++ b/drivers/scsi/bfa/lport_priv.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#ifndef __VP_PRIV_H__ +#define __VP_PRIV_H__ + +#include <fcs/bfa_fcs_lport.h> +#include <fcs/bfa_fcs_vport.h> + +/* + * Functions exported by vps + */ +void            bfa_fcs_vport_init(struct bfa_fcs_vport_s *vport); + +/* + * Functions exported by vps + */ +void            bfa_fcs_vps_online(struct bfa_fcs_port_s *port); +void            bfa_fcs_vps_offline(struct bfa_fcs_port_s *port); +void            bfa_fcs_vps_lip(struct bfa_fcs_port_s *port); + +/* + * Functions exported by port_fab + */ +void            bfa_fcs_port_fab_init(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_fab_online(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_fab_rx_frame(struct bfa_fcs_port_s *port, +					  u8 *rx_frame, u32 len); + +/* + * Functions exported by VP-NS. + */ +void            bfa_fcs_port_ns_init(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_ns_online(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port); + +/* + * Functions exported by VP-SCN + */ +void            bfa_fcs_port_scn_init(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_scn_online(struct bfa_fcs_port_s *vport); +void            bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, +					      struct fchs_s *rx_frame, u32 len); + +/* + * Functions exported by VP-N2N + */ + +void            bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_n2n_rx_frame(struct bfa_fcs_port_s *port, +					  u8 *rx_frame, u32 len); + +/* + * Functions exported by VP-LOOP + */ +void            bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port); +void            bfa_fcs_port_loop_rx_frame(struct bfa_fcs_port_s *port, +					   u8 *rx_frame, u32 len); + +#endif /* __VP_PRIV_H__ */ diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c new file mode 100644 index 00000000000..c96b3ca007a --- /dev/null +++ b/drivers/scsi/bfa/ms.c @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "lport_priv.h" + +BFA_TRC_FILE(FCS, MS); + +#define BFA_FCS_MS_CMD_MAX_RETRIES  2 +/* + * forward declarations + */ +static void     bfa_fcs_port_ms_send_plogi(void *ms_cbarg, +					   struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ms_timeout(void *arg); +static void     bfa_fcs_port_ms_plogi_response(void *fcsarg, +					       struct bfa_fcxp_s *fcxp, +					       void *cbarg, +					       bfa_status_t req_status, +					       u32 rsp_len, +					       u32 resid_len, +					       struct fchs_s *rsp_fchs); + +static void     bfa_fcs_port_ms_send_gmal(void *ms_cbarg, +					  struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ms_gmal_response(void *fcsarg, +					      struct bfa_fcxp_s *fcxp, +					      void *cbarg, +					      bfa_status_t req_status, +					      u32 rsp_len, +					      u32 resid_len, +					      struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ms_send_gfn(void *ms_cbarg, +					 struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ms_gfn_response(void *fcsarg, +					     struct bfa_fcxp_s *fcxp, +					     void *cbarg, +					     bfa_status_t req_status, +					     u32 rsp_len, +					     u32 resid_len, +					     struct fchs_s *rsp_fchs); +/** + *  fcs_ms_sm FCS MS state machine + */ + +/** + *  MS State Machine events + */ +enum port_ms_event { +	MSSM_EVENT_PORT_ONLINE = 1, +	MSSM_EVENT_PORT_OFFLINE = 2, +	MSSM_EVENT_RSP_OK = 3, +	MSSM_EVENT_RSP_ERROR = 4, +	MSSM_EVENT_TIMEOUT = 5, +	MSSM_EVENT_FCXP_SENT = 6, +	MSSM_EVENT_PORT_FABRIC_RSCN = 7 +}; + +static void     bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms, +					   enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms, +						 enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, +					 enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms, +					       enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms, +						enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, +					enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms, +					      enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms, +					       enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, +				       enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms, +					     enum port_ms_event event); +static void     bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms, +					  enum port_ms_event event); +/** + * 		Start in offline state - awaiting NS to send start. + */ +static void +bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms, +			   enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_PORT_ONLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending); +		bfa_fcs_port_ms_send_plogi(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms, +				 enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), +				       &ms->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry); +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer, +				bfa_fcs_port_ms_timeout, ms, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case MSSM_EVENT_RSP_OK: +		/* +		 * since plogi is done, now invoke MS related sub-modules +		 */ +		bfa_fcs_port_fdmi_online(ms); + +		/** +		 * if this is a Vport, go to online state. +		 */ +		if (ms->port->vport) { +			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); +			break; +		} + +		/* +		 * For a base port we need to get the +		 * switch's IP address. +		 */ +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending); +		bfa_fcs_port_ms_send_gmal(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_discard(ms->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms, +			       enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending); +		bfa_fcs_port_ms_send_plogi(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_timer_stop(&ms->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms, +			  enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		/* +		 * now invoke MS related sub-modules +		 */ +		bfa_fcs_port_fdmi_offline(ms); +		break; + +	case MSSM_EVENT_PORT_FABRIC_RSCN: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); +		ms->retry_cnt = 0; +		bfa_fcs_port_ms_send_gfn(ms, NULL); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms, +				enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), +				       &ms->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { +			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry); +			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), +					&ms->timer, bfa_fcs_port_ms_timeout, ms, +					BFA_FCS_RETRY_TIMEOUT); +		} else { +			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); +			bfa_fcs_port_ms_send_gfn(ms, NULL); +			ms->retry_cnt = 0; +		} +		break; + +	case MSSM_EVENT_RSP_OK: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); +		bfa_fcs_port_ms_send_gfn(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_discard(ms->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms, +			      enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending); +		bfa_fcs_port_ms_send_gmal(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_timer_stop(&ms->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *  ms_pvt MS local functions + */ + +static void +bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ms_s *ms = ms_cbarg; +	struct bfa_fcs_port_s *port = ms->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, +				    bfa_fcs_port_ms_send_gmal, ms); +		return; +	} +	ms->fcxp = fcxp; + +	len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +				bfa_fcs_port_get_fcid(port), +				bfa_lps_get_peer_nwwn(port->fabric->lps)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response, +		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_port_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +			      void *cbarg, bfa_status_t req_status, +			      u32 rsp_len, u32 resid_len, +			      struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; +	struct bfa_fcs_port_s *port = ms->port; +	struct ct_hdr_s       *cthdr = NULL; +	struct fcgs_gmal_resp_s *gmal_resp; +	struct fc_gmal_entry_s *gmal_entry; +	u32        num_entries; +	u8        *rsp_str; + +	bfa_trc(port->fcs, req_status); +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1); +		num_entries = bfa_os_ntohl(gmal_resp->ms_len); +		if (num_entries == 0) { +			bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +			return; +		} +		/* +		 * The response could contain multiple Entries. +		 * Entries for SNMP interface, etc. +		 * We look for the entry with a telnet prefix. +		 * First "http://" entry refers to IP addr +		 */ + +		gmal_entry = (struct fc_gmal_entry_s *)gmal_resp->ms_ma; +		while (num_entries > 0) { +			if (strncmp +			    (gmal_entry->prefix, CT_GMAL_RESP_PREFIX_HTTP, +			     sizeof(gmal_entry->prefix)) == 0) { + +				/* +				 * if the IP address is terminating with a '/', +				 * remove it. *Byte 0 consists of the length +				 * of the string. +				 */ +				rsp_str = &(gmal_entry->prefix[0]); +				if (rsp_str[gmal_entry->len - 1] == '/') +					rsp_str[gmal_entry->len - 1] = 0; +				/* +				 * copy IP Address to fabric +				 */ +				strncpy(bfa_fcs_port_get_fabric_ipaddr(port), +					gmal_entry->ip_addr, +					BFA_FCS_FABRIC_IPADDR_SZ); +				break; +			} else { +				--num_entries; +				++gmal_entry; +			} +		} + +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); +		return; +	} + +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +} + +static void +bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms, +			       enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), +				       &ms->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { +			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry); +			bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), +					&ms->timer, bfa_fcs_port_ms_timeout, ms, +					BFA_FCS_RETRY_TIMEOUT); +		} else { +			bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); +			ms->retry_cnt = 0; +		} +		break; + +	case MSSM_EVENT_RSP_OK: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_fcxp_discard(ms->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms, +			     enum port_ms_event event) +{ +	bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); +	bfa_trc(ms->port->fcs, event); + +	switch (event) { +	case MSSM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending); +		bfa_fcs_port_ms_send_gfn(ms, NULL); +		break; + +	case MSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); +		bfa_timer_stop(&ms->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + *  ms_pvt MS local functions + */ + +static void +bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ms_s *ms = ms_cbarg; +	struct bfa_fcs_port_s *port = ms->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, +				    bfa_fcs_port_ms_send_gfn, ms); +		return; +	} +	ms->fcxp = fcxp; + +	len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			       bfa_fcs_port_get_fcid(port), +			       bfa_lps_get_peer_nwwn(port->fabric->lps)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response, +		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_port_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			     bfa_status_t req_status, u32 rsp_len, +			       u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; +	struct bfa_fcs_port_s *port = ms->port; +	struct ct_hdr_s       *cthdr = NULL; +	wwn_t          *gfn_resp; + +	bfa_trc(port->fcs, req_status); +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		gfn_resp = (wwn_t *) (cthdr + 1); +		/* +		 * check if it has actually changed +		 */ +		if ((memcmp +		     ((void *)&bfa_fcs_port_get_fabric_name(port), gfn_resp, +		      sizeof(wwn_t)) != 0)) +			bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp); +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); +		return; +	} + +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +} + +/** + *  ms_pvt MS local functions + */ + +static void +bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ms_s *ms = ms_cbarg; +	struct bfa_fcs_port_s *port = ms->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ms_plogi_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, +				    bfa_fcs_port_ms_send_plogi, ms); +		return; +	} +	ms->fcxp = fcxp; + +	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			     bfa_os_hton3b(FC_MGMT_SERVER), +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn, +			     bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response, +		      (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + +	port->stats.ms_plogi_sent++; +	bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_port_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +			       void *cbarg, bfa_status_t req_status, +			       u32 rsp_len, u32 resid_len, +			       struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg; + +	struct bfa_fcs_port_s *port = ms->port; +	struct fc_els_cmd_s   *els_cmd; +	struct fc_ls_rjt_s    *ls_rjt; + +	bfa_trc(port->fcs, req_status); +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		port->stats.ms_plogi_rsp_err++; +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + +	switch (els_cmd->els_code) { + +	case FC_ELS_ACC: +		if (rsp_len < sizeof(struct fc_logi_s)) { +			bfa_trc(port->fcs, rsp_len); +			port->stats.ms_plogi_acc_err++; +			bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +			break; +		} +		port->stats.ms_plogi_accepts++; +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); +		break; + +	case FC_ELS_LS_RJT: +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + +		bfa_trc(port->fcs, ls_rjt->reason_code); +		bfa_trc(port->fcs, ls_rjt->reason_code_expl); + +		port->stats.ms_rejects++; +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +		break; + +	default: +		port->stats.ms_plogi_unknown_rsp++; +		bfa_trc(port->fcs, els_cmd->els_code); +		bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); +	} +} + +static void +bfa_fcs_port_ms_timeout(void *arg) +{ +	struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)arg; + +	ms->port->stats.ms_timeouts++; +	bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT); +} + + +void +bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + +	ms->port = port; +	bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline); + +	/* +	 * Invoke init routines of sub modules. +	 */ +	bfa_fcs_port_fdmi_init(ms); +} + +void +bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + +	ms->port = port; +	bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + +	ms->port = port; +	bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE); +} + +void +bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); + +	/* +	 * @todo.  Handle this only when in Online state +	 */ +	if (bfa_sm_cmp_state(ms, bfa_fcs_port_ms_sm_online)) +		bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN); +} diff --git a/drivers/scsi/bfa/n2n.c b/drivers/scsi/bfa/n2n.c new file mode 100644 index 00000000000..73545682434 --- /dev/null +++ b/drivers/scsi/bfa/n2n.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  n2n.c n2n implementation. + */ +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_trcmod.h" +#include "lport_priv.h" + +BFA_TRC_FILE(FCS, N2N); + +/** + *   Called by fcs/port to initialize N2N topology. + */ +void +bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port) +{ +} + +/** + *   Called by fcs/port to notify transition to online state. + */ +void +bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n; +	struct bfa_port_cfg_s *pcfg = &port->port_cfg; +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, pcfg->pwwn); + +	/* +	 * If our PWWN is > than that of the r-port, we have to initiate PLOGI +	 * and assign an Address. if not, we need to wait for its PLOGI. +	 * +	 * If our PWWN is < than that of the remote port, it will send a PLOGI +	 * with the PIDs assigned. The rport state machine take care of this +	 * incoming PLOGI. +	 */ +	if (memcmp +	    ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn, +	     sizeof(wwn_t)) > 0) { +		port->pid = N2N_LOCAL_PID; +		/** +		 * First, check if we know the device by pwwn. +		 */ +		rport = bfa_fcs_port_get_rport_by_pwwn(port, +						       n2n_port->rem_port_wwn); +		if (rport) { +			bfa_trc(port->fcs, rport->pid); +			bfa_trc(port->fcs, rport->pwwn); +			rport->pid = N2N_REMOTE_PID; +			bfa_fcs_rport_online(rport); +			return; +		} + +		/* +		 * In n2n there can be only one rport. Delete the old one whose +		 * pid should be zero, because it is offline. +		 */ +		if (port->num_rports > 0) { +			rport = bfa_fcs_port_get_rport_by_pid(port, 0); +			bfa_assert(rport != NULL); +			if (rport) { +				bfa_trc(port->fcs, rport->pwwn); +				bfa_fcs_rport_delete(rport); +			} +		} +		bfa_fcs_rport_create(port, N2N_REMOTE_PID); +	} +} + +/** + *   Called by fcs/port to notify transition to offline state. + */ +void +bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n; + +	bfa_trc(port->fcs, port->pid); +	port->pid = 0; +	n2n_port->rem_port_wwn = 0; +	n2n_port->reply_oxid = 0; +} + + diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c new file mode 100644 index 00000000000..59fea99d67a --- /dev/null +++ b/drivers/scsi/bfa/ns.c @@ -0,0 +1,1243 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + * @page ns_sm_info VPORT NS State Machine + * + * @section ns_sm_interactions VPORT NS State Machine Interactions + * + * @section ns_sm VPORT NS State Machine + * 	img ns_sm.jpg + */ +#include <bfa.h> +#include <bfa_svc.h> +#include <bfa_iocfc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs.h" +#include "lport_priv.h" + +BFA_TRC_FILE(FCS, NS); + +/* + * forward declarations + */ +static void     bfa_fcs_port_ns_send_plogi(void *ns_cbarg, +					   struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, +					     struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_ns_timeout(void *arg); +static void     bfa_fcs_port_ns_plogi_response(void *fcsarg, +					       struct bfa_fcxp_s *fcxp, +					       void *cbarg, +					       bfa_status_t req_status, +					       u32 rsp_len, +					       u32 resid_len, +					       struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ns_rspn_id_response(void *fcsarg, +						 struct bfa_fcxp_s *fcxp, +						 void *cbarg, +						 bfa_status_t req_status, +						 u32 rsp_len, +						 u32 resid_len, +						 struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ns_rft_id_response(void *fcsarg, +						struct bfa_fcxp_s *fcxp, +						void *cbarg, +						bfa_status_t req_status, +						u32 rsp_len, +						u32 resid_len, +						struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ns_rff_id_response(void *fcsarg, +						struct bfa_fcxp_s *fcxp, +						void *cbarg, +						bfa_status_t req_status, +						u32 rsp_len, +						u32 resid_len, +						struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ns_gid_ft_response(void *fcsarg, +						struct bfa_fcxp_s *fcxp, +						void *cbarg, +						bfa_status_t req_status, +						u32 rsp_len, +						u32 resid_len, +						struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, +						   u32 *pid_buf, +						   u32 n_pids); + +static void     bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port); +/** + *  fcs_ns_sm FCS nameserver interface state machine + */ + +/** + * VPort NS State Machine events + */ +enum vport_ns_event { +	NSSM_EVENT_PORT_ONLINE = 1, +	NSSM_EVENT_PORT_OFFLINE = 2, +	NSSM_EVENT_PLOGI_SENT = 3, +	NSSM_EVENT_RSP_OK = 4, +	NSSM_EVENT_RSP_ERROR = 5, +	NSSM_EVENT_TIMEOUT = 6, +	NSSM_EVENT_NS_QUERY = 7, +	NSSM_EVENT_RSPNID_SENT = 8, +	NSSM_EVENT_RFTID_SENT = 9, +	NSSM_EVENT_RFFID_SENT = 10, +	NSSM_EVENT_GIDFT_SENT = 11, +}; + +static void     bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, +					   enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, +						 enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, +					 enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, +					       enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, +						   enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, +					   enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, +						 enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, +						  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, +						enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, +					  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, +						  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, +						enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, +					  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, +						  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, +					  enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, +						enum vport_ns_event event); +static void     bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, +					  enum vport_ns_event event); +/** + * 		Start in offline state - awaiting linkup + */ +static void +bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns, +			   enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_PORT_ONLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); +		bfa_fcs_port_ns_send_plogi(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns, +				 enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_PLOGI_SENT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), +				       &ns->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns, +			 enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_retry); +		ns->port->stats.ns_retries++; +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, +				bfa_fcs_port_ns_timeout, ns, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case NSSM_EVENT_RSP_OK: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); +		bfa_fcs_port_ns_send_rspn_id(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_discard(ns->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns, +			       enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending); +		bfa_fcs_port_ns_send_plogi(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_timer_stop(&ns->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns, +				   enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSPNID_SENT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), +				       &ns->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns, +			   enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id_retry); +		ns->port->stats.ns_retries++; +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, +				bfa_fcs_port_ns_timeout, ns, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case NSSM_EVENT_RSP_OK: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); +		bfa_fcs_port_ns_send_rft_id(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_fcxp_discard(ns->fcxp); +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns, +				 enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_TIMEOUT: +		/* +		 * Retry Timer Expired. Re-send +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id); +		bfa_fcs_port_ns_send_rspn_id(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_timer_stop(&ns->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns, +				  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RFTID_SENT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), +				       &ns->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns, +			  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSP_OK: +		/* +		 * Now move to register FC4 Features +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); +		bfa_fcs_port_ns_send_rff_id(ns, NULL); +		break; + +	case NSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id_retry); +		ns->port->stats.ns_retries++; +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, +				bfa_fcs_port_ns_timeout, ns, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_discard(ns->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns, +				enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_TIMEOUT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id); +		bfa_fcs_port_ns_send_rft_id(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_timer_stop(&ns->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns, +				  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RFFID_SENT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), +				       &ns->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns, +			  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSP_OK: + +		/* +		 * If min cfg mode is enabled, we donot initiate rport +		 * discovery with the fabric. Instead, we will retrieve the +		 * boot targets from HAL/FW. +		 */ +		if (__fcs_min_cfg(ns->port->fcs)) { +			bfa_fcs_port_ns_boot_target_disc(ns->port); +			bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); +			return; +		} + +		/* +		 * If the port role is Initiator Mode issue NS query. +		 * If it is Target Mode, skip this and go to online. +		 */ +		if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { +			bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); +			bfa_fcs_port_ns_send_gid_ft(ns, NULL); +		} else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) { +			bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); +		} +		/* +		 * kick off mgmt srvr state machine +		 */ +		bfa_fcs_port_ms_online(ns->port); +		break; + +	case NSSM_EVENT_RSP_ERROR: +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id_retry); +		ns->port->stats.ns_retries++; +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, +				bfa_fcs_port_ns_timeout, ns, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_discard(ns->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns, +				enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_TIMEOUT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id); +		bfa_fcs_port_ns_send_rff_id(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_timer_stop(&ns->timer); +		break; + +	default: +		bfa_assert(0); +	} +} +static void +bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns, +				  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_GIDFT_SENT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), +				       &ns->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns, +			  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_RSP_OK: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online); +		break; + +	case NSSM_EVENT_RSP_ERROR: +		/* +		 * TBD: for certain reject codes, we don't need to retry +		 */ +		/* +		 * Start timer for a delayed retry +		 */ +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft_retry); +		ns->port->stats.ns_retries++; +		bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer, +				bfa_fcs_port_ns_timeout, ns, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_fcxp_discard(ns->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns, +				enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_TIMEOUT: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); +		bfa_fcs_port_ns_send_gid_ft(ns, NULL); +		break; + +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		bfa_timer_stop(&ns->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns, +			  enum vport_ns_event event) +{ +	bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); +	bfa_trc(ns->port->fcs, event); + +	switch (event) { +	case NSSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +		break; + +	case NSSM_EVENT_NS_QUERY: +		/* +		 * If the port role is Initiator Mode issue NS query. +		 * If it is Target Mode, skip this and go to online. +		 */ +		if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { +			bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft); +			bfa_fcs_port_ns_send_gid_ft(ns, NULL); +		}; +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  ns_pvt Nameserver local functions + */ + +static void +bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ns_s *ns = ns_cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ns_plogi_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, +				    bfa_fcs_port_ns_send_plogi, ns); +		return; +	} +	ns->fcxp = fcxp; + +	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			     bfa_os_hton3b(FC_NAME_SERVER), +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn, +			     bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response, +		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); +	port->stats.ns_plogi_sent++; + +	bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); +} + +static void +bfa_fcs_port_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +			       void *cbarg, bfa_status_t req_status, +			       u32 rsp_len, u32 resid_len, +			       struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	/* struct fc_logi_s *plogi_resp; */ +	struct fc_els_cmd_s   *els_cmd; +	struct fc_ls_rjt_s    *ls_rjt; + +	bfa_trc(port->fcs, req_status); +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		port->stats.ns_plogi_rsp_err++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + +	switch (els_cmd->els_code) { + +	case FC_ELS_ACC: +		if (rsp_len < sizeof(struct fc_logi_s)) { +			bfa_trc(port->fcs, rsp_len); +			port->stats.ns_plogi_acc_err++; +			bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +			break; +		} +		port->stats.ns_plogi_accepts++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		break; + +	case FC_ELS_LS_RJT: +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + +		bfa_trc(port->fcs, ls_rjt->reason_code); +		bfa_trc(port->fcs, ls_rjt->reason_code_expl); + +		port->stats.ns_rejects++; + +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		break; + +	default: +		port->stats.ns_plogi_unknown_rsp++; +		bfa_trc(port->fcs, els_cmd->els_code); +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +	} +} + +/** + * Register the symbolic port name. + */ +static void +bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ns_s *ns = ns_cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; +	u8         symbl[256]; +	u8        *psymbl = &symbl[0]; + +	bfa_os_memset(symbl, 0, sizeof(symbl)); + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ns_rspnid_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, +				    bfa_fcs_port_ns_send_rspn_id, ns); +		return; +	} +	ns->fcxp = fcxp; + +	/* +	 * for V-Port, form a Port Symbolic Name +	 */ +	if (port->vport) { +		/**For Vports, +		 *  we append the vport's port symbolic name to that of the base port. +		 */ + +		strncpy((char *)psymbl, +			(char *) +			&(bfa_fcs_port_get_psym_name +			  (bfa_fcs_get_base_port(port->fcs))), +			strlen((char *) +			       &bfa_fcs_port_get_psym_name(bfa_fcs_get_base_port +							   (port->fcs)))); + +		/* +		 * Ensure we have a null terminating string. +		 */ +		((char *) +		 psymbl)[strlen((char *) +				&bfa_fcs_port_get_psym_name +				(bfa_fcs_get_base_port(port->fcs)))] = 0; + +		strncat((char *)psymbl, +			(char *)&(bfa_fcs_port_get_psym_name(port)), +			strlen((char *)&bfa_fcs_port_get_psym_name(port))); +	} else { +		psymbl = (u8 *) &(bfa_fcs_port_get_psym_name(port)); +	} + +	len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			      bfa_fcs_port_get_fcid(port), 0, psymbl); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response, +		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + +	port->stats.ns_rspnid_sent++; + +	bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT); +} + +static void +bfa_fcs_port_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				 void *cbarg, bfa_status_t req_status, +				 u32 rsp_len, u32 resid_len, +				 struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		port->stats.ns_rspnid_rsp_err++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		port->stats.ns_rspnid_accepts++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		return; +	} + +	port->stats.ns_rspnid_rejects++; +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +} + +/** + * Register FC4-Types + * TBD, Need to retrieve this from the OS driver, in case IPFC is enabled ? + */ +static void +bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ns_s *ns = ns_cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ns_rftid_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, +				    bfa_fcs_port_ns_send_rft_id, ns); +		return; +	} +	ns->fcxp = fcxp; + +	len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.roles); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response, +		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + +	port->stats.ns_rftid_sent++; +	bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); +} + +static void +bfa_fcs_port_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				void *cbarg, bfa_status_t req_status, +				u32 rsp_len, u32 resid_len, +				struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		port->stats.ns_rftid_rsp_err++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		port->stats.ns_rftid_accepts++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		return; +	} + +	port->stats.ns_rftid_rejects++; +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); +	bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +} + +/** +* Register FC4-Features : Should be done after RFT_ID + */ +static void +bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ns_s *ns = ns_cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; +	u8         fc4_ftrs = 0; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ns_rffid_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, +				    bfa_fcs_port_ns_send_rff_id, ns); +		return; +	} +	ns->fcxp = fcxp; + +	if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { +		fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR; +	} else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) { +		fc4_ftrs = FC_GS_FCP_FC4_FEATURE_TARGET; +	} + +	len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			     bfa_fcs_port_get_fcid(port), 0, FC_TYPE_FCP, +			     fc4_ftrs); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response, +		      (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + +	port->stats.ns_rffid_sent++; +	bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); +} + +static void +bfa_fcs_port_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				void *cbarg, bfa_status_t req_status, +				u32 rsp_len, u32 resid_len, +				struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct ct_hdr_s       *cthdr = NULL; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		port->stats.ns_rffid_rsp_err++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		port->stats.ns_rffid_accepts++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		return; +	} + +	port->stats.ns_rffid_rejects++; +	bfa_trc(port->fcs, cthdr->reason_code); +	bfa_trc(port->fcs, cthdr->exp_code); + +	if (cthdr->reason_code == CT_RSN_NOT_SUPP) { +		/* +		 * if this command is not supported, we don't retry +		 */ +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +	} else { +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +	} +} + +/** + * Query Fabric for FC4-Types Devices. + * +*  TBD : Need to use a local (FCS private) response buffer, since the response + * can be larger than 2K. + */ +static void +bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_ns_s *ns = ns_cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		port->stats.ns_gidft_alloc_wait++; +		bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, +				    bfa_fcs_port_ns_send_gid_ft, ns); +		return; +	} +	ns->fcxp = fcxp; + +	/* +	 * This query is only initiated for FCP initiator mode. +	 */ +	len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), ns->port->pid, +			      FC_TYPE_FCP); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response, +		      (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa), +		      FC_RA_TOV); + +	port->stats.ns_gidft_sent++; + +	bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT); +} + +static void +bfa_fcs_port_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +				void *cbarg, bfa_status_t req_status, +				u32 rsp_len, u32 resid_len, +				struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg; +	struct bfa_fcs_port_s *port = ns->port; +	struct ct_hdr_s       *cthdr = NULL; +	u32        n_pids; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		port->stats.ns_gidft_rsp_err++; +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		return; +	} + +	if (resid_len != 0) { +		/* +		 * TBD : we will need to allocate a larger buffer & retry the +		 * command +		 */ +		bfa_trc(port->fcs, rsp_len); +		bfa_trc(port->fcs, resid_len); +		return; +	} + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	switch (cthdr->cmd_rsp_code) { + +	case CT_RSP_ACCEPT: + +		port->stats.ns_gidft_accepts++; +		n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32)); +		bfa_trc(port->fcs, n_pids); +		bfa_fcs_port_ns_process_gidft_pids(port, +						   (u32 *) (cthdr + 1), +						   n_pids); +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		break; + +	case CT_RSP_REJECT: + +		/* +		 * Check the reason code  & explanation. +		 * There may not have been any FC4 devices in the fabric +		 */ +		port->stats.ns_gidft_rejects++; +		bfa_trc(port->fcs, cthdr->reason_code); +		bfa_trc(port->fcs, cthdr->exp_code); + +		if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF) +		    && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) { + +			bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); +		} else { +			/* +			 * for all other errors, retry +			 */ +			bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +		} +		break; + +	default: +		port->stats.ns_gidft_unknown_rsp++; +		bfa_trc(port->fcs, cthdr->cmd_rsp_code); +		bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); +	} +} + +/** + *     This routine will be called by bfa_timer on timer timeouts. + * + * 	param[in] 	port 	- pointer to bfa_fcs_port_t. + * + * 	return + * 		void + * +* 	Special Considerations: + * + * 	note + */ +static void +bfa_fcs_port_ns_timeout(void *arg) +{ +	struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)arg; + +	ns->port->stats.ns_timeouts++; +	bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT); +} + +/* + * Process the PID list in GID_FT response + */ +static void +bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port, +				   u32 *pid_buf, u32 n_pids) +{ +	struct fcgs_gidft_resp_s *gidft_entry; +	struct bfa_fcs_rport_s *rport; +	u32        ii; + +	for (ii = 0; ii < n_pids; ii++) { +		gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii]; + +		if (gidft_entry->pid == port->pid) +			continue; + +		/* +		 * Check if this rport already exists +		 */ +		rport = bfa_fcs_port_get_rport_by_pid(port, gidft_entry->pid); +		if (rport == NULL) { +			/* +			 * this is a new device. create rport +			 */ +			rport = bfa_fcs_rport_create(port, gidft_entry->pid); +		} else { +			/* +			 * this rport already exists +			 */ +			bfa_fcs_rport_scn(rport); +		} + +		bfa_trc(port->fcs, gidft_entry->pid); + +		/* +		 * if the last entry bit is set, bail out. +		 */ +		if (gidft_entry->last) +			return; +	} +} + +/** + *  fcs_ns_public FCS nameserver public interfaces + */ + +/* + * Functions called by port/fab. + * These will send relevant Events to the ns state machine. + */ +void +bfa_fcs_port_ns_init(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + +	ns->port = port; +	bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline); +} + +void +bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + +	ns->port = port; +	bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_port_ns_online(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + +	ns->port = port; +	bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE); +} + +void +bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); + +	bfa_trc(port->fcs, port->pid); +	bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY); +} + +static void +bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port) +{ + +	struct bfa_fcs_rport_s *rport; +	u8         nwwns; +	wwn_t          *wwns; +	int             ii; + +	bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns); + +	for (ii = 0; ii < nwwns; ++ii) { +		rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); +		bfa_assert(rport); +	} +} + + diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c new file mode 100644 index 00000000000..86af818d17b --- /dev/null +++ b/drivers/scsi/bfa/plog.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa_os_inc.h> +#include <cs/bfa_plog.h> +#include <cs/bfa_debug.h> + +static int +plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec) +{ +	if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) +	    && (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING)) +		return 1; + +	if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) +	    && (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ)) +		return 1; + +	return 0; +} + +static void +bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec) +{ +	u16        tail; +	struct bfa_plog_rec_s *pl_recp; + +	if (plog->plog_enabled == 0) +		return; + +	if (plkd_validate_logrec(pl_rec)) { +		bfa_assert(0); +		return; +	} + +	tail = plog->tail; + +	pl_recp = &(plog->plog_recs[tail]); + +	bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s)); + +	pl_recp->tv = BFA_TRC_TS(plog); +	BFA_PL_LOG_REC_INCR(plog->tail); + +	if (plog->head == plog->tail) +		BFA_PL_LOG_REC_INCR(plog->head); +} + +void +bfa_plog_init(struct bfa_plog_s *plog) +{ +	bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s)); + +	bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN); +	plog->head = plog->tail = 0; +	plog->plog_enabled = 1; +} + +void +bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +		enum bfa_plog_eid event, +		u16 misc, char *log_str) +{ +	struct bfa_plog_rec_s  lp; + +	if (plog->plog_enabled) { +		bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); +		lp.mid = mid; +		lp.eid = event; +		lp.log_type = BFA_PL_LOG_TYPE_STRING; +		lp.misc = misc; +		strncpy(lp.log_entry.string_log, log_str, +			BFA_PL_STRING_LOG_SZ - 1); +		lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0'; +		bfa_plog_add(plog, &lp); +	} +} + +void +bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +		enum bfa_plog_eid event, +		u16 misc, u32 *intarr, u32 num_ints) +{ +	struct bfa_plog_rec_s  lp; +	u32        i; + +	if (num_ints > BFA_PL_INT_LOG_SZ) +		num_ints = BFA_PL_INT_LOG_SZ; + +	if (plog->plog_enabled) { +		bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); +		lp.mid = mid; +		lp.eid = event; +		lp.log_type = BFA_PL_LOG_TYPE_INT; +		lp.misc = misc; + +		for (i = 0; i < num_ints; i++) +			bfa_os_assign(lp.log_entry.int_log[i], +					intarr[i]); + +		lp.log_num_ints = (u8) num_ints; + +		bfa_plog_add(plog, &lp); +	} +} + +void +bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +			enum bfa_plog_eid event, +			u16 misc, struct fchs_s *fchdr) +{ +	struct bfa_plog_rec_s  lp; +	u32       *tmp_int = (u32 *) fchdr; +	u32        ints[BFA_PL_INT_LOG_SZ]; + +	if (plog->plog_enabled) { +		bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + +		ints[0] = tmp_int[0]; +		ints[1] = tmp_int[1]; +		ints[2] = tmp_int[4]; + +		bfa_plog_intarr(plog, mid, event, misc, ints, 3); +	} +} + +void +bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, +		      enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr, +		      u32 pld_w0) +{ +	struct bfa_plog_rec_s  lp; +	u32       *tmp_int = (u32 *) fchdr; +	u32        ints[BFA_PL_INT_LOG_SZ]; + +	if (plog->plog_enabled) { +		bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); + +		ints[0] = tmp_int[0]; +		ints[1] = tmp_int[1]; +		ints[2] = tmp_int[4]; +		ints[3] = pld_w0; + +		bfa_plog_intarr(plog, mid, event, misc, ints, 4); +	} +} + +void +bfa_plog_clear(struct bfa_plog_s *plog) +{ +	plog->head = plog->tail = 0; +} + +void +bfa_plog_enable(struct bfa_plog_s *plog) +{ +	plog->plog_enabled = 1; +} + +void +bfa_plog_disable(struct bfa_plog_s *plog) +{ +	plog->plog_enabled = 0; +} + +bfa_boolean_t +bfa_plog_get_setting(struct bfa_plog_s *plog) +{ +	return((bfa_boolean_t)plog->plog_enabled); +} diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c new file mode 100644 index 00000000000..9cf58bb138d --- /dev/null +++ b/drivers/scsi/bfa/rport.c @@ -0,0 +1,2618 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  rport.c Remote port implementation. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcbuild.h" +#include "fcs_vport.h" +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_fcpim.h" +#include "fcs_fcptm.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs.h" +#include <fcb/bfa_fcb_rport.h> +#include <aen/bfa_aen_rport.h> + +BFA_TRC_FILE(FCS, RPORT); + +#define BFA_FCS_RPORT_MAX_RETRIES		(5) + +/* In millisecs */ +static u32 bfa_fcs_rport_del_timeout = +			BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000; + +/* + * forward declarations + */ +static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, +						   wwn_t pwwn, u32 rpid); +static void     bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, +				     struct fc_logi_s *plogi); +static void     bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport); +static void     bfa_fcs_rport_timeout(void *arg); +static void     bfa_fcs_rport_send_plogi(void *rport_cbarg, +					 struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rport_send_plogiacc(void *rport_cbarg, +					    struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rport_plogi_response(void *fcsarg, +					     struct bfa_fcxp_s *fcxp, +					     void *cbarg, +					     bfa_status_t req_status, +					     u32 rsp_len, +					     u32 resid_len, +					     struct fchs_s *rsp_fchs); +static void     bfa_fcs_rport_send_adisc(void *rport_cbarg, +					 struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rport_adisc_response(void *fcsarg, +					     struct bfa_fcxp_s *fcxp, +					     void *cbarg, +					     bfa_status_t req_status, +					     u32 rsp_len, +					     u32 resid_len, +					     struct fchs_s *rsp_fchs); +static void     bfa_fcs_rport_send_gidpn(void *rport_cbarg, +					 struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rport_gidpn_response(void *fcsarg, +					     struct bfa_fcxp_s *fcxp, +					     void *cbarg, +					     bfa_status_t req_status, +					     u32 rsp_len, +					     u32 resid_len, +					     struct fchs_s *rsp_fchs); +static void     bfa_fcs_rport_send_logo(void *rport_cbarg, +					struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rport_send_logo_acc(void *rport_cbarg); +static void     bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u16 len); +static void     bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u8 reason_code, +			u8 reason_code_expl); +static void     bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u16 len); +/** + *  fcs_rport_sm FCS rport state machine events + */ + +enum rport_event { +	RPSM_EVENT_PLOGI_SEND = 1,	/*  new rport; start with PLOGI */ +	RPSM_EVENT_PLOGI_RCVD = 2,	/*  Inbound PLOGI from remote port */ +	RPSM_EVENT_PLOGI_COMP = 3,	/*  PLOGI completed to rport */ +	RPSM_EVENT_LOGO_RCVD = 4,	/*  LOGO from remote device */ +	RPSM_EVENT_LOGO_IMP = 5,	/*  implicit logo for SLER */ +	RPSM_EVENT_FCXP_SENT = 6,	/*  Frame from has been sent */ +	RPSM_EVENT_DELETE = 7,	/*  RPORT delete request */ +	RPSM_EVENT_SCN = 8,	/*  state change notification */ +	RPSM_EVENT_ACCEPTED = 9,/*  Good response from remote device */ +	RPSM_EVENT_FAILED = 10,	/*  Request to rport failed.  */ +	RPSM_EVENT_TIMEOUT = 11,	/*  Rport SM timeout event */ +	RPSM_EVENT_HCB_ONLINE = 12,	/*  BFA rport online callback */ +	RPSM_EVENT_HCB_OFFLINE = 13,	/*  BFA rport offline callback */ +	RPSM_EVENT_FC4_OFFLINE = 14,	/*  FC-4 offline complete */ +	RPSM_EVENT_ADDRESS_CHANGE = 15,	/*  Rport's PID has changed */ +	RPSM_EVENT_ADDRESS_DISC = 16	/*  Need to Discover rport's PID */ +}; + +static void     bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, +					enum rport_event event); +static void     bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, +					       enum rport_event event); +static void     bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, +						  enum rport_event event); +static void     bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, +				       enum rport_event event); +static void     bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, +					    enum rport_event event); +static void     bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, +					enum rport_event event); +static void     bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, +						 enum rport_event event); +static void     bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, +					 enum rport_event event); +static void     bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, +					       enum rport_event event); +static void     bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, +				       enum rport_event event); +static void     bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, +					      enum rport_event event); +static void     bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, +					      enum rport_event event); +static void     bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, +					      enum rport_event event); +static void     bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, +					 enum rport_event event); +static void     bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, +						enum rport_event event); +static void     bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, +					      enum rport_event event); +static void     bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); +static void     bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, +					     enum rport_event event); + +static struct bfa_sm_table_s rport_sm_table[] = { +	{BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT}, +	{BFA_SM(bfa_fcs_rport_sm_plogi_sending), BFA_RPORT_PLOGI}, +	{BFA_SM(bfa_fcs_rport_sm_plogiacc_sending), BFA_RPORT_ONLINE}, +	{BFA_SM(bfa_fcs_rport_sm_plogi_retry), BFA_RPORT_PLOGI_RETRY}, +	{BFA_SM(bfa_fcs_rport_sm_plogi), BFA_RPORT_PLOGI}, +	{BFA_SM(bfa_fcs_rport_sm_hal_online), BFA_RPORT_ONLINE}, +	{BFA_SM(bfa_fcs_rport_sm_online), BFA_RPORT_ONLINE}, +	{BFA_SM(bfa_fcs_rport_sm_nsquery_sending), BFA_RPORT_NSQUERY}, +	{BFA_SM(bfa_fcs_rport_sm_nsquery), BFA_RPORT_NSQUERY}, +	{BFA_SM(bfa_fcs_rport_sm_adisc_sending), BFA_RPORT_ADISC}, +	{BFA_SM(bfa_fcs_rport_sm_adisc), BFA_RPORT_ADISC}, +	{BFA_SM(bfa_fcs_rport_sm_fc4_logorcv), BFA_RPORT_LOGORCV}, +	{BFA_SM(bfa_fcs_rport_sm_fc4_logosend), BFA_RPORT_LOGO}, +	{BFA_SM(bfa_fcs_rport_sm_fc4_offline), BFA_RPORT_OFFLINE}, +	{BFA_SM(bfa_fcs_rport_sm_hcb_offline), BFA_RPORT_OFFLINE}, +	{BFA_SM(bfa_fcs_rport_sm_hcb_logorcv), BFA_RPORT_LOGORCV}, +	{BFA_SM(bfa_fcs_rport_sm_hcb_logosend), BFA_RPORT_LOGO}, +	{BFA_SM(bfa_fcs_rport_sm_logo_sending), BFA_RPORT_LOGO}, +	{BFA_SM(bfa_fcs_rport_sm_offline), BFA_RPORT_OFFLINE}, +	{BFA_SM(bfa_fcs_rport_sm_nsdisc_sending), BFA_RPORT_NSDISC}, +	{BFA_SM(bfa_fcs_rport_sm_nsdisc_retry), BFA_RPORT_NSDISC}, +	{BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC}, +}; + +/** + * 		Beginning state. + */ +static void +bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_PLOGI_SEND: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); +		rport->plogi_retries = 0; +		bfa_fcs_rport_send_plogi(rport, NULL); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_fcs_rport_hal_online(rport); +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +	case RPSM_EVENT_ADDRESS_DISC: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		PLOGI is being sent. + */ +static void +bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, +			       enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_SCN: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		PLOGI is being sent. + */ +static void +bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, +				  enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_fcs_rport_hal_online(rport); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * Ignore, SCN is possibly online notification. +		 */ +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_HCB_OFFLINE: +		/** +		 * Ignore BFA callback, on a PLOGI receive we call bfa offline. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		PLOGI is sent. + */ +static void +bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_SCN: +		bfa_timer_stop(&rport->timer); +		/* +		 * !! fall through !! +		 */ + +	case RPSM_EVENT_TIMEOUT: +		rport->plogi_retries++; +		if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) { +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); +			bfa_fcs_rport_send_plogi(rport, NULL); +		} else { +			rport->pid = 0; +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +			bfa_timer_start(rport->fcs->bfa, &rport->timer, +					bfa_fcs_rport_timeout, rport, +					bfa_fcs_rport_del_timeout); +		} +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_timer_stop(&rport->timer); +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_timer_stop(&rport->timer); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_hal_online(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		PLOGI is sent. + */ +static void +bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_ACCEPTED: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		rport->plogi_retries = 0; +		bfa_fcs_rport_hal_online(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_fcs_rport_send_logo_acc(rport); +		bfa_fcxp_discard(rport->fcxp); +		/* +		 * !! fall through !! +		 */ +	case RPSM_EVENT_FAILED: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_discard(rport->fcxp); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_fcxp_discard(rport->fcxp); +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * Ignore SCN - wait for PLOGI response. +		 */ +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_hal_online(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		PLOGI is complete. Awaiting BFA rport online callback. FC-4s + * 		are offline. + */ +static void +bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_HCB_ONLINE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_online); +		bfa_fcs_rport_online_action(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	case RPSM_EVENT_LOGO_IMP: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_rport_offline(rport->bfa_rport); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * @todo +		 * Ignore SCN - PLOGI just completed, FC-4 login should detect +		 * device failures. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport is ONLINE. FC-4s active. + */ +static void +bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_SCN: +		/** +		 * Pause FC-4 activity till rport is authenticated. +		 * In switched fabrics, check presence of device in nameserver +		 * first. +		 */ +		bfa_fcs_rport_fc4_pause(rport); + +		if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsquery_sending); +			rport->ns_retries = 0; +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} else { +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); +			bfa_fcs_rport_send_adisc(rport, NULL); +		} +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +	case RPSM_EVENT_LOGO_IMP: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		An SCN event is received in ONLINE state. NS query is being sent + * 		prior to ADISC authentication with rport. FC-4s are paused. + */ +static void +bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, +				 enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * ignore SCN, wait for response to query itself +		 */ +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +	case RPSM_EVENT_ADDRESS_CHANGE: +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 	An SCN event is received in ONLINE state. NS query is sent to rport. + * 	FC-4s are paused. + */ +static void +bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_ACCEPTED: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); +		bfa_fcs_rport_send_adisc(rport, NULL); +		break; + +	case RPSM_EVENT_FAILED: +		rport->ns_retries++; +		if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsquery_sending); +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} else { +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +			bfa_fcs_rport_offline_action(rport); +		} +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_SCN: +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +	case RPSM_EVENT_ADDRESS_CHANGE: +	case RPSM_EVENT_PLOGI_RCVD: +	case RPSM_EVENT_LOGO_IMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 	An SCN event is received in ONLINE state. ADISC is being sent for + * 	authenticating with rport. FC-4s are paused. + */ +static void +bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, +			       enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_LOGO_IMP: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_SCN: +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_offline_action(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		An SCN event is received in ONLINE state. ADISC is to rport. + * 		FC-4s are paused. + */ +static void +bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_ACCEPTED: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_online); +		bfa_fcs_rport_fc4_resume(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		/** +		 * Too complex to cleanup FC-4 & rport and then acc to PLOGI. +		 * At least go offline when a PLOGI is received. +		 */ +		bfa_fcxp_discard(rport->fcxp); +		/* +		 * !!! fall through !!! +		 */ + +	case RPSM_EVENT_FAILED: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * already processing RSCN +		 */ +		break; + +	case RPSM_EVENT_LOGO_IMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_offline_action(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport has sent LOGO. Awaiting FC-4 offline completion callback. + */ +static void +bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FC4_OFFLINE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +	case RPSM_EVENT_ADDRESS_CHANGE: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		LOGO needs to be sent to rport. Awaiting FC-4 offline completion + * 		callback. + */ +static void +bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, +			      enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FC4_OFFLINE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 	Rport is going offline. Awaiting FC-4 offline completion callback. + */ +static void +bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FC4_OFFLINE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); +		bfa_rport_offline(rport->bfa_rport); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_LOGO_IMP: +	case RPSM_EVENT_LOGO_RCVD: +	case RPSM_EVENT_ADDRESS_CHANGE: +		/** +		 * rport is already going offline. +		 * SCN - ignore and wait till transitioning to offline state +		 */ +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport is offline. FC-4s are offline. Awaiting BFA rport offline + * 		callback. + */ +static void +bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_HCB_OFFLINE: +	case RPSM_EVENT_ADDRESS_CHANGE: +		if (bfa_fcs_port_is_online(rport->port)) { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsdisc_sending); +			rport->ns_retries = 0; +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} else { +			rport->pid = 0; +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +			bfa_timer_start(rport->fcs->bfa, &rport->timer, +					bfa_fcs_rport_timeout, rport, +					bfa_fcs_rport_del_timeout); +		} +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_LOGO_RCVD: +		/** +		 * Ignore, already offline. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport is offline. FC-4s are offline. Awaiting BFA rport offline + * 		callback to send LOGO accept. + */ +static void +bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_HCB_OFFLINE: +	case RPSM_EVENT_ADDRESS_CHANGE: +		if (rport->pid) +			bfa_fcs_rport_send_logo_acc(rport); +		/* +		 * If the lport is online and if the rport is not a well known +		 * address port, we try to re-discover the r-port. +		 */ +		if (bfa_fcs_port_is_online(rport->port) +		    && (!BFA_FCS_PID_IS_WKA(rport->pid))) { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsdisc_sending); +			rport->ns_retries = 0; +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} else { +			/* +			 * if it is not a well known address, reset the pid to +			 * +			 */ +			if (!BFA_FCS_PID_IS_WKA(rport->pid)) +				rport->pid = 0; +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +			bfa_timer_start(rport->fcs->bfa, &rport->timer, +					bfa_fcs_rport_timeout, rport, +					bfa_fcs_rport_del_timeout); +		} +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		/** +		 * Ignore - already processing a LOGO. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Rport is being deleted. FC-4s are offline. Awaiting BFA rport offline + * callback to send LOGO. + */ +static void +bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, +			      enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_HCB_OFFLINE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_logo_sending); +		bfa_fcs_rport_send_logo(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +	case RPSM_EVENT_ADDRESS_CHANGE: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport is being deleted. FC-4s are offline. LOGO is being sent. + */ +static void +bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, +			      enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		/* +		 * Once LOGO is sent, we donot wait for the response +		 */ +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_ADDRESS_CHANGE: +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_free(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Rport is offline. FC-4s are offline. BFA rport is offline. + * 		Timer active to delete stale rport. + */ +static void +bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_TIMEOUT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		bfa_timer_stop(&rport->timer); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +	case RPSM_EVENT_LOGO_IMP: +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_hal_online(rport); +		break; + +	case RPSM_EVENT_PLOGI_SEND: +		bfa_timer_stop(&rport->timer); +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); +		rport->plogi_retries = 0; +		bfa_fcs_rport_send_plogi(rport, NULL); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 	Rport address has changed. Nameserver discovery request is being sent. + */ +static void +bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, +				enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sent); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_LOGO_RCVD: +	case RPSM_EVENT_PLOGI_SEND: +		break; + +	case RPSM_EVENT_ADDRESS_CHANGE: +		rport->ns_retries = 0;	/* reset the retry count */ +		break; + +	case RPSM_EVENT_LOGO_IMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); +		bfa_fcs_rport_hal_online(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * 		Nameserver discovery failed. Waiting for timeout to retry. + */ +static void +bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, +			      enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_TIMEOUT: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_SCN: +	case RPSM_EVENT_ADDRESS_CHANGE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); +		bfa_timer_stop(&rport->timer); +		rport->ns_retries = 0; +		bfa_fcs_rport_send_gidpn(rport, NULL); +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_timer_stop(&rport->timer); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		bfa_fcs_rport_send_logo_acc(rport); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_timer_stop(&rport->timer); +		bfa_fcs_rport_hal_online(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Rport address has changed. Nameserver discovery request is sent. + */ +static void +bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, +			enum rport_event event) +{ +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPSM_EVENT_ACCEPTED: +	case RPSM_EVENT_ADDRESS_CHANGE: +		if (rport->pid) { +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); +			bfa_fcs_rport_send_plogi(rport, NULL); +		} else { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsdisc_sending); +			rport->ns_retries = 0; +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} +		break; + +	case RPSM_EVENT_FAILED: +		rport->ns_retries++; +		if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { +			bfa_sm_set_state(rport, +					 bfa_fcs_rport_sm_nsdisc_sending); +			bfa_fcs_rport_send_gidpn(rport, NULL); +		} else { +			rport->pid = 0; +			bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +			bfa_timer_start(rport->fcs->bfa, &rport->timer, +					bfa_fcs_rport_timeout, rport, +					bfa_fcs_rport_del_timeout); +		}; +		break; + +	case RPSM_EVENT_DELETE: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_free(rport); +		break; + +	case RPSM_EVENT_PLOGI_RCVD: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_send_plogiacc(rport, NULL); +		break; + +	case RPSM_EVENT_LOGO_IMP: +		rport->pid = 0; +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); +		bfa_fcxp_discard(rport->fcxp); +		bfa_timer_start(rport->fcs->bfa, &rport->timer, +				bfa_fcs_rport_timeout, rport, +				bfa_fcs_rport_del_timeout); +		break; + +	case RPSM_EVENT_SCN: +		/** +		 * ignore, wait for NS query response +		 */ +		break; + +	case RPSM_EVENT_LOGO_RCVD: +		/** +		 * Not logged-in yet. Accept LOGO. +		 */ +		bfa_fcs_rport_send_logo_acc(rport); +		break; + +	case RPSM_EVENT_PLOGI_COMP: +		bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); +		bfa_fcxp_discard(rport->fcxp); +		bfa_fcs_rport_hal_online(rport); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  fcs_rport_private FCS RPORT provate functions + */ + +static void +bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(rport->fcs, rport->pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, +				    bfa_fcs_rport_send_plogi, rport); +		return; +	} +	rport->fcxp = fcxp; + +	len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn, +			     bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, +		      (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV); + +	rport->stats.plogis++; +	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			     bfa_status_t req_status, u32 rsp_len, +			     u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; +	struct fc_logi_s	*plogi_rsp; +	struct fc_ls_rjt_s	*ls_rjt; +	struct bfa_fcs_rport_s *twin; +	struct list_head *qe; + +	bfa_trc(rport->fcs, rport->pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(rport->fcs, req_status); +		rport->stats.plogi_failed++; +		bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +		return; +	} + +	plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp); + +	/** +	 * Check for failure first. +	 */ +	if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) { +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + +		bfa_trc(rport->fcs, ls_rjt->reason_code); +		bfa_trc(rport->fcs, ls_rjt->reason_code_expl); + +		rport->stats.plogi_rejects++; +		bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +		return; +	} + +	/** +	 * PLOGI is complete. Make sure this device is not one of the known +	 * device with a new FC port address. +	 */ +	list_for_each(qe, &rport->port->rport_q) { +		twin = (struct bfa_fcs_rport_s *)qe; +		if (twin == rport) +			continue; +		if (!rport->pwwn && (plogi_rsp->port_name == twin->pwwn)) { +			bfa_trc(rport->fcs, twin->pid); +			bfa_trc(rport->fcs, rport->pid); + +			/* +			 * Update plogi stats in twin +			 */ +			twin->stats.plogis += rport->stats.plogis; +			twin->stats.plogi_rejects += rport->stats.plogi_rejects; +			twin->stats.plogi_timeouts += +				rport->stats.plogi_timeouts; +			twin->stats.plogi_failed += rport->stats.plogi_failed; +			twin->stats.plogi_rcvd += rport->stats.plogi_rcvd; +			twin->stats.plogi_accs++; + +			bfa_fcs_rport_delete(rport); + +			bfa_fcs_rport_update(twin, plogi_rsp); +			twin->pid = rsp_fchs->s_id; +			bfa_sm_send_event(twin, RPSM_EVENT_PLOGI_COMP); +			return; +		} +	} + +	/** +	 * Normal login path -- no evil twins. +	 */ +	rport->stats.plogi_accs++; +	bfa_fcs_rport_update(rport, plogi_rsp); +	bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); +} + +static void +bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->reply_oxid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, +				    bfa_fcs_rport_send_plogiacc, rport); +		return; +	} +	rport->fcxp = fcxp; + +	len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +				 bfa_fcs_port_get_fcid(port), rport->reply_oxid, +				 port->port_cfg.pwwn, port->port_cfg.nwwn, +				 bfa_pport_get_maxfrsize(port->fcs->bfa)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); + +	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(rport->fcs, rport->pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, +				    bfa_fcs_rport_send_adisc, rport); +		return; +	} +	rport->fcxp = fcxp; + +	len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +			     bfa_fcs_port_get_fcid(port), 0, +			     port->port_cfg.pwwn, port->port_cfg.nwwn); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response, +		      rport, FC_MAX_PDUSZ, FC_RA_TOV); + +	rport->stats.adisc_sent++; +	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_rport_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			     bfa_status_t req_status, u32 rsp_len, +			     u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; +	void           *pld = bfa_fcxp_get_rspbuf(fcxp); +	struct fc_ls_rjt_s    *ls_rjt; + +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(rport->fcs, req_status); +		rport->stats.adisc_failed++; +		bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +		return; +	} + +	if (fc_adisc_rsp_parse((struct fc_adisc_s *)pld, rsp_len, rport->pwwn, +		rport->nwwn)  == FC_PARSE_OK) { +		rport->stats.adisc_accs++; +		bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); +		return; +	} + +	rport->stats.adisc_rejects++; +	ls_rjt = pld; +	bfa_trc(rport->fcs, ls_rjt->els_cmd.els_code); +	bfa_trc(rport->fcs, ls_rjt->reason_code); +	bfa_trc(rport->fcs, ls_rjt->reason_code_expl); +	bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +} + +static void +bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(rport->fcs, rport->pid); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, +				    bfa_fcs_rport_send_gidpn, rport); +		return; +	} +	rport->fcxp = fcxp; + +	len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +			     bfa_fcs_port_get_fcid(port), 0, rport->pwwn); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response, +		      (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); +} + +static void +bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			     bfa_status_t req_status, u32 rsp_len, +			     u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; +	struct bfa_fcs_rport_s *twin; +	struct list_head *qe; +	struct ct_hdr_s       	*cthdr; +	struct fcgs_gidpn_resp_s	*gidpn_rsp; + +	bfa_trc(rport->fcs, rport->pwwn); + +	cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); +	cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code); + +	if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { +		/* +		 * Check if the pid is the same as before. +		 */ +		gidpn_rsp = (struct fcgs_gidpn_resp_s *) (cthdr + 1); + +		if (gidpn_rsp->dap == rport->pid) { +			/* +			 * Device is online +			 */ +			bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); +		} else { +			/* +			 * Device's PID has changed. We need to cleanup and +			 * re-login. If there is another device with the the +			 * newly discovered pid, send an scn notice so that its +			 * new pid can be discovered. +			 */ +			list_for_each(qe, &rport->port->rport_q) { +				twin = (struct bfa_fcs_rport_s *)qe; +				if (twin == rport) +					continue; +				if (gidpn_rsp->dap == twin->pid) { +					bfa_trc(rport->fcs, twin->pid); +					bfa_trc(rport->fcs, rport->pid); + +					twin->pid = 0; +					bfa_sm_send_event(twin, +						RPSM_EVENT_ADDRESS_CHANGE); +				} +			} +			rport->pid = gidpn_rsp->dap; +			bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_CHANGE); +		} +		return; +	} + +	/* +	 * Reject Response +	 */ +	switch (cthdr->reason_code) { +	case CT_RSN_LOGICAL_BUSY: +		/* +		 * Need to retry +		 */ +		bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); +		break; + +	case CT_RSN_UNABLE_TO_PERF: +		/* +		 * device doesn't exist : Start timer to cleanup this later. +		 */ +		bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +		break; + +	default: +		bfa_sm_send_event(rport, RPSM_EVENT_FAILED); +		break; +	} +} + +/** + *    Called to send a logout to the rport. + */ +static void +bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	u16        len; + +	bfa_trc(rport->fcs, rport->pid); + +	port = rport->port; + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, +				    bfa_fcs_rport_send_logo, rport); +		return; +	} +	rport->fcxp = fcxp; + +	len = fc_logo_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +			    bfa_fcs_port_get_fcid(port), 0, +			    bfa_fcs_port_get_pwwn(port)); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ, +		      FC_ED_TOV); + +	rport->stats.logos++; +	bfa_fcxp_discard(rport->fcxp); +	bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); +} + +/** + *    Send ACC for a LOGO received. + */ +static void +bfa_fcs_rport_send_logo_acc(void *rport_cbarg) +{ +	struct bfa_fcs_rport_s *rport = rport_cbarg; +	struct bfa_fcs_port_s *port; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	u16        len; + +	bfa_trc(rport->fcs, rport->pid); + +	port = rport->port; + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	rport->stats.logo_rcvd++; +	len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +				bfa_fcs_port_get_fcid(port), rport->reply_oxid); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); +} + +/** + *     This routine will be called by bfa_timer on timer timeouts. + * + * 	param[in] 	rport 			- pointer to bfa_fcs_port_ns_t. + * 	param[out]	rport_status 	- pointer to return vport status in + * + * 	return + * 		void + * +*  	Special Considerations: + * + * 	note + */ +static void +bfa_fcs_rport_timeout(void *arg) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)arg; + +	rport->stats.plogi_timeouts++; +	bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); +} + +static void +bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u16 len) +{ +	struct bfa_fcxp_s *fcxp; +	struct fchs_s          fchs; +	struct bfa_fcs_port_s *port = rport->port; +	struct fc_prli_s      *prli; + +	bfa_trc(port->fcs, rx_fchs->s_id); +	bfa_trc(port->fcs, rx_fchs->d_id); + +	rport->stats.prli_rcvd++; + +	if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) { +		/* +		 * Target Mode : Let the fcptm handle it +		 */ +		bfa_fcs_tin_rx_prli(rport->tin, rx_fchs, len); +		return; +	} + +	/* +	 * We are either in Initiator or ipfc Mode +	 */ +	prli = (struct fc_prli_s *) (rx_fchs + 1); + +	if (prli->parampage.servparams.initiator) { +		bfa_trc(rport->fcs, prli->parampage.type); +		rport->scsi_function = BFA_RPORT_INITIATOR; +		bfa_fcs_itnim_is_initiator(rport->itnim); +	} else { +		/* +		 * @todo: PRLI from a target ? +		 */ +		bfa_trc(port->fcs, rx_fchs->s_id); +		rport->scsi_function = BFA_RPORT_TARGET; +	} + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +				bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, +				port->port_cfg.roles); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); +} + +static void +bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u16 len) +{ +	struct bfa_fcxp_s *fcxp; +	struct fchs_s          fchs; +	struct bfa_fcs_port_s *port = rport->port; +	struct fc_rpsc_speed_info_s speeds; +	struct bfa_pport_attr_s pport_attr; + +	bfa_trc(port->fcs, rx_fchs->s_id); +	bfa_trc(port->fcs, rx_fchs->d_id); + +	rport->stats.rpsc_rcvd++; +	speeds.port_speed_cap = +		RPSC_SPEED_CAP_1G | RPSC_SPEED_CAP_2G | RPSC_SPEED_CAP_4G | +		RPSC_SPEED_CAP_8G; + +	/* +	 * get curent speed from pport attributes from BFA +	 */ +	bfa_pport_get_attr(port->fcs->bfa, &pport_attr); + +	speeds.port_op_speed = fc_bfa_speed_to_rpsc_operspeed(pport_attr.speed); + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +				bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, +				&speeds); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); +} + +static void +bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, +			struct fchs_s *rx_fchs, u16 len) +{ +	struct bfa_fcxp_s *fcxp; +	struct fchs_s          fchs; +	struct bfa_fcs_port_s *port = rport->port; +	struct fc_adisc_s      *adisc; + +	bfa_trc(port->fcs, rx_fchs->s_id); +	bfa_trc(port->fcs, rx_fchs->d_id); + +	rport->stats.adisc_rcvd++; + +	if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) { +		/* +		 * @todo : Target Mode handling +		 */ +		bfa_trc(port->fcs, rx_fchs->d_id); +		bfa_assert(0); +		return; +	} + +	adisc = (struct fc_adisc_s *) (rx_fchs + 1); + +	/* +	 * Accept if the itnim for this rport is online. Else reject the ADISC +	 */ +	if (bfa_fcs_itnim_get_online_state(rport->itnim) == BFA_STATUS_OK) { + +		fcxp = bfa_fcs_fcxp_alloc(port->fcs); +		if (!fcxp) +			return; + +		len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +					 rx_fchs->s_id, +					 bfa_fcs_port_get_fcid(port), +					 rx_fchs->ox_id, port->port_cfg.pwwn, +					 port->port_cfg.nwwn); + +		bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, +			      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, +			      FC_MAX_PDUSZ, 0); +	} else { +		rport->stats.adisc_rejected++; +		bfa_fcs_rport_send_ls_rjt(rport, rx_fchs, +					  FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD, +					  FC_LS_RJT_EXP_LOGIN_REQUIRED); +	} + +} + +static void +bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_port_s *port = rport->port; +	struct bfa_rport_info_s rport_info; + +	rport_info.pid = rport->pid; +	rport_info.local_pid = port->pid; +	rport_info.lp_tag = port->lp_tag; +	rport_info.vf_id = port->fabric->vf_id; +	rport_info.vf_en = port->fabric->is_vf; +	rport_info.fc_class = rport->fc_cos; +	rport_info.cisc = rport->cisc; +	rport_info.max_frmsz = rport->maxfrsize; +	bfa_rport_online(rport->bfa_rport, &rport_info); +} + +static void +bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport) +{ +	if (bfa_fcs_port_is_initiator(rport->port)) +		bfa_fcs_itnim_pause(rport->itnim); + +	if (bfa_fcs_port_is_target(rport->port)) +		bfa_fcs_tin_pause(rport->tin); +} + +static void +bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport) +{ +	if (bfa_fcs_port_is_initiator(rport->port)) +		bfa_fcs_itnim_resume(rport->itnim); + +	if (bfa_fcs_port_is_target(rport->port)) +		bfa_fcs_tin_resume(rport->tin); +} + +static struct bfa_fcs_rport_s * +bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid) +{ +	struct bfa_fcs_s *fcs = port->fcs; +	struct bfa_fcs_rport_s *rport; +	struct bfad_rport_s *rport_drv; + +	/** +	 * allocate rport +	 */ +	if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv) +	    != BFA_STATUS_OK) { +		bfa_trc(fcs, rpid); +		return NULL; +	} + +	/* +	 * Initialize r-port +	 */ +	rport->port = port; +	rport->fcs = fcs; +	rport->rp_drv = rport_drv; +	rport->pid = rpid; +	rport->pwwn = pwwn; + +	/** +	 * allocate BFA rport +	 */ +	rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport); +	if (!rport->bfa_rport) { +		bfa_trc(fcs, rpid); +		kfree(rport_drv); +		return NULL; +	} + +	/** +	 * allocate FC-4s +	 */ +	bfa_assert(bfa_fcs_port_is_initiator(port) ^ +		   bfa_fcs_port_is_target(port)); + +	if (bfa_fcs_port_is_initiator(port)) { +		rport->itnim = bfa_fcs_itnim_create(rport); +		if (!rport->itnim) { +			bfa_trc(fcs, rpid); +			bfa_rport_delete(rport->bfa_rport); +			kfree(rport_drv); +			return NULL; +		} +	} + +	if (bfa_fcs_port_is_target(port)) { +		rport->tin = bfa_fcs_tin_create(rport); +		if (!rport->tin) { +			bfa_trc(fcs, rpid); +			bfa_rport_delete(rport->bfa_rport); +			kfree(rport_drv); +			return NULL; +		} +	} + +	bfa_fcs_port_add_rport(port, rport); + +	bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); + +	/* +	 * Initialize the Rport Features(RPF) Sub Module +	 */ +	if (!BFA_FCS_PID_IS_WKA(rport->pid)) +		bfa_fcs_rpf_init(rport); + +	return rport; +} + + +static void +bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_port_s *port = rport->port; + +	/** +	 * - delete FC-4s +	 * - delete BFA rport +	 * - remove from queue of rports +	 */ +	if (bfa_fcs_port_is_initiator(port)) +		bfa_fcs_itnim_delete(rport->itnim); + +	if (bfa_fcs_port_is_target(port)) +		bfa_fcs_tin_delete(rport->tin); + +	bfa_rport_delete(rport->bfa_rport); +	bfa_fcs_port_del_rport(port, rport); +	kfree(rport->rp_drv); +} + +static void +bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport, +		       enum bfa_rport_aen_event event, +		       struct bfa_rport_aen_data_s *data) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = rport->fcs->logm; +	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(rport->port); +	wwn_t           rpwwn = rport->pwwn; +	char            lpwwn_ptr[BFA_STRING_32]; +	char            rpwwn_ptr[BFA_STRING_32]; +	char           *prio_str[] = { "unknown", "high", "medium", "low" }; + +	wwn2str(lpwwn_ptr, lpwwn); +	wwn2str(rpwwn_ptr, rpwwn); + +	switch (event) { +	case BFA_RPORT_AEN_ONLINE: +		bfa_log(logmod, BFA_AEN_RPORT_ONLINE, rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_RPORT_AEN_OFFLINE: +		bfa_log(logmod, BFA_AEN_RPORT_OFFLINE, rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_RPORT_AEN_DISCONNECT: +		bfa_log(logmod, BFA_AEN_RPORT_DISCONNECT, rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_RPORT_AEN_QOS_PRIO: +		aen_data.rport.priv.qos = data->priv.qos; +		bfa_log(logmod, BFA_AEN_RPORT_QOS_PRIO, +			prio_str[aen_data.rport.priv.qos.qos_priority], +			rpwwn_ptr, lpwwn_ptr); +		break; +	case BFA_RPORT_AEN_QOS_FLOWID: +		aen_data.rport.priv.qos = data->priv.qos; +		bfa_log(logmod, BFA_AEN_RPORT_QOS_FLOWID, +			aen_data.rport.priv.qos.qos_flow_id, rpwwn_ptr, +			lpwwn_ptr); +		break; +	default: +		break; +	} + +	aen_data.rport.vf_id = rport->port->fabric->vf_id; +	aen_data.rport.ppwwn = +		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(rport->fcs)); +	aen_data.rport.lpwwn = lpwwn; +	aen_data.rport.rpwwn = rpwwn; +} + +static void +bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_port_s *port = rport->port; + +	rport->stats.onlines++; + +	if (bfa_fcs_port_is_initiator(port)) { +		bfa_fcs_itnim_rport_online(rport->itnim); +		if (!BFA_FCS_PID_IS_WKA(rport->pid)) +			bfa_fcs_rpf_rport_online(rport); +	}; + +	if (bfa_fcs_port_is_target(port)) +		bfa_fcs_tin_rport_online(rport->tin); + +	/* +	 * Don't post events for well known addresses +	 */ +	if (!BFA_FCS_PID_IS_WKA(rport->pid)) +		bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL); +} + +static void +bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_port_s *port = rport->port; + +	rport->stats.offlines++; + +	/* +	 * Don't post events for well known addresses +	 */ +	if (!BFA_FCS_PID_IS_WKA(rport->pid)) { +		if (bfa_fcs_port_is_online(rport->port) == BFA_TRUE) { +			bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_DISCONNECT, +					       NULL); +		} else { +			bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_OFFLINE, +					       NULL); +		} +	} + +	if (bfa_fcs_port_is_initiator(port)) { +		bfa_fcs_itnim_rport_offline(rport->itnim); +		if (!BFA_FCS_PID_IS_WKA(rport->pid)) +			bfa_fcs_rpf_rport_offline(rport); +	} + +	if (bfa_fcs_port_is_target(port)) +		bfa_fcs_tin_rport_offline(rport->tin); +} + +/** + * Update rport parameters from PLOGI or PLOGI accept. + */ +static void +bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) +{ +	struct bfa_fcs_port_s *port = rport->port; + +	/** +	 * - port name +	 * - node name +	 */ +	rport->pwwn = plogi->port_name; +	rport->nwwn = plogi->node_name; + +	/** +	 * - class of service +	 */ +	rport->fc_cos = 0; +	if (plogi->class3.class_valid) +		rport->fc_cos = FC_CLASS_3; + +	if (plogi->class2.class_valid) +		rport->fc_cos |= FC_CLASS_2; + +	/** +	 * - CISC +	 * - MAX receive frame size +	 */ +	rport->cisc = plogi->csp.cisc; +	rport->maxfrsize = bfa_os_ntohs(plogi->class3.rxsz); + +	bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred)); +	bfa_trc(port->fcs, port->fabric->bb_credit); +	/** +	 * Direct Attach P2P mode : +	 * This is to handle a bug (233476) in IBM targets in Direct Attach +	 * Mode. Basically, in FLOGI Accept the target would have erroneously +	 * set the BB Credit to the value used in the FLOGI sent by the HBA. +	 * It uses the correct value (its own BB credit) in PLOGI. +	 */ +	if ((!bfa_fcs_fabric_is_switched(port->fabric)) +	    && (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) { + +		bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred)); +		bfa_trc(port->fcs, port->fabric->bb_credit); + +		port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred); +		bfa_pport_set_tx_bbcredit(port->fcs->bfa, +					  port->fabric->bb_credit); +	} + +} + +/** + *   Called to handle LOGO received from an existing remote port. + */ +static void +bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) +{ +	rport->reply_oxid = fchs->ox_id; +	bfa_trc(rport->fcs, rport->reply_oxid); + +	rport->stats.logo_rcvd++; +	bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD); +} + + + +/** + *  fcs_rport_public FCS rport public interfaces + */ + +/** + * 	Called by bport/vport to create a remote port instance for a discovered + * 	remote device. + * + * @param[in] port	- base port or vport + * @param[in] rpid	- remote port ID + * + * @return None + */ +struct bfa_fcs_rport_s * +bfa_fcs_rport_create(struct bfa_fcs_port_s *port, u32 rpid) +{ +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, rpid); +	rport = bfa_fcs_rport_alloc(port, WWN_NULL, rpid); +	if (!rport) +		return NULL; + +	bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND); +	return rport; +} + +/** + * Called to create a rport for which only the wwn is known. + * + * @param[in] port	- base port + * @param[in] rpwwn	- remote port wwn + * + * @return None + */ +struct bfa_fcs_rport_s * +bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn) +{ +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, rpwwn); +	rport = bfa_fcs_rport_alloc(port, rpwwn, 0); +	if (!rport) +		return NULL; + +	bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC); +	return rport; +} + +/** + * Called by bport in private loop topology to indicate that a + * rport has been discovered and plogi has been completed. + * + * @param[in] port	- base port or vport + * @param[in] rpid	- remote port ID + */ +void +bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *fchs, +			struct fc_logi_s *plogi) +{ +	struct bfa_fcs_rport_s *rport; + +	rport = bfa_fcs_rport_alloc(port, WWN_NULL, fchs->s_id); +	if (!rport) +		return; + +	bfa_fcs_rport_update(rport, plogi); + +	bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP); +} + +/** + *   Called by bport/vport to handle PLOGI received from a new remote port. + *   If an existing rport does a plogi, it will be handled separately. + */ +void +bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, struct fchs_s *fchs, +			   struct fc_logi_s *plogi) +{ +	struct bfa_fcs_rport_s *rport; + +	rport = bfa_fcs_rport_alloc(port, plogi->port_name, fchs->s_id); +	if (!rport) +		return; + +	bfa_fcs_rport_update(rport, plogi); + +	rport->reply_oxid = fchs->ox_id; +	bfa_trc(rport->fcs, rport->reply_oxid); + +	rport->stats.plogi_rcvd++; +	bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); +} + +static int +wwn_compare(wwn_t wwn1, wwn_t wwn2) +{ +	u8        *b1 = (u8 *) &wwn1; +	u8        *b2 = (u8 *) &wwn2; +	int             i; + +	for (i = 0; i < sizeof(wwn_t); i++) { +		if (b1[i] < b2[i]) +			return -1; +		if (b1[i] > b2[i]) +			return 1; +	} +	return 0; +} + +/** + *   Called by bport/vport to handle PLOGI received from an existing + * 	 remote port. + */ +void +bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, +		    struct fc_logi_s *plogi) +{ +	/** +	 * @todo Handle P2P and initiator-initiator. +	 */ + +	bfa_fcs_rport_update(rport, plogi); + +	rport->reply_oxid = rx_fchs->ox_id; +	bfa_trc(rport->fcs, rport->reply_oxid); + +	/** +	 * In Switched fabric topology, +	 * PLOGI to each other. If our pwwn is smaller, ignore it, +	 * if it is not a well known address. +	 * If the link topology is N2N, +	 * this Plogi should be accepted. +	 */ +	if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1) +	    && (bfa_fcs_fabric_is_switched(rport->port->fabric)) +	    && (!BFA_FCS_PID_IS_WKA(rport->pid))) { +		bfa_trc(rport->fcs, rport->pid); +		return; +	} + +	rport->stats.plogi_rcvd++; +	bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); +} + +/** + * Called by bport/vport to delete a remote port instance. + * +* Rport delete is called under the following conditions: + * 		- vport is deleted + * 		- vf is deleted + * 		- explicit request from OS to delete rport (vmware) + */ +void +bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_DELETE); +} + +/** + * Called by bport/vport to  when a target goes offline. + * + */ +void +bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP); +} + +/** + * Called by bport in n2n when a target (attached port) becomes online. + * + */ +void +bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND); +} + +/** + *   Called by bport/vport to notify SCN for the remote port + */ +void +bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport) +{ + +	rport->stats.rscns++; +	bfa_sm_send_event(rport, RPSM_EVENT_SCN); +} + +/** + *   Called by  fcpim to notify that the ITN cleanup is done. + */ +void +bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE); +} + +/** + *   Called by fcptm to notify that the ITN cleanup is done. + */ +void +bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE); +} + +/** + *     This routine BFA callback for bfa_rport_online() call. + * + * 	param[in] 	cb_arg	-  rport struct. + * + * 	return + * 		void + * +* 	Special Considerations: + * + * 	note + */ +void +bfa_cb_rport_online(void *cbarg) +{ + +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE); +} + +/** + *     This routine BFA callback for bfa_rport_offline() call. + * + * 	param[in] 	rport 	- + * + * 	return + * 		void + * + * 	Special Considerations: + * + * 	note + */ +void +bfa_cb_rport_offline(void *cbarg) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE); +} + +/** + * This routine is a static BFA callback when there is a QoS flow_id + * change notification + * + * @param[in] 	rport 	- + * + * @return  	void + * + * Special Considerations: + * + * @note + */ +void +bfa_cb_rport_qos_scn_flowid(void *cbarg, +			    struct bfa_rport_qos_attr_s old_qos_attr, +			    struct bfa_rport_qos_attr_s new_qos_attr) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; +	struct bfa_rport_aen_data_s aen_data; + +	bfa_trc(rport->fcs, rport->pwwn); +	aen_data.priv.qos = new_qos_attr; +	bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data); +} + +/** + * This routine is a static BFA callback when there is a QoS priority + * change notification + * + * @param[in] 	rport 	- + * + * @return 	void + * + * Special Considerations: + * + * @note + */ +void +bfa_cb_rport_qos_scn_prio(void *cbarg, struct bfa_rport_qos_attr_s old_qos_attr, +			  struct bfa_rport_qos_attr_s new_qos_attr) +{ +	struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg; +	struct bfa_rport_aen_data_s aen_data; + +	bfa_trc(rport->fcs, rport->pwwn); +	aen_data.priv.qos = new_qos_attr; +	bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data); +} + +/** + * 		Called to process any unsolicted frames from this remote port + */ +void +bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport) +{ +	bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP); +} + +/** + * 		Called to process any unsolicted frames from this remote port + */ +void +bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, +			u16 len) +{ +	struct bfa_fcs_port_s *port = rport->port; +	struct fc_els_cmd_s   *els_cmd; + +	bfa_trc(rport->fcs, fchs->s_id); +	bfa_trc(rport->fcs, fchs->d_id); +	bfa_trc(rport->fcs, fchs->type); + +	if (fchs->type != FC_TYPE_ELS) +		return; + +	els_cmd = (struct fc_els_cmd_s *) (fchs + 1); + +	bfa_trc(rport->fcs, els_cmd->els_code); + +	switch (els_cmd->els_code) { +	case FC_ELS_LOGO: +		bfa_fcs_rport_process_logo(rport, fchs); +		break; + +	case FC_ELS_ADISC: +		bfa_fcs_rport_process_adisc(rport, fchs, len); +		break; + +	case FC_ELS_PRLO: +		if (bfa_fcs_port_is_initiator(port)) +			bfa_fcs_fcpim_uf_recv(rport->itnim, fchs, len); + +		if (bfa_fcs_port_is_target(port)) +			bfa_fcs_fcptm_uf_recv(rport->tin, fchs, len); +		break; + +	case FC_ELS_PRLI: +		bfa_fcs_rport_process_prli(rport, fchs, len); +		break; + +	case FC_ELS_RPSC: +		bfa_fcs_rport_process_rpsc(rport, fchs, len); +		break; + +	default: +		bfa_fcs_rport_send_ls_rjt(rport, fchs, +					  FC_LS_RJT_RSN_CMD_NOT_SUPP, +					  FC_LS_RJT_EXP_NO_ADDL_INFO); +		break; +	} +} + +/* + * Send a LS reject + */ +static void +bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, +			  u8 reason_code, u8 reason_code_expl) +{ +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	int             len; + +	bfa_trc(rport->fcs, rx_fchs->s_id); + +	fcxp = bfa_fcs_fcxp_alloc(rport->fcs); +	if (!fcxp) +		return; + +	len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id, +			      reason_code, reason_code_expl); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); +} + +/** + *   Module initialization + */ +void +bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs) +{ +} + +/** + *   Module cleanup + */ +void +bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} + +/** + * Return state of rport. + */ +int +bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport) +{ +	return bfa_sm_to_state(rport_sm_table, rport->sm); +} + +/** + * 		 Called by the Driver to set rport delete/ageout timeout + * + * 	param[in]		rport timeout value in seconds. + * + * 	return None + */ +void +bfa_fcs_rport_set_del_timeout(u8 rport_tmo) +{ +	/* +	 * convert to Millisecs +	 */ +	if (rport_tmo > 0) +		bfa_fcs_rport_del_timeout = rport_tmo * 1000; +} diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c new file mode 100644 index 00000000000..3dae1774181 --- /dev/null +++ b/drivers/scsi/bfa/rport_api.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_vport.h" +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_trcmod.h" + +BFA_TRC_FILE(FCS, RPORT_API); + +/** + *  rport_api.c Remote port implementation. + */ + +/** + *  fcs_rport_api FCS rport API. + */ + +/** + * 	Direct API to add a target by port wwn. This interface is used, for + *	example, by bios when target pwwn is known from boot lun configuration. + */ +bfa_status_t +bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn, +			struct bfa_fcs_rport_s *rport, +			struct bfad_rport_s *rport_drv) +{ +	bfa_trc(port->fcs, *pwwn); + +	return BFA_STATUS_OK; +} + +/** + *	Direct API to remove a target and its associated resources. This + *	interface is used, for example, by vmware driver to remove target + *	ports from the target list for a VM. + */ +bfa_status_t +bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in) +{ + +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(rport_in->fcs, rport_in->pwwn); + +	rport = bfa_fcs_port_get_rport_by_pwwn(rport_in->port, rport_in->pwwn); +	if (rport == NULL) { +		/* +		 * TBD Error handling +		 */ +		bfa_trc(rport_in->fcs, rport_in->pid); +		return BFA_STATUS_UNKNOWN_RWWN; +	} + +	/* +	 * TBD if this remote port is online, send a logo +	 */ +	return BFA_STATUS_OK; + +} + +/** + *	Remote device status for display/debug. + */ +void +bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, +			struct bfa_rport_attr_s *rport_attr) +{ +	struct bfa_rport_qos_attr_s qos_attr; +	struct bfa_fcs_port_s *port = rport->port; + +	bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); + +	rport_attr->pid = rport->pid; +	rport_attr->pwwn = rport->pwwn; +	rport_attr->nwwn = rport->nwwn; +	rport_attr->cos_supported = rport->fc_cos; +	rport_attr->df_sz = rport->maxfrsize; +	rport_attr->state = bfa_fcs_rport_get_state(rport); +	rport_attr->fc_cos = rport->fc_cos; +	rport_attr->cisc = rport->cisc; +	rport_attr->scsi_function = rport->scsi_function; +	rport_attr->curr_speed  = rport->rpf.rpsc_speed; +	rport_attr->assigned_speed  = rport->rpf.assigned_speed; + +	bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr); +	rport_attr->qos_attr = qos_attr; + +	rport_attr->trl_enforced = BFA_FALSE; +	if (bfa_pport_is_ratelim(port->fcs->bfa)) { +		if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) || +			(rport->rpf.rpsc_speed < +			bfa_fcs_port_get_rport_max_speed(port))) +			rport_attr->trl_enforced = BFA_TRUE; +	} + +	/* +	 * TODO +	 * rport->symname +	 */ +} + +/** + * 	Per remote device statistics. + */ +void +bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport, +			struct bfa_rport_stats_s *stats) +{ +	*stats = rport->stats; +} + +void +bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport) +{ +	bfa_os_memset((char *)&rport->stats, 0, +			sizeof(struct bfa_rport_stats_s)); +} + +struct bfa_fcs_rport_s * +bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn) +{ +	struct bfa_fcs_rport_s *rport; + +	rport = bfa_fcs_port_get_rport_by_pwwn(port, rpwwn); +	if (rport == NULL) { +		/* +		 * TBD Error handling +		 */ +	} + +	return rport; +} + +struct bfa_fcs_rport_s * +bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_port_s *port, wwn_t rnwwn) +{ +	struct bfa_fcs_rport_s *rport; + +	rport = bfa_fcs_port_get_rport_by_nwwn(port, rnwwn); +	if (rport == NULL) { +		/* +		 * TBD Error handling +		 */ +	} + +	return rport; +} + +/* + * This API is to set the Rport's speed. Should be used when RPSC is not + * supported by the rport. + */ +void +bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport, +			enum bfa_pport_speed speed) +{ +	rport->rpf.assigned_speed  = speed; + +	/* Set this speed in f/w only if the RPSC speed is not available */ +	if (rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) +		bfa_rport_speed(rport->bfa_rport, speed); +} + + diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c new file mode 100644 index 00000000000..8a1f59d596c --- /dev/null +++ b/drivers/scsi/bfa/rport_ftrs.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  rport_ftrs.c Remote port features (RPF) implementation. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcbuild.h" +#include "fcs_rport.h" +#include "fcs_lport.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs.h" + +BFA_TRC_FILE(FCS, RPORT_FTRS); + +#define BFA_FCS_RPF_RETRIES	(3) +#define BFA_FCS_RPF_RETRY_TIMEOUT  (1000) /* 1 sec (In millisecs) */ + +static void     bfa_fcs_rpf_send_rpsc2(void *rport_cbarg, +			struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_rpf_rpsc2_response(void *fcsarg, +			struct bfa_fcxp_s *fcxp, void *cbarg, +			bfa_status_t req_status, u32 rsp_len, +			u32 resid_len, +			struct fchs_s *rsp_fchs); +static void     bfa_fcs_rpf_timeout(void *arg); + +/** + *  fcs_rport_ftrs_sm FCS rport state machine events + */ + +enum rpf_event { +	RPFSM_EVENT_RPORT_OFFLINE  = 1,     /*  Rport offline            */ +	RPFSM_EVENT_RPORT_ONLINE   = 2,     /*  Rport online            */ +	RPFSM_EVENT_FCXP_SENT      = 3,    /*  Frame from has been sent */ +	RPFSM_EVENT_TIMEOUT  	   = 4,    /*  Rport SM timeout event   */ +	RPFSM_EVENT_RPSC_COMP      = 5, +	RPFSM_EVENT_RPSC_FAIL      = 6, +	RPFSM_EVENT_RPSC_ERROR     = 7, +}; + +static void	bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, +					enum rpf_event event); +static void     bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, +					       enum rpf_event event); +static void     bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, +					       enum rpf_event event); +static void 	bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, +							enum rpf_event event); +static void     bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, +							enum rpf_event event); +static void     bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, +							enum rpf_event event); + +static void +bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_RPORT_ONLINE : +		if (!BFA_FCS_PID_IS_WKA(rport->pid)) { +			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); +			rpf->rpsc_retries = 0; +			bfa_fcs_rpf_send_rpsc2(rpf, NULL); +			break; +		}; + +	case RPFSM_EVENT_RPORT_OFFLINE : +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_FCXP_SENT: +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc); +		break; + +	case RPFSM_EVENT_RPORT_OFFLINE : +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); +		bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe); +		rpf->rpsc_retries = 0; +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_RPSC_COMP: +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); +		/* Update speed info in f/w via BFA */ +		if (rpf->rpsc_speed != BFA_PPORT_SPEED_UNKNOWN) { +			bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed); +		} else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN) { +			bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed); +		} +		break; + +	case RPFSM_EVENT_RPSC_FAIL: +		/* RPSC not supported by rport */ +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); +		break; + +	case RPFSM_EVENT_RPSC_ERROR: +		/* need to retry...delayed a bit. */ +		if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) { +			bfa_timer_start(rport->fcs->bfa, &rpf->timer, +				    bfa_fcs_rpf_timeout, rpf, +				    BFA_FCS_RPF_RETRY_TIMEOUT); +			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry); +		} else { +			bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); +		} +		break; + +	case RPFSM_EVENT_RPORT_OFFLINE : +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); +		bfa_fcxp_discard(rpf->fcxp); +		rpf->rpsc_retries = 0; +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_TIMEOUT : +		/* re-send the RPSC */ +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); +		bfa_fcs_rpf_send_rpsc2(rpf, NULL); +		break; + +	case RPFSM_EVENT_RPORT_OFFLINE : +		bfa_timer_stop(&rpf->timer); +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); +		rpf->rpsc_retries = 0; +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_RPORT_OFFLINE : +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); +		rpf->rpsc_retries = 0; +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) +{ +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pwwn); +	bfa_trc(rport->fcs, rport->pid); +	bfa_trc(rport->fcs, event); + +	switch (event) { +	case RPFSM_EVENT_RPORT_ONLINE : +		bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); +		bfa_fcs_rpf_send_rpsc2(rpf, NULL); +		break; + +	case RPFSM_EVENT_RPORT_OFFLINE : +		break; + +	default: +		bfa_assert(0); +	} +} +/** + * Called when Rport is created. + */ +void  bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport) +{ +	struct bfa_fcs_rpf_s *rpf = &rport->rpf; + +	bfa_trc(rport->fcs, rport->pid); +	rpf->rport = rport; + +	bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit); +} + +/** + * Called when Rport becomes online + */ +void  bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport) +{ +	bfa_trc(rport->fcs, rport->pid); + +	if (__fcs_min_cfg(rport->port->fcs)) +		return; + +	if (bfa_fcs_fabric_is_switched(rport->port->fabric)) +		bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE); +} + +/** + * Called when Rport becomes offline + */ +void  bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport) +{ +	bfa_trc(rport->fcs, rport->pid); + +	if (__fcs_min_cfg(rport->port->fcs)) +		return; + +	bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE); +} + +static void +bfa_fcs_rpf_timeout(void *arg) +{ +	struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg; +	struct bfa_fcs_rport_s *rport = rpf->rport; + +	bfa_trc(rport->fcs, rport->pid); +	bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT); +} + +static void +bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_rpf_s *rpf 	= (struct bfa_fcs_rpf_s *)rpf_cbarg; +	struct bfa_fcs_rport_s *rport = rpf->rport; +	struct bfa_fcs_port_s *port = rport->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(rport->fcs, rport->pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe, +					bfa_fcs_rpf_send_rpsc2, rpf); +		return; +	} +	rpf->fcxp = fcxp; + +	len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, +			    bfa_fcs_port_get_fcid(port), &rport->pid, 1); + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +			  FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response, +			  rpf, FC_MAX_PDUSZ, FC_RA_TOV); +	rport->stats.rpsc_sent++; +	bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT); + +} + +static void +bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, +			    bfa_status_t req_status, u32 rsp_len, +			    u32 resid_len, struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg; +	struct bfa_fcs_rport_s *rport = rpf->rport; +	struct fc_ls_rjt_s    *ls_rjt; +	struct fc_rpsc2_acc_s  *rpsc2_acc; +	u16        num_ents; + +	bfa_trc(rport->fcs, req_status); + +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(rport->fcs, req_status); +		if (req_status == BFA_STATUS_ETIMER) +			rport->stats.rpsc_failed++; +		bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); +		return; +	} + +	rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp); +	if (rpsc2_acc->els_cmd == FC_ELS_ACC) { +		rport->stats.rpsc_accs++; +		num_ents = bfa_os_ntohs(rpsc2_acc->num_pids); +		bfa_trc(rport->fcs, num_ents); +		if (num_ents > 0) { +			bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid); +			bfa_trc(rport->fcs, +				bfa_os_ntohs(rpsc2_acc->port_info[0].pid)); +			bfa_trc(rport->fcs, +				bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); +			bfa_trc(rport->fcs, +				bfa_os_ntohs(rpsc2_acc->port_info[0].index)); +			bfa_trc(rport->fcs, +				rpsc2_acc->port_info[0].type); + +			if (rpsc2_acc->port_info[0].speed == 0) { +				bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); +				return; +			} + +			rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed( +				bfa_os_ntohs(rpsc2_acc->port_info[0].speed)); + +			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP); +		} +	} else { +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); +		bfa_trc(rport->fcs, ls_rjt->reason_code); +		bfa_trc(rport->fcs, ls_rjt->reason_code_expl); +		rport->stats.rpsc_rejects++; +		if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) { +			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL); +		} else { +			bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); +		} +	} +} diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c new file mode 100644 index 00000000000..bd4771ff62c --- /dev/null +++ b/drivers/scsi/bfa/scn.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include "fcs_lport.h" +#include "fcs_rport.h" +#include "fcs_ms.h" +#include "fcs_trcmod.h" +#include "fcs_fcxp.h" +#include "fcs.h" +#include "lport_priv.h" + +BFA_TRC_FILE(FCS, SCN); + +#define FC_QOS_RSCN_EVENT		0x0c +#define FC_FABRIC_NAME_RSCN_EVENT	0x0d + +/* + * forward declarations + */ +static void     bfa_fcs_port_scn_send_scr(void *scn_cbarg, +					  struct bfa_fcxp_s *fcxp_alloced); +static void     bfa_fcs_port_scn_scr_response(void *fcsarg, +					      struct bfa_fcxp_s *fcxp, +					      void *cbarg, +					      bfa_status_t req_status, +					      u32 rsp_len, +					      u32 resid_len, +					      struct fchs_s *rsp_fchs); +static void     bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port, +					     struct fchs_s *rx_fchs); +static void     bfa_fcs_port_scn_timeout(void *arg); + +/** + *  fcs_scm_sm FCS SCN state machine + */ + +/** + * VPort SCN State Machine events + */ +enum port_scn_event { +	SCNSM_EVENT_PORT_ONLINE = 1, +	SCNSM_EVENT_PORT_OFFLINE = 2, +	SCNSM_EVENT_RSP_OK = 3, +	SCNSM_EVENT_RSP_ERROR = 4, +	SCNSM_EVENT_TIMEOUT = 5, +	SCNSM_EVENT_SCR_SENT = 6, +}; + +static void     bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn, +					    enum port_scn_event event); +static void     bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn, +						enum port_scn_event event); +static void     bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn, +					enum port_scn_event event); +static void     bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn, +					      enum port_scn_event event); +static void     bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn, +					   enum port_scn_event event); + +/** + * 		Starting state - awaiting link up. + */ +static void +bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn, +			    enum port_scn_event event) +{ +	switch (event) { +	case SCNSM_EVENT_PORT_ONLINE: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr); +		bfa_fcs_port_scn_send_scr(scn, NULL); +		break; + +	case SCNSM_EVENT_PORT_OFFLINE: +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn, +				enum port_scn_event event) +{ +	switch (event) { +	case SCNSM_EVENT_SCR_SENT: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr); +		break; + +	case SCNSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); +		bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn, +			enum port_scn_event event) +{ +	struct bfa_fcs_port_s *port = scn->port; + +	switch (event) { +	case SCNSM_EVENT_RSP_OK: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online); +		break; + +	case SCNSM_EVENT_RSP_ERROR: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry); +		bfa_timer_start(port->fcs->bfa, &scn->timer, +				bfa_fcs_port_scn_timeout, scn, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case SCNSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); +		bfa_fcxp_discard(scn->fcxp); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn, +			      enum port_scn_event event) +{ +	switch (event) { +	case SCNSM_EVENT_TIMEOUT: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr); +		bfa_fcs_port_scn_send_scr(scn, NULL); +		break; + +	case SCNSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); +		bfa_timer_stop(&scn->timer); +		break; + +	default: +		bfa_assert(0); +	} +} + +static void +bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn, +			   enum port_scn_event event) +{ +	switch (event) { +	case SCNSM_EVENT_PORT_OFFLINE: +		bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  fcs_scn_private FCS SCN private functions + */ + +/** + * This routine will be called to send a SCR command. + */ +static void +bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced) +{ +	struct bfa_fcs_port_scn_s *scn = scn_cbarg; +	struct bfa_fcs_port_s *port = scn->port; +	struct fchs_s          fchs; +	int             len; +	struct bfa_fcxp_s *fcxp; + +	bfa_trc(port->fcs, port->pid); +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) { +		bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe, +				    bfa_fcs_port_scn_send_scr, scn); +		return; +	} +	scn->fcxp = fcxp; + +	/* +	 * Handle VU registrations for Base port only +	 */ +	if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) { +		len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), +				   bfa_lps_is_brcd_fabric(port->fabric->lps), +				   port->pid, 0); +	} else { +		len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), BFA_FALSE, +				   port->pid, 0); +	} + +	bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, +		      FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response, +		      (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV); + +	bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT); +} + +static void +bfa_fcs_port_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp, +			      void *cbarg, bfa_status_t req_status, +			      u32 rsp_len, u32 resid_len, +			      struct fchs_s *rsp_fchs) +{ +	struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg; +	struct bfa_fcs_port_s *port = scn->port; +	struct fc_els_cmd_s   *els_cmd; +	struct fc_ls_rjt_s    *ls_rjt; + +	bfa_trc(port->fcs, port->port_cfg.pwwn); + +	/* +	 * Sanity Checks +	 */ +	if (req_status != BFA_STATUS_OK) { +		bfa_trc(port->fcs, req_status); +		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); +		return; +	} + +	els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); + +	switch (els_cmd->els_code) { + +	case FC_ELS_ACC: +		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK); +		break; + +	case FC_ELS_LS_RJT: + +		ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); + +		bfa_trc(port->fcs, ls_rjt->reason_code); +		bfa_trc(port->fcs, ls_rjt->reason_code_expl); + +		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); +		break; + +	default: +		bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); +	} +} + +/* + * Send a LS Accept + */ +static void +bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port, +			struct fchs_s *rx_fchs) +{ +	struct fchs_s          fchs; +	struct bfa_fcxp_s *fcxp; +	struct bfa_rport_s *bfa_rport = NULL; +	int             len; + +	bfa_trc(port->fcs, rx_fchs->s_id); + +	fcxp = bfa_fcs_fcxp_alloc(port->fcs); +	if (!fcxp) +		return; + +	len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id, +			      bfa_fcs_port_get_fcid(port), rx_fchs->ox_id); + +	bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, +		      BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, +		      FC_MAX_PDUSZ, 0); +} + +/** + *     This routine will be called by bfa_timer on timer timeouts. + * + * 	param[in] 	vport 			- pointer to bfa_fcs_port_t. + * 	param[out]	vport_status 	- pointer to return vport status in + * + * 	return + * 		void + * +*  	Special Considerations: + * + * 	note + */ +static void +bfa_fcs_port_scn_timeout(void *arg) +{ +	struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)arg; + +	bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT); +} + + + +/** + *  fcs_scn_public FCS state change notification public interfaces + */ + +/* + * Functions called by port/fab + */ +void +bfa_fcs_port_scn_init(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + +	scn->port = port; +	bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline); +} + +void +bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + +	scn->port = port; +	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE); +} + +void +bfa_fcs_port_scn_online(struct bfa_fcs_port_s *port) +{ +	struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); + +	scn->port = port; +	bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE); +} + +static void +bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s *port, u32 rpid) +{ +	struct bfa_fcs_rport_s *rport; + +	bfa_trc(port->fcs, rpid); + +	/** +	 * If this is an unknown device, then it just came online. +	 * Otherwise let rport handle the RSCN event. +	 */ +	rport = bfa_fcs_port_get_rport_by_pid(port, rpid); +	if (rport == NULL) { +		/* +		 * If min cfg mode is enabled, we donot need to +		 * discover any new rports. +		 */ +		if (!__fcs_min_cfg(port->fcs)) +			rport = bfa_fcs_rport_create(port, rpid); +	} else { +		bfa_fcs_rport_scn(rport); +	} +} + +/** + * rscn format based PID comparison + */ +#define __fc_pid_match(__c0, __c1, __fmt)		\ +	(((__fmt) == FC_RSCN_FORMAT_FABRIC) ||		\ +	 (((__fmt) == FC_RSCN_FORMAT_DOMAIN) &&		\ +	  ((__c0)[0] == (__c1)[0])) ||			\ +	 (((__fmt) == FC_RSCN_FORMAT_AREA) &&		\ +	  ((__c0)[0] == (__c1)[0]) &&			\ +	  ((__c0)[1] == (__c1)[1]))) + +static void +bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s *port, +			enum fc_rscn_format format, u32 rscn_pid) +{ +	struct bfa_fcs_rport_s *rport; +	struct list_head *qe, *qe_next; +	u8        *c0, *c1; + +	bfa_trc(port->fcs, format); +	bfa_trc(port->fcs, rscn_pid); + +	c0 = (u8 *) &rscn_pid; + +	list_for_each_safe(qe, qe_next, &port->rport_q) { +		rport = (struct bfa_fcs_rport_s *)qe; +		c1 = (u8 *) &rport->pid; +		if (__fc_pid_match(c0, c1, format)) +			bfa_fcs_rport_scn(rport); +	} +} + +void +bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, struct fchs_s *fchs, +			      u32 len) +{ +	struct fc_rscn_pl_s   *rscn = (struct fc_rscn_pl_s *) (fchs + 1); +	int             num_entries; +	u32        rscn_pid; +	bfa_boolean_t   nsquery = BFA_FALSE; +	int             i = 0; + +	num_entries = +		(bfa_os_ntohs(rscn->payldlen) - +		 sizeof(u32)) / sizeof(rscn->event[0]); + +	bfa_trc(port->fcs, num_entries); + +	port->stats.num_rscn++; + +	bfa_fcs_port_scn_send_ls_acc(port, fchs); + +	for (i = 0; i < num_entries; i++) { +		rscn_pid = rscn->event[i].portid; + +		bfa_trc(port->fcs, rscn->event[i].format); +		bfa_trc(port->fcs, rscn_pid); + +		switch (rscn->event[i].format) { +		case FC_RSCN_FORMAT_PORTID: +			if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) { +				/* +				 * Ignore this event. f/w would have processed +				 * it +				 */ +				bfa_trc(port->fcs, rscn_pid); +			} else { +				port->stats.num_portid_rscn++; +				bfa_fcs_port_scn_portid_rscn(port, rscn_pid); +			} +			break; + +		case FC_RSCN_FORMAT_FABRIC: +			if (rscn->event[i].qualifier == +			    FC_FABRIC_NAME_RSCN_EVENT) { +				bfa_fcs_port_ms_fabric_rscn(port); +				break; +			} +			/* +			 * !!!!!!!!! Fall Through !!!!!!!!!!!!! +			 */ + +		case FC_RSCN_FORMAT_AREA: +		case FC_RSCN_FORMAT_DOMAIN: +			nsquery = BFA_TRUE; +			bfa_fcs_port_scn_multiport_rscn(port, +							rscn->event[i].format, +							rscn_pid); +			break; + +		default: +			bfa_assert(0); +			nsquery = BFA_TRUE; +		} +	} + +	/** +	 * If any of area, domain or fabric RSCN is received, do a fresh discovery +	 * to find new devices. +	 */ +	if (nsquery) +		bfa_fcs_port_ns_query(port); +} + + diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c new file mode 100644 index 00000000000..31d81fe2fc4 --- /dev/null +++ b/drivers/scsi/bfa/vfapi.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  vfapi.c Fabric module implementation. + */ + +#include "fcs_fabric.h" +#include "fcs_trcmod.h" + +BFA_TRC_FILE(FCS, VFAPI); + +/** + *  fcs_vf_api virtual fabrics API + */ + +/** + * 		Enable VF mode. + * + * @param[in]		fcs		fcs module instance + * @param[in]		vf_id		default vf_id of port, FC_VF_ID_NULL + * 					to use standard default vf_id of 1. + * + * @retval	BFA_STATUS_OK		vf mode is enabled + * @retval	BFA_STATUS_BUSY		Port is active. Port must be disabled + *					before VF mode can be enabled. + */ +bfa_status_t +bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id) +{ +	return BFA_STATUS_OK; +} + +/** + * 		Disable VF mode. + * + * @param[in]		fcs		fcs module instance + * + * @retval	BFA_STATUS_OK		vf mode is disabled + * @retval	BFA_STATUS_BUSY		VFs are present and being used. All + * 					VFs must be deleted before disabling + *					VF mode. + */ +bfa_status_t +bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs) +{ +	return BFA_STATUS_OK; +} + +/** + * 		Create a new VF instance. + * + *  A new VF is created using the given VF configuration. A VF is identified + *  by VF id. No duplicate VF creation is allowed with the same VF id. Once + *  a VF is created, VF is automatically started after link initialization + *  and EVFP exchange is completed. + * + * 	param[in] vf		- 	FCS vf data structure. Memory is + *					allocated by caller (driver) + * 	param[in] fcs 		- 	FCS module + * 	param[in] vf_cfg	- 	VF configuration + * 	param[in] vf_drv 	- 	Opaque handle back to the driver's + *					virtual vf structure + * + * 	retval BFA_STATUS_OK VF creation is successful + * 	retval BFA_STATUS_FAILED VF creation failed + * 	retval BFA_STATUS_EEXIST A VF exists with the given vf_id + */ +bfa_status_t +bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id, +		  struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv) +{ +	bfa_trc(fcs, vf_id); +	return BFA_STATUS_OK; +} + +/** + *  	Use this function to delete a BFA VF object. VF object should + * 		be stopped before this function call. + * + * 	param[in] vf - pointer to bfa_vf_t. + * + * 	retval BFA_STATUS_OK	On vf deletion success + * 	retval BFA_STATUS_BUSY VF is not in a stopped state + * 	retval BFA_STATUS_INPROGRESS VF deletion in in progress + */ +bfa_status_t +bfa_fcs_vf_delete(bfa_fcs_vf_t *vf) +{ +	bfa_trc(vf->fcs, vf->vf_id); +	return BFA_STATUS_OK; +} + +/** + *  	Start participation in VF. This triggers login to the virtual fabric. + * + * 	param[in] vf - pointer to bfa_vf_t. + * + * 	return None + */ +void +bfa_fcs_vf_start(bfa_fcs_vf_t *vf) +{ +	bfa_trc(vf->fcs, vf->vf_id); +} + +/** + *  	Logout with the virtual fabric. + * + * 	param[in] vf - pointer to bfa_vf_t. + * + * 	retval BFA_STATUS_OK 	On success. + * 	retval BFA_STATUS_INPROGRESS VF is being stopped. + */ +bfa_status_t +bfa_fcs_vf_stop(bfa_fcs_vf_t *vf) +{ +	bfa_trc(vf->fcs, vf->vf_id); +	return BFA_STATUS_OK; +} + +/** + *  	Returns attributes of the given VF. + * + * 	param[in] 	vf			pointer to bfa_vf_t. + * 	param[out] vf_attr 	vf attributes returned + * + * 	return None + */ +void +bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr) +{ +	bfa_trc(vf->fcs, vf->vf_id); +} + +/** + * 		Return statistics associated with the given vf. + * + * 	param[in] 	vf			pointer to bfa_vf_t. + * 	param[out] vf_stats 	vf statistics returned + * + *  @return None + */ +void +bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats) +{ +	bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s)); +	return; +} + +void +/** + * 		clear statistics associated with the given vf. + * + * 	param[in] 	vf			pointer to bfa_vf_t. + * + *  @return None + */ +bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf) +{ +	bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s)); +	return; +} + +/** + *  	Returns FCS vf structure for a given vf_id. + * + * 	param[in] 	vf_id		- VF_ID + * + * 	return + * 		If lookup succeeds, retuns fcs vf object, otherwise returns NULL + */ +bfa_fcs_vf_t   * +bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) +{ +	bfa_trc(fcs, vf_id); +	if (vf_id == FC_VF_ID_NULL) +		return (&fcs->fabric); + +	/** +	 * @todo vf support +	 */ + +	return NULL; +} + +/** + *  	Returns driver VF structure for a given FCS vf. + * + * 	param[in] 	vf		- pointer to bfa_vf_t + * + * 	return Driver VF structure + */ +struct bfad_vf_s      * +bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf) +{ +	bfa_assert(vf); +	bfa_trc(vf->fcs, vf->vf_id); +	return vf->vf_drv; +} + +/** + *  	Return the list of VFs configured. + * + * 	param[in]	fcs	fcs module instance + * 	param[out] 	vf_ids	returned list of vf_ids + * 	param[in,out] 	nvfs	in:size of vf_ids array, + * 				out:total elements present, + * 				actual elements returned is limited by the size + * + * 	return Driver VF structure + */ +void +bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) +{ +	bfa_trc(fcs, *nvfs); +} + +/** + *  	Return the list of all VFs visible from fabric. + * + * 	param[in]	fcs	fcs module instance + * 	param[out] 	vf_ids	returned list of vf_ids + * 	param[in,out] 	nvfs	in:size of vf_ids array, + *				out:total elements present, + * 				actual elements returned is limited by the size + * + * 	return Driver VF structure + */ +void +bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs) +{ +	bfa_trc(fcs, *nvfs); +} + +/** + * 		Return the list of local logical ports present in the given VF. + * + * 	param[in]	vf	vf for which logical ports are returned + * 	param[out] 	lpwwn	returned logical port wwn list + * 	param[in,out] 	nlports	in:size of lpwwn list; + *				out:total elements present, + * 				actual elements returned is limited by the size + * + */ +void +bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) +{ +	struct list_head        *qe; +	struct bfa_fcs_vport_s *vport; +	int             i; +	struct bfa_fcs_s      *fcs; + +	if (vf == NULL || lpwwn == NULL || *nlports == 0) +		return; + +	fcs = vf->fcs; + +	bfa_trc(fcs, vf->vf_id); +	bfa_trc(fcs, (u32) *nlports); + +	i = 0; +	lpwwn[i++] = vf->bport.port_cfg.pwwn; + +	list_for_each(qe, &vf->vport_q) { +		if (i >= *nlports) +			break; + +		vport = (struct bfa_fcs_vport_s *) qe; +		lpwwn[i++] = vport->lport.port_cfg.pwwn; +	} + +	bfa_trc(fcs, i); +	*nlports = i; +	return; +} + + diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c new file mode 100644 index 00000000000..c10af06c571 --- /dev/null +++ b/drivers/scsi/bfa/vport.c @@ -0,0 +1,891 @@ +/* + * Copyright (c) 2005-2009 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + */ + +/** + *  bfa_fcs_vport.c FCS virtual port state machine + */ + +#include <bfa.h> +#include <bfa_svc.h> +#include <fcbuild.h> +#include "fcs_fabric.h" +#include "fcs_lport.h" +#include "fcs_vport.h" +#include "fcs_trcmod.h" +#include "fcs.h" +#include <aen/bfa_aen_lport.h> + +BFA_TRC_FILE(FCS, VPORT); + +#define __vport_fcs(__vp)       (__vp)->lport.fcs +#define __vport_pwwn(__vp)      (__vp)->lport.port_cfg.pwwn +#define __vport_nwwn(__vp)      (__vp)->lport.port_cfg.nwwn +#define __vport_bfa(__vp)       (__vp)->lport.fcs->bfa +#define __vport_fcid(__vp)      (__vp)->lport.pid +#define __vport_fabric(__vp)    (__vp)->lport.fabric +#define __vport_vfid(__vp)      (__vp)->lport.fabric->vf_id + +#define BFA_FCS_VPORT_MAX_RETRIES  5 +/* + * Forward declarations + */ +static void     bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport); +static void     bfa_fcs_vport_timeout(void *vport_arg); +static void     bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport); +static void     bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport); + +/** + *  fcs_vport_sm FCS virtual port state machine + */ + +/** + * VPort State Machine events + */ +enum bfa_fcs_vport_event { +	BFA_FCS_VPORT_SM_CREATE = 1,	/*  vport create event */ +	BFA_FCS_VPORT_SM_DELETE = 2,	/*  vport delete event */ +	BFA_FCS_VPORT_SM_START = 3,	/*  vport start request */ +	BFA_FCS_VPORT_SM_STOP = 4,	/*  stop: unsupported */ +	BFA_FCS_VPORT_SM_ONLINE = 5,	/*  fabric online */ +	BFA_FCS_VPORT_SM_OFFLINE = 6,	/*  fabric offline event */ +	BFA_FCS_VPORT_SM_FRMSENT = 7,	/*  fdisc/logo sent events */ +	BFA_FCS_VPORT_SM_RSP_OK = 8,	/*  good response */ +	BFA_FCS_VPORT_SM_RSP_ERROR = 9,	/*  error/bad response */ +	BFA_FCS_VPORT_SM_TIMEOUT = 10,	/*  delay timer event */ +	BFA_FCS_VPORT_SM_DELCOMP = 11,	/*  lport delete completion */ +	BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12,	/*  Dup wnn error */ +	BFA_FCS_VPORT_SM_RSP_FAILED = 13,	/*  non-retryable failure */ +}; + +static void     bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, +					enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, +					 enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, +					 enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, +				       enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, +					     enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, +					enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, +					  enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, +					 enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, +				      enum bfa_fcs_vport_event event); +static void     bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, +				       enum bfa_fcs_vport_event event); + +static struct bfa_sm_table_s vport_sm_table[] = { +	{BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, +	{BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED}, +	{BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, +	{BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, +	{BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, +	{BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, +	{BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, +	{BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, +	{BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO}, +	{BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR} +}; + +/** + * Beginning state. + */ +static void +bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, +			enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_CREATE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); +		bfa_fcs_fabric_addvport(__vport_fabric(vport), vport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Created state - a start event is required to start up the state machine. + */ +static void +bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, +			 enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_START: +		if (bfa_fcs_fabric_is_online(__vport_fabric(vport)) +		    && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) { +			bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); +			bfa_fcs_vport_do_fdisc(vport); +		} else { +			/** +			 * Fabric is offline or not NPIV capable, stay in +			 * offline state. +			 */ +			vport->vport_stats.fab_no_npiv++; +			bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); +		} +		break; + +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); +		bfa_fcs_port_delete(&vport->lport); +		break; + +	case BFA_FCS_VPORT_SM_ONLINE: +	case BFA_FCS_VPORT_SM_OFFLINE: +		/** +		 * Ignore ONLINE/OFFLINE events from fabric till vport is started. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Offline state - awaiting ONLINE event from fabric SM. + */ +static void +bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, +			 enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); +		bfa_fcs_port_delete(&vport->lport); +		break; + +	case BFA_FCS_VPORT_SM_ONLINE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); +		vport->fdisc_retries = 0; +		bfa_fcs_vport_do_fdisc(vport); +		break; + +	case BFA_FCS_VPORT_SM_OFFLINE: +		/* +		 * This can happen if the vport couldn't be initialzied due +		 * the fact that the npiv was not enabled on the switch. In +		 * that case we will put the vport in offline state. However, +		 * the link can go down and cause the this event to be sent when +		 * we are already offline. Ignore it. +		 */ +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * FDISC is sent and awaiting reply from fabric. + */ +static void +bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, +		       enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); +		bfa_lps_discard(vport->lps); +		bfa_fcs_vport_do_logo(vport); +		break; + +	case BFA_FCS_VPORT_SM_OFFLINE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); +		bfa_lps_discard(vport->lps); +		break; + +	case BFA_FCS_VPORT_SM_RSP_OK: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_online); +		bfa_fcs_port_online(&vport->lport); +		break; + +	case BFA_FCS_VPORT_SM_RSP_ERROR: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry); +		bfa_timer_start(__vport_bfa(vport), &vport->timer, +				bfa_fcs_vport_timeout, vport, +				BFA_FCS_RETRY_TIMEOUT); +		break; + +	case BFA_FCS_VPORT_SM_RSP_FAILED: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); +		break; + +	case BFA_FCS_VPORT_SM_RSP_DUP_WWN: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_error); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * FDISC attempt failed - a timer is active to retry FDISC. + */ +static void +bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, +			     enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); +		bfa_timer_stop(&vport->timer); +		bfa_fcs_port_delete(&vport->lport); +		break; + +	case BFA_FCS_VPORT_SM_OFFLINE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); +		bfa_timer_stop(&vport->timer); +		break; + +	case BFA_FCS_VPORT_SM_TIMEOUT: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); +		vport->vport_stats.fdisc_retries++; +		vport->fdisc_retries++; +		bfa_fcs_vport_do_fdisc(vport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Vport is online (FDISC is complete). + */ +static void +bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, +			enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); +		bfa_fcs_port_delete(&vport->lport); +		break; + +	case BFA_FCS_VPORT_SM_OFFLINE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); +		bfa_lps_discard(vport->lps); +		bfa_fcs_port_offline(&vport->lport); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Vport is being deleted - awaiting lport delete completion to send + * LOGO to fabric. + */ +static void +bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, +			  enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		break; + +	case BFA_FCS_VPORT_SM_DELCOMP: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); +		bfa_fcs_vport_do_logo(vport); +		break; + +	case BFA_FCS_VPORT_SM_OFFLINE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * Error State. + * This state will be set when the Vport Creation fails due to errors like + * Dup WWN. In this state only operation allowed is a Vport Delete. + */ +static void +bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, +		       enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELETE: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); +		bfa_fcs_vport_free(vport); +		break; + +	default: +		bfa_trc(__vport_fcs(vport), event); +	} +} + +/** + * Lport cleanup is in progress since vport is being deleted. Fabric is + * offline, so no LOGO is needed to complete vport deletion. + */ +static void +bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, +			 enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_DELCOMP: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); +		bfa_fcs_vport_free(vport); +		break; + +	case BFA_FCS_VPORT_SM_DELETE: +		break; + +	default: +		bfa_assert(0); +	} +} + +/** + * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup + * is done. + */ +static void +bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, +		      enum bfa_fcs_vport_event event) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), event); + +	switch (event) { +	case BFA_FCS_VPORT_SM_OFFLINE: +		bfa_lps_discard(vport->lps); +		/* +		 * !!! fall through !!! +		 */ + +	case BFA_FCS_VPORT_SM_RSP_OK: +	case BFA_FCS_VPORT_SM_RSP_ERROR: +		bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); +		bfa_fcs_vport_free(vport); +		break; + +	case BFA_FCS_VPORT_SM_DELETE: +		break; + +	default: +		bfa_assert(0); +	} +} + + + +/** + *  fcs_vport_private FCS virtual port private functions + */ + +/** + * Send AEN notification + */ +static void +bfa_fcs_vport_aen_post(bfa_fcs_lport_t *port, enum bfa_lport_aen_event event) +{ +	union bfa_aen_data_u aen_data; +	struct bfa_log_mod_s *logmod = port->fcs->logm; +	enum bfa_port_role role = port->port_cfg.roles; +	wwn_t           lpwwn = bfa_fcs_port_get_pwwn(port); +	char            lpwwn_ptr[BFA_STRING_32]; +	char           *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] = +		{ "Initiator", "Target", "IPFC" }; + +	wwn2str(lpwwn_ptr, lpwwn); + +	bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX); + +	switch (event) { +	case BFA_LPORT_AEN_NPIV_DUP_WWN: +		bfa_log(logmod, BFA_AEN_LPORT_NPIV_DUP_WWN, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_NPIV_FABRIC_MAX: +		bfa_log(logmod, BFA_AEN_LPORT_NPIV_FABRIC_MAX, lpwwn_ptr, +			role_str[role / 2]); +		break; +	case BFA_LPORT_AEN_NPIV_UNKNOWN: +		bfa_log(logmod, BFA_AEN_LPORT_NPIV_UNKNOWN, lpwwn_ptr, +			role_str[role / 2]); +		break; +	default: +		break; +	} + +	aen_data.lport.vf_id = port->fabric->vf_id; +	aen_data.lport.roles = role; +	aen_data.lport.ppwwn = +		bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs)); +	aen_data.lport.lpwwn = lpwwn; +} + +/** + * This routine will be called to send a FDISC command. + */ +static void +bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport) +{ +	bfa_lps_fdisc(vport->lps, vport, +		      bfa_pport_get_maxfrsize(__vport_bfa(vport)), +		      __vport_pwwn(vport), __vport_nwwn(vport)); +	vport->vport_stats.fdisc_sent++; +} + +static void +bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport) +{ +	u8         lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps); +	u8         lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps); + +	bfa_trc(__vport_fcs(vport), lsrjt_rsn); +	bfa_trc(__vport_fcs(vport), lsrjt_expl); + +	/* +	 * For certain reason codes, we don't want to retry. +	 */ +	switch (bfa_lps_get_lsrjt_expl(vport->lps)) { +	case FC_LS_RJT_EXP_INV_PORT_NAME:	/* by brocade */ +	case FC_LS_RJT_EXP_INVALID_NPORT_ID:	/* by Cisco */ +		if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) +			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); +		else { +			bfa_fcs_vport_aen_post(&vport->lport, +					       BFA_LPORT_AEN_NPIV_DUP_WWN); +			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN); +		} +		break; + +	case FC_LS_RJT_EXP_INSUFF_RES: +		/* +		 * This means max logins per port/switch setting on the +		 * switch was exceeded. +		 */ +		if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) +			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); +		else { +			bfa_fcs_vport_aen_post(&vport->lport, +					       BFA_LPORT_AEN_NPIV_FABRIC_MAX); +			bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED); +		} +		break; + +	default: +		if (vport->fdisc_retries == 0)	/* Print only once */ +			bfa_fcs_vport_aen_post(&vport->lport, +					       BFA_LPORT_AEN_NPIV_UNKNOWN); +		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); +	} +} + +/** + * 	Called to send a logout to the fabric. Used when a V-Port is + * 	deleted/stopped. + */ +static void +bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport) +{ +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); + +	vport->vport_stats.logo_sent++; +	bfa_lps_fdisclogo(vport->lps); +} + +/** + *     This routine will be called by bfa_timer on timer timeouts. + * + * 	param[in] 	vport 		- pointer to bfa_fcs_vport_t. + * 	param[out]	vport_status 	- pointer to return vport status in + * + * 	return + * 		void + * +* 	Special Considerations: + * + * 	note + */ +static void +bfa_fcs_vport_timeout(void *vport_arg) +{ +	struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *)vport_arg; + +	vport->vport_stats.fdisc_timeouts++; +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT); +} + +static void +bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport) +{ +	bfa_fcs_fabric_delvport(__vport_fabric(vport), vport); +	bfa_fcb_vport_delete(vport->vport_drv); +	bfa_lps_delete(vport->lps); +} + + + +/** + *  fcs_vport_public FCS virtual port public interfaces + */ + +/** + * Online notification from fabric SM. + */ +void +bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) +{ +	vport->vport_stats.fab_online++; +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); +} + +/** + * Offline notification from fabric SM. + */ +void +bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport) +{ +	vport->vport_stats.fab_offline++; +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); +} + +/** + * Cleanup notification from fabric SM on link timer expiry. + */ +void +bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) +{ +	vport->vport_stats.fab_cleanup++; +} + +/** + * Delete completion callback from associated lport + */ +void +bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport) +{ +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP); +} + +/** + *   Module initialization + */ +void +bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs) +{ +} + +/** + *   Module cleanup + */ +void +bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs) +{ +	bfa_fcs_modexit_comp(fcs); +} + +u32 +bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs) +{ +	struct bfa_ioc_attr_s ioc_attr; + +	bfa_get_attr(fcs->bfa, &ioc_attr); + +	if (ioc_attr.pci_attr.device_id == BFA_PCI_DEVICE_ID_CT) +		return (BFA_FCS_MAX_VPORTS_SUPP_CT); +	else +		return (BFA_FCS_MAX_VPORTS_SUPP_CB); +} + + + +/** + *  fcs_vport_api Virtual port API + */ + +/** + *  	Use this function to instantiate a new FCS vport object. This + * 	function will not trigger any HW initialization process (which will be + * 	done in vport_start() call) + * + * 	param[in] vport	- 	pointer to bfa_fcs_vport_t. This space + * 					needs to be allocated by the driver. + * 	param[in] fcs 		- 	FCS instance + * 	param[in] vport_cfg	- 	vport configuration + * 	param[in] vf_id    	- 	VF_ID if vport is created within a VF. + *                          		FC_VF_ID_NULL to specify base fabric. + * 	param[in] vport_drv 	- 	Opaque handle back to the driver's vport + * 					structure + * + * 	retval BFA_STATUS_OK - on success. + * 	retval BFA_STATUS_FAILED - on failure. + */ +bfa_status_t +bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, +		     u16 vf_id, struct bfa_port_cfg_s *vport_cfg, +		     struct bfad_vport_s *vport_drv) +{ +	if (vport_cfg->pwwn == 0) +		return (BFA_STATUS_INVALID_WWN); + +	if (bfa_fcs_port_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn) +		return BFA_STATUS_VPORT_WWN_BP; + +	if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL) +		return BFA_STATUS_VPORT_EXISTS; + +	if (bfa_fcs_fabric_vport_count(&fcs->fabric) == +	    bfa_fcs_vport_get_max(fcs)) +		return BFA_STATUS_VPORT_MAX; + +	vport->lps = bfa_lps_alloc(fcs->bfa); +	if (!vport->lps) +		return BFA_STATUS_VPORT_MAX; + +	vport->vport_drv = vport_drv; +	bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); + +	bfa_fcs_lport_init(&vport->lport, fcs, vf_id, vport_cfg, vport); + +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE); + +	return BFA_STATUS_OK; +} + +/** + *  	Use this function initialize the vport. + * + *  @param[in] vport - pointer to bfa_fcs_vport_t. + * + *  @returns None + */ +bfa_status_t +bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport) +{ +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START); + +	return BFA_STATUS_OK; +} + +/** + *  	Use this function quiese the vport object. This function will return + * 	immediately, when the vport is actually stopped, the + * 	bfa_drv_vport_stop_cb() will be called. + * + * 	param[in] vport - pointer to bfa_fcs_vport_t. + * + * 	return None + */ +bfa_status_t +bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) +{ +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP); + +	return BFA_STATUS_OK; +} + +/** + *  	Use this function to delete a vport object. Fabric object should + * 		be stopped before this function call. + * + * 	param[in] vport - pointer to bfa_fcs_vport_t. + * + * 	return     None + */ +bfa_status_t +bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport) +{ +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); + +	return BFA_STATUS_OK; +} + +/** + *  	Use this function to get vport's current status info. + * + * 	param[in] 	vport 		pointer to bfa_fcs_vport_t. + * 	param[out]	attr 		pointer to return vport attributes + * + * 	return None + */ +void +bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, +		       struct bfa_vport_attr_s *attr) +{ +	if (vport == NULL || attr == NULL) +		return; + +	bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s)); + +	bfa_fcs_port_get_attr(&vport->lport, &attr->port_attr); +	attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm); +} + +/** + *  	Use this function to get vport's statistics. + * + * 	param[in] 	vport 		pointer to bfa_fcs_vport_t. + * 	param[out]	stats		pointer to return vport statistics in + * + * 	return None + */ +void +bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport, +			struct bfa_vport_stats_s *stats) +{ +	*stats = vport->vport_stats; +} + +/** + *  	Use this function to clear vport's statistics. + * + * 	param[in] 	vport 		pointer to bfa_fcs_vport_t. + * + * 	return None + */ +void +bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport) +{ +	bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s)); +} + +/** + *      Lookup a virtual port. Excludes base port from lookup. + */ +struct bfa_fcs_vport_s * +bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn) +{ +	struct bfa_fcs_vport_s *vport; +	struct bfa_fcs_fabric_s *fabric; + +	bfa_trc(fcs, vf_id); +	bfa_trc(fcs, vpwwn); + +	fabric = bfa_fcs_vf_lookup(fcs, vf_id); +	if (!fabric) { +		bfa_trc(fcs, vf_id); +		return NULL; +	} + +	vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn); +	return vport; +} + +/** + * FDISC Response + */ +void +bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) +{ +	struct bfa_fcs_vport_s *vport = uarg; + +	bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); +	bfa_trc(__vport_fcs(vport), status); + +	switch (status) { +	case BFA_STATUS_OK: +		/* +		 * Initialiaze the V-Port fields +		 */ +		__vport_fcid(vport) = bfa_lps_get_pid(vport->lps); +		vport->vport_stats.fdisc_accepts++; +		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); +		break; + +	case BFA_STATUS_INVALID_MAC: +		/* +		 * Only for CNA +		 */ +		vport->vport_stats.fdisc_acc_bad++; +		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); + +		break; + +	case BFA_STATUS_EPROTOCOL: +		switch (bfa_lps_get_extstatus(vport->lps)) { +		case BFA_EPROTO_BAD_ACCEPT: +			vport->vport_stats.fdisc_acc_bad++; +			break; + +		case BFA_EPROTO_UNKNOWN_RSP: +			vport->vport_stats.fdisc_unknown_rsp++; +			break; + +		default: +			break; +		} + +		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); +		break; + +	case BFA_STATUS_FABRIC_RJT: +		vport->vport_stats.fdisc_rejects++; +		bfa_fcs_vport_fdisc_rejected(vport); +		break; + +	default: +		vport->vport_stats.fdisc_rsp_err++; +		bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); +	} +} + +/** + * LOGO response + */ +void +bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg) +{ +	struct bfa_fcs_vport_s *vport = uarg; +	bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); +} + + diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index d7576f28c6e..5edde1a8c04 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -100,6 +100,8 @@  #define CTX_OFFSET 			0x10000  #define MAX_CID_CNT			0x4000 +#define BNX2I_570X_PAGE_SIZE_DEFAULT	4096 +  /* 5709 context registers */  #define BNX2_MQ_CONFIG2			0x00003d00  #define BNX2_MQ_CONFIG2_CONT_SZ		(0x7L<<4) diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 41e1b0e7e2e..5c8d7630c13 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -2386,7 +2386,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)  		ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;  		if (ctx_sz)  			reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE -				  + PAGE_SIZE * +				  + BNX2I_570X_PAGE_SIZE_DEFAULT *  				  (((cid_num - first_l4l5) / ctx_sz) + 256);  		else  			reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num); diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 9a7ba71f1af..cafb888c237 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1243,7 +1243,7 @@ bnx2i_session_create(struct iscsi_endpoint *ep,  		cmds_max = BNX2I_SQ_WQES_MIN;  	cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost, -					  cmds_max, sizeof(struct bnx2i_cmd), +					  cmds_max, 0, sizeof(struct bnx2i_cmd),  					  initial_cmdsn, ISCSI_MAX_TARGET);  	if (!cls_session)  		return NULL; diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c index c399f485aa7..2631bddd255 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c +++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c @@ -422,7 +422,7 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,  	BUG_ON(hba != iscsi_host_priv(shost));  	cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost, -					  cmds_max, +					  cmds_max, 0,  					  sizeof(struct iscsi_tcp_task) +  					  sizeof(struct cxgb3i_task_data),  					  initial_cmdsn, ISCSI_MAX_TARGET); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 11c89311427..268189d31d9 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -500,8 +500,6 @@ static int mode_select_handle_sense(struct scsi_device *sdev,  	if (!ret)  		goto done; -	err = SCSI_DH_OK; -  	switch (sense_hdr.sense_key) {  	case NO_SENSE:  	case ABORTED_COMMAND: diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index c596ab5f05c..a0e7e711ff9 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1,6 +1,6 @@  /*   * HighPoint RR3xxx/4xxx controller driver for Linux - * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");  static char driver_name[] = "hptiop";  static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver"; -static const char driver_ver[] = "v1.3 (071203)"; +static const char driver_ver[] = "v1.6 (090910)";  static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);  static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, @@ -115,9 +115,13 @@ static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)  static int iop_intr_itl(struct hptiop_hba *hba)  {  	struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop; +	void __iomem *plx = hba->u.itl.plx;  	u32 status;  	int ret = 0; +	if (plx && readl(plx + 0x11C5C) & 0xf) +		writel(1, plx + 0x11C60); +  	status = readl(&iop->outbound_intstatus);  	if (status & IOPMU_OUTBOUND_INT_MSG0) { @@ -460,15 +464,25 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)  static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)  { +	struct pci_dev *pcidev = hba->pcidev;  	hba->u.itl.iop = hptiop_map_pci_bar(hba, 0); -	if (hba->u.itl.iop) -		return 0; -	else +	if (hba->u.itl.iop == NULL)  		return -1; +	if ((pcidev->device & 0xff00) == 0x4400) { +		hba->u.itl.plx = hba->u.itl.iop; +		hba->u.itl.iop = hptiop_map_pci_bar(hba, 2); +		if (hba->u.itl.iop == NULL) { +			iounmap(hba->u.itl.plx); +			return -1; +		} +	} +	return 0;  }  static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)  { +	if (hba->u.itl.plx) +		iounmap(hba->u.itl.plx);  	iounmap(hba->u.itl.iop);  } @@ -1239,22 +1253,23 @@ static struct hptiop_adapter_ops hptiop_mv_ops = {  static struct pci_device_id hptiop_id_table[] = {  	{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, -	{ PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, +	{ PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops },  	{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },  	{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },  	{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops }, diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h index a0289f21975..0b871c0ae56 100644 --- a/drivers/scsi/hptiop.h +++ b/drivers/scsi/hptiop.h @@ -1,6 +1,6 @@  /*   * HighPoint RR3xxx/4xxx controller driver for Linux - * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. + * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -228,6 +228,7 @@ struct hptiop_hba {  	union {  		struct {  			struct hpt_iopmu_itl __iomem *iop; +			void __iomem *plx;  		} itl;  		struct {  			struct hpt_iopmv_regs *regs; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 2b1b834a098..edc49ca49ce 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -811,7 +811,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,  		goto free_host;  	cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost, -					  cmds_max, +					  cmds_max, 0,  					  sizeof(struct iscsi_tcp_task) +  					  sizeof(struct iscsi_sw_tcp_hdrbuf),  					  initial_cmdsn, 0); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8dc73c489a1..f1a4246f890 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -2436,7 +2436,7 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)   */  struct iscsi_cls_session *  iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, -		    uint16_t cmds_max, int cmd_task_size, +		    uint16_t cmds_max, int dd_size, int cmd_task_size,  		    uint32_t initial_cmdsn, unsigned int id)  {  	struct iscsi_host *ihost = shost_priv(shost); @@ -2486,7 +2486,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,  	scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;  	cls_session = iscsi_alloc_session(shost, iscsit, -					  sizeof(struct iscsi_session)); +					  sizeof(struct iscsi_session) + +					  dd_size);  	if (!cls_session)  		goto dec_session_count;  	session = cls_session->dd_data; @@ -2503,6 +2504,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,  	session->max_cmdsn = initial_cmdsn + 1;  	session->max_r2t = 1;  	session->tt = iscsit; +	session->dd_data = cls_session->dd_data + sizeof(*session);  	mutex_init(&session->eh_mutex);  	spin_lock_init(&session->lock); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 61d08970380..c88f59f0ce3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -56,8 +56,6 @@ static char *dif_op_str[] = {  	"SCSI_PROT_WRITE_INSERT",  	"SCSI_PROT_READ_PASS",  	"SCSI_PROT_WRITE_PASS", -	"SCSI_PROT_READ_CONVERT", -	"SCSI_PROT_WRITE_CONVERT"  };  static void  lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); @@ -1131,13 +1129,11 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)  			ret_prof = LPFC_PROF_A1;  			break; -		case SCSI_PROT_READ_CONVERT: -		case SCSI_PROT_WRITE_CONVERT: +		case SCSI_PROT_READ_PASS: +		case SCSI_PROT_WRITE_PASS:  			ret_prof = LPFC_PROF_AST1;  			break; -		case SCSI_PROT_READ_PASS: -		case SCSI_PROT_WRITE_PASS:  		case SCSI_PROT_NORMAL:  		default:  			printk(KERN_ERR "Bad op/guard:%d/%d combination\n", @@ -1157,8 +1153,6 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)  			ret_prof = LPFC_PROF_C1;  			break; -		case SCSI_PROT_READ_CONVERT: -		case SCSI_PROT_WRITE_CONVERT:  		case SCSI_PROT_READ_INSERT:  		case SCSI_PROT_WRITE_STRIP:  		case SCSI_PROT_NORMAL: @@ -1209,8 +1203,7 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,  	static int cnt;  	if (protcnt && (op == SCSI_PROT_WRITE_STRIP || -				op == SCSI_PROT_WRITE_PASS || -				op == SCSI_PROT_WRITE_CONVERT)) { +				op == SCSI_PROT_WRITE_PASS)) {  		cnt++;  		spt = page_address(sg_page(scsi_prot_sglist(sc))) + @@ -1501,8 +1494,6 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)  	case SCSI_PROT_WRITE_STRIP:  	case SCSI_PROT_READ_PASS:  	case SCSI_PROT_WRITE_PASS: -	case SCSI_PROT_WRITE_CONVERT: -	case SCSI_PROT_READ_CONVERT:  		ret = LPFC_PG_TYPE_DIF_BUF;  		break;  	default: diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig index 4a86855c23b..70c4c2467dd 100644 --- a/drivers/scsi/mpt2sas/Kconfig +++ b/drivers/scsi/mpt2sas/Kconfig @@ -2,7 +2,7 @@  # Kernel configuration file for the MPT2SAS  #  # This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2008  LSI Corporation +# Copyright (C) 2007-2009  LSI Corporation  #  (mailto:DL-MPTFusionLinux@lsi.com)  # This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index 7bb2ece8b2e..f9f6c083927 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@   *                  scatter/gather formats.   *  Creation Date:  June 21, 2006   * - *  mpi2.h Version:  02.00.11 + *  mpi2.h Version:  02.00.12   *   *  Version History   *  --------------- @@ -45,6 +45,13 @@   *  10-02-08  02.00.10  Bumped MPI2_HEADER_VERSION_UNIT.   *                      Moved LUN field defines from mpi2_init.h.   *  01-19-09  02.00.11  Bumped MPI2_HEADER_VERSION_UNIT. + *  05-06-09  02.00.12  Bumped MPI2_HEADER_VERSION_UNIT. + *                      In all request and reply descriptors, replaced VF_ID + *                      field with MSIxIndex field. + *                      Removed DevHandle field from + *                      MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + *                      bytes reserved. + *                      Added RAID Accelerator functionality.   *  --------------------------------------------------------------------------   */ @@ -70,7 +77,7 @@  #define MPI2_VERSION_02_00                  (0x0200)  /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT            (0x0B) +#define MPI2_HEADER_VERSION_UNIT            (0x0C)  #define MPI2_HEADER_VERSION_DEV             (0x00)  #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)  #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8) @@ -257,7 +264,7 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS  typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR  {      U8              RequestFlags;               /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U16             LMID;                       /* 0x04 */      U16             DescriptorTypeDependent;    /* 0x06 */ @@ -271,6 +278,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR  #define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET             (0x02)  #define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY           (0x06)  #define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE            (0x08) +#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR        (0x0A)  #define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) @@ -279,7 +287,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR  typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR  {      U8              RequestFlags;               /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U16             LMID;                       /* 0x04 */      U16             Reserved1;                  /* 0x06 */ @@ -293,7 +301,7 @@ typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR  typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR  {      U8              RequestFlags;               /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U16             LMID;                       /* 0x04 */      U16             DevHandle;                  /* 0x06 */ @@ -306,7 +314,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR  typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR  {      U8              RequestFlags;               /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U16             LMID;                       /* 0x04 */      U16             IoIndex;                    /* 0x06 */ @@ -315,14 +323,29 @@ typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR    Mpi2SCSITargetRequestDescriptor_t,    MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; + +/* RAID Accelerator Request Descriptor */ +typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { +    U8              RequestFlags;               /* 0x00 */ +    U8              MSIxIndex;                  /* 0x01 */ +    U16             SMID;                       /* 0x02 */ +    U16             LMID;                       /* 0x04 */ +    U16             Reserved;                   /* 0x06 */ +} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, +  MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, +  Mpi2RAIDAcceleratorRequestDescriptor_t, +  MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; + +  /* union of Request Descriptors */  typedef union _MPI2_REQUEST_DESCRIPTOR_UNION  { -    MPI2_DEFAULT_REQUEST_DESCRIPTOR         Default; -    MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR   HighPriority; -    MPI2_SCSI_IO_REQUEST_DESCRIPTOR         SCSIIO; -    MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR     SCSITarget; -    U64                                     Words; +    MPI2_DEFAULT_REQUEST_DESCRIPTOR             Default; +    MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR       HighPriority; +    MPI2_SCSI_IO_REQUEST_DESCRIPTOR             SCSIIO; +    MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR         SCSITarget; +    MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR          RAIDAccelerator; +    U64                                         Words;  } MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,    Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; @@ -333,19 +356,20 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION  typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR  {      U8              ReplyFlags;                 /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             DescriptorTypeDependent1;   /* 0x02 */      U32             DescriptorTypeDependent2;   /* 0x04 */  } MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,    Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;  /* defines for the ReplyFlags field */ -#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK               (0x0F) -#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS         (0x00) -#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY           (0x01) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS    (0x02) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER   (0x03) -#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED                  (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK                   (0x0F) +#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS             (0x00) +#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY               (0x01) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS        (0x02) +#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER       (0x03) +#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS    (0x05) +#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED                      (0x0F)  /* values for marking a reply descriptor as unused */  #define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK             (0xFFFFFFFF) @@ -355,7 +379,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR  typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR  {      U8              ReplyFlags;                 /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U32             ReplyFrameAddress;          /* 0x04 */  } MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, @@ -368,10 +392,10 @@ typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR  typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR  {      U8              ReplyFlags;                 /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U16             TaskTag;                    /* 0x04 */ -    U16             DevHandle;                  /* 0x06 */ +    U16             Reserved1;                  /* 0x06 */  } MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,    MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,    Mpi2SCSIIOSuccessReplyDescriptor_t, @@ -382,7 +406,7 @@ typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR  typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR  {      U8              ReplyFlags;                 /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U16             SMID;                       /* 0x02 */      U8              SequenceNumber;             /* 0x04 */      U8              Reserved1;                  /* 0x05 */ @@ -397,7 +421,7 @@ typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR  typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR  {      U8              ReplyFlags;                 /* 0x00 */ -    U8              VF_ID;                      /* 0x01 */ +    U8              MSIxIndex;                  /* 0x01 */      U8              VP_ID;                      /* 0x02 */      U8              Flags;                      /* 0x03 */      U16             InitiatorDevHandle;         /* 0x04 */ @@ -411,15 +435,28 @@ typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR  #define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK     (0x3F) +/* RAID Accelerator Success Reply Descriptor */ +typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { +    U8              ReplyFlags;                 /* 0x00 */ +    U8              MSIxIndex;                  /* 0x01 */ +    U16             SMID;                       /* 0x02 */ +    U32             Reserved;                   /* 0x04 */ +} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, +  MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, +  Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, +  MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; + +  /* union of Reply Descriptors */  typedef union _MPI2_REPLY_DESCRIPTORS_UNION  { -    MPI2_DEFAULT_REPLY_DESCRIPTOR               Default; -    MPI2_ADDRESS_REPLY_DESCRIPTOR               AddressReply; -    MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR       SCSIIOSuccess; -    MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR  TargetAssistSuccess; -    MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; -    U64                                         Words; +    MPI2_DEFAULT_REPLY_DESCRIPTOR                   Default; +    MPI2_ADDRESS_REPLY_DESCRIPTOR                   AddressReply; +    MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR           SCSIIOSuccess; +    MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR      TargetAssistSuccess; +    MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR     TargetCommandBuffer; +    MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR  RAIDAcceleratorSuccess; +    U64                                             Words;  } MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,    Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; @@ -458,6 +495,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION  #define MPI2_FUNCTION_DIAG_RELEASE                  (0x1E) /* Diagnostic Release */  #define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST      (0x24) /* Target Command Buffer Post Base */  #define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST      (0x25) /* Target Command Buffer Post List */ +#define MPI2_FUNCTION_RAID_ACCELERATOR              (0x2C) /* RAID Accelerator*/ @@ -555,12 +593,17 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION  #define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED          (0x00A0) +/**************************************************************************** +*  RAID Accelerator values +****************************************************************************/ + +#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR             (0x00B0)  /****************************************************************************  *  IOCStatus flag to indicate that log info is available  ****************************************************************************/ -#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE  (0x8000) +#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE      (0x8000)  /****************************************************************************  *  IOCLogInfo Types diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index 2f27cf6d6c6..ab47c467964 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@   *          Title:  MPI Configuration messages and pages   *  Creation Date:  November 10, 2006   * - *    mpi2_cnfg.h Version:  02.00.10 + *    mpi2_cnfg.h Version:  02.00.11   *   *  Version History   *  --------------- @@ -95,6 +95,11 @@   *                      Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.   *                      Added PortGroups, DmaGroup, and ControlGroup fields to   *                      SAS Device Page 0. + *  05-06-09  02.00.11  Added structures and defines for IO Unit Page 5 and IO + *                      Unit Page 6. + *                      Added expander reduced functionality data to SAS + *                      Expander Page 0. + *                      Added SAS PHY Page 2 and SAS PHY Page 3.   *  --------------------------------------------------------------------------   */ @@ -723,6 +728,65 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3  #define MPI2_IOUNITPAGE3_GPIO_SETTING_ON                (0x0001) +/* IO Unit Page 5 */ + +/* + * Upper layer code (drivers, utilities, etc.) should leave this define set to + * one and check Header.PageLength or NumDmaEngines at runtime. + */ +#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES +#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES      (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { +    MPI2_CONFIG_PAGE_HEADER Header;				/* 0x00 */ +    U64                     RaidAcceleratorBufferBaseAddress;  /* 0x04 */ +    U64                     RaidAcceleratorBufferSize;         /* 0x0C */ +    U64                     RaidAcceleratorControlBaseAddress; /* 0x14 */ +    U8                      RAControlSize;                     /* 0x1C */ +    U8                      NumDmaEngines;                     /* 0x1D */ +    U8                      RAMinControlSize;                  /* 0x1E */ +    U8                      RAMaxControlSize;                  /* 0x1F */ +    U32                     Reserved1;                         /* 0x20 */ +    U32                     Reserved2;                         /* 0x24 */ +    U32                     Reserved3;                         /* 0x28 */ +    U32                     DmaEngineCapabilities +				[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ +} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, +  Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; + +#define MPI2_IOUNITPAGE5_PAGEVERSION                    (0x00) + +/* defines for IO Unit Page 5 DmaEngineCapabilities field */ +#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS      (0xFF00) +#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS     (16) + +#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP                   (0x0008) +#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION      (0x0004) +#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING                (0x0002) +#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION             (0x0001) + + +/* IO Unit Page 6 */ + +typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { +    MPI2_CONFIG_PAGE_HEADER Header;                                 /* 0x00 */ +    U16                     Flags;                                  /* 0x04 */ +    U8                      RAHostControlSize;                      /* 0x06 */ +    U8                      Reserved0;                              /* 0x07 */ +    U64                     RaidAcceleratorHostControlBaseAddress;  /* 0x08 */ +    U32                     Reserved1;                              /* 0x10 */ +    U32                     Reserved2;                              /* 0x14 */ +    U32                     Reserved3;                              /* 0x18 */ +} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, +  Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; + +#define MPI2_IOUNITPAGE6_PAGEVERSION                    (0x00) + +/* defines for IO Unit Page 6 Flags field */ +#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR  (0x0001) + +  /****************************************************************************  *   IOC Config Pages  ****************************************************************************/ @@ -1709,10 +1773,14 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0      U64                                 ActiveZoneManagerSASAddress;/* 0x2C */      U16                                 ZoneLockInactivityLimit;    /* 0x34 */      U16                                 Reserved1;                  /* 0x36 */ +    U8                                  TimeToReducedFunc;          /* 0x38 */ +    U8                                  InitialTimeToReducedFunc;   /* 0x39 */ +    U8                                  MaxReducedFuncTime;         /* 0x3A */ +    U8                                  Reserved2;                  /* 0x3B */  } MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,    Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; -#define MPI2_SASEXPANDER0_PAGEVERSION       (0x05) +#define MPI2_SASEXPANDER0_PAGEVERSION       (0x06)  /* values for SAS Expander Page 0 DiscoveryStatus field */  #define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED         (0x80000000) @@ -1737,6 +1805,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0  #define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED                 (0x00000001)  /* values for SAS Expander Page 0 Flags field */ +#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY      (0x2000)  #define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED                (0x1000)  #define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES    (0x0800)  #define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES     (0x0400) @@ -1944,6 +2013,133 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1  #define MPI2_SASPHY1_PAGEVERSION            (0x01) +/* SAS PHY Page 2 */ + +typedef struct _MPI2_SASPHY2_PHY_EVENT { +    U8          PhyEventCode;       /* 0x00 */ +    U8          Reserved1;          /* 0x01 */ +    U16         Reserved2;          /* 0x02 */ +    U32         PhyEventInfo;       /* 0x04 */ +} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, +  Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY2_PHY_EVENT_MAX +#define MPI2_SASPHY2_PHY_EVENT_MAX      (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { +    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */ +    U32                                 Reserved1;                  /* 0x08 */ +    U8                                  NumPhyEvents;               /* 0x0C */ +    U8                                  Reserved2;                  /* 0x0D */ +    U16                                 Reserved3;                  /* 0x0E */ +    MPI2_SASPHY2_PHY_EVENT              PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; +								/* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, +  Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; + +#define MPI2_SASPHY2_PAGEVERSION            (0x00) + + +/* SAS PHY Page 3 */ + +typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { +    U8          PhyEventCode;       /* 0x00 */ +    U8          Reserved1;          /* 0x01 */ +    U16         Reserved2;          /* 0x02 */ +    U8          CounterType;        /* 0x04 */ +    U8          ThresholdWindow;    /* 0x05 */ +    U8          TimeUnits;          /* 0x06 */ +    U8          Reserved3;          /* 0x07 */ +    U32         EventThreshold;     /* 0x08 */ +    U16         ThresholdFlags;     /* 0x0C */ +    U16         Reserved4;          /* 0x0E */ +} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, +  Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; + +/* values for PhyEventCode field */ +#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT                    (0x00) +#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD               (0x01) +#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR     (0x02) +#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC             (0x03) +#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM           (0x04) +#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW     (0x05) +#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR                    (0x06) +#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR         (0x20) +#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT           (0x21) +#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT           (0x22) +#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT           (0x23) +#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT           (0x24) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON   (0x25) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON   (0x26) +#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK                    (0x27) +#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK                    (0x28) +#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT               (0x29) +#define MPI2_SASPHY3_EVENT_CODE_CONNECTION                  (0x2A) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED      (0x2B) +#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME        (0x2C) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME          (0x2D) +#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME           (0x2E) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES               (0x40) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES               (0x41) +#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES         (0x42) +#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES         (0x43) +#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED           (0x44) +#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED           (0x45) +#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES              (0x50) +#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES              (0x51) +#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW               (0x52) +#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES               (0x60) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES               (0x61) +#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES         (0x63) +#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT             (0xD0) +#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE    (0xD1) +#define MPI2_SASPHY3_EVENT_CODE_RX_AIP                      (0xD2) + +/* values for the CounterType field */ +#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING                  (0x00) +#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING                (0x01) +#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE                (0x02) + +/* values for the TimeUnits field */ +#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS             (0x00) +#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS            (0x01) +#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND               (0x02) +#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS             (0x03) + +/* values for the ThresholdFlags field */ +#define MPI2_SASPHY3_TFLAGS_PHY_RESET                       (0x0002) +#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY                    (0x0001) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.ExtPageLength or NumPhyEvents at runtime. + */ +#ifndef MPI2_SASPHY3_PHY_EVENT_MAX +#define MPI2_SASPHY3_PHY_EVENT_MAX      (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { +    MPI2_CONFIG_EXTENDED_PAGE_HEADER    Header;                     /* 0x00 */ +    U32                                 Reserved1;                  /* 0x08 */ +    U8                                  NumPhyEvents;               /* 0x0C */ +    U8                                  Reserved2;                  /* 0x0D */ +    U16                                 Reserved3;                  /* 0x0E */ +    MPI2_SASPHY3_PHY_EVENT_CONFIG       PhyEventConfig +					[MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ +} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, +  Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; + +#define MPI2_SASPHY3_PAGEVERSION            (0x00) + +  /****************************************************************************  *   SAS Port Config Pages  ****************************************************************************/ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt new file mode 100644 index 00000000000..65fcaa31cb3 --- /dev/null +++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt @@ -0,0 +1,334 @@ + ============================== + Fusion-MPT MPI 2.0 Header File Change History + ============================== + + Copyright (c) 2000-2009 LSI Corporation. + + --------------------------------------- + Header Set Release Version:    02.00.12 + Header Set Release Date:       05-06-09 + --------------------------------------- + + Filename               Current version     Prior version + ----------             ---------------     ------------- + mpi2.h                 02.00.12            02.00.11 + mpi2_cnfg.h            02.00.11            02.00.10 + mpi2_init.h            02.00.07            02.00.06 + mpi2_ioc.h             02.00.11            02.00.10 + mpi2_raid.h            02.00.03            02.00.03 + mpi2_sas.h             02.00.02            02.00.02 + mpi2_targ.h            02.00.03            02.00.03 + mpi2_tool.h            02.00.03            02.00.02 + mpi2_type.h            02.00.00            02.00.00 + mpi2_ra.h              02.00.00 + mpi2_history.txt       02.00.11            02.00.12 + + + *  Date      Version   Description + *  --------  --------  ------------------------------------------------------ + +mpi2.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  06-04-07  02.00.01  Bumped MPI2_HEADER_VERSION_UNIT. + *  06-26-07  02.00.02  Bumped MPI2_HEADER_VERSION_UNIT. + *  08-31-07  02.00.03  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Moved ReplyPostHostIndex register to offset 0x6C of the + *                      MPI2_SYSTEM_INTERFACE_REGS and modified the define for + *                      MPI2_REPLY_POST_HOST_INDEX_OFFSET. + *                      Added union of request descriptors. + *                      Added union of reply descriptors. + *  10-31-07  02.00.04  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added define for MPI2_VERSION_02_00. + *                      Fixed the size of the FunctionDependent5 field in the + *                      MPI2_DEFAULT_REPLY structure. + *  12-18-07  02.00.05  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Removed the MPI-defined Fault Codes and extended the + *                      product specific codes up to 0xEFFF. + *                      Added a sixth key value for the WriteSequence register + *                      and changed the flush value to 0x0. + *                      Added message function codes for Diagnostic Buffer Post + *                      and Diagnsotic Release. + *                      New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED + *                      Moved MPI2_VERSION_UNION from mpi2_ioc.h. + *  02-29-08  02.00.06  Bumped MPI2_HEADER_VERSION_UNIT. + *  03-03-08  02.00.07  Bumped MPI2_HEADER_VERSION_UNIT. + *  05-21-08  02.00.08  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Added #defines for marking a reply descriptor as unused. + *  06-27-08  02.00.09  Bumped MPI2_HEADER_VERSION_UNIT. + *  10-02-08  02.00.10  Bumped MPI2_HEADER_VERSION_UNIT. + *                      Moved LUN field defines from mpi2_init.h. + *  01-19-09  02.00.11  Bumped MPI2_HEADER_VERSION_UNIT. + *  05-06-09  02.00.12  Bumped MPI2_HEADER_VERSION_UNIT. + *                      In all request and reply descriptors, replaced VF_ID + *                      field with MSIxIndex field. + *                      Removed DevHandle field from + *                      MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those + *                      bytes reserved. + *                      Added RAID Accelerator functionality. + *  -------------------------------------------------------------------------- + +mpi2_cnfg.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  06-04-07  02.00.01  Added defines for SAS IO Unit Page 2 PhyFlags. + *                      Added Manufacturing Page 11. + *                      Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE + *                      define. + *  06-26-07  02.00.02  Adding generic structure for product-specific + *                      Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. + *                      Rework of BIOS Page 2 configuration page. + *                      Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the + *                      forms. + *                      Added configuration pages IOC Page 8 and Driver + *                      Persistent Mapping Page 0. + *  08-31-07  02.00.03  Modified configuration pages dealing with Integrated + *                      RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, + *                      RAID Physical Disk Pages 0 and 1, RAID Configuration + *                      Page 0). + *                      Added new value for AccessStatus field of SAS Device + *                      Page 0 (_SATA_NEEDS_INITIALIZATION). + *  10-31-07  02.00.04  Added missing SEPDevHandle field to + *                      MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + *  12-18-07  02.00.05  Modified IO Unit Page 0 to use 32-bit version fields for + *                      NVDATA. + *                      Modified IOC Page 7 to use masks and added field for + *                      SASBroadcastPrimitiveMasks. + *                      Added MPI2_CONFIG_PAGE_BIOS_4. + *                      Added MPI2_CONFIG_PAGE_LOG_0. + *  02-29-08  02.00.06  Modified various names to make them 32-character unique. + *                      Added SAS Device IDs. + *                      Updated Integrated RAID configuration pages including + *                      Manufacturing Page 4, IOC Page 6, and RAID Configuration + *                      Page 0. + *  05-21-08  02.00.07  Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. + *                      Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. + *                      Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. + *                      Added missing MaxNumRoutedSasAddresses field to + *                      MPI2_CONFIG_PAGE_EXPANDER_0. + *                      Added SAS Port Page 0. + *                      Modified structure layout for + *                      MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. + *  06-27-08  02.00.08  Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use + *                      MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. + *  10-02-08  02.00.09  Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF + *                      to 0x000000FF. + *                      Added two new values for the Physical Disk Coercion Size + *                      bits in the Flags field of Manufacturing Page 4. + *                      Added product-specific Manufacturing pages 16 to 31. + *                      Modified Flags bits for controlling write cache on SATA + *                      drives in IO Unit Page 1. + *                      Added new bit to AdditionalControlFlags of SAS IO Unit + *                      Page 1 to control Invalid Topology Correction. + *                      Added SupportedPhysDisks field to RAID Volume Page 1 and + *                      added related defines. + *                      Added additional defines for RAID Volume Page 0 + *                      VolumeStatusFlags field. + *                      Modified meaning of RAID Volume Page 0 VolumeSettings + *                      define for auto-configure of hot-swap drives. + *                      Added PhysDiskAttributes field (and related defines) to + *                      RAID Physical Disk Page 0. + *                      Added MPI2_SAS_PHYINFO_PHY_VACANT define. + *                      Added three new DiscoveryStatus bits for SAS IO Unit + *                      Page 0 and SAS Expander Page 0. + *                      Removed multiplexing information from SAS IO Unit pages. + *                      Added BootDeviceWaitTime field to SAS IO Unit Page 4. + *                      Removed Zone Address Resolved bit from PhyInfo and from + *                      Expander Page 0 Flags field. + *                      Added two new AccessStatus values to SAS Device Page 0 + *                      for indicating routing problems. Added 3 reserved words + *                      to this page. + *  01-19-09  02.00.10  Fixed defines for GPIOVal field of IO Unit Page 3. + *                      Inserted missing reserved field into structure for IOC + *                      Page 6. + *                      Added more pending task bits to RAID Volume Page 0 + *                      VolumeStatusFlags defines. + *                      Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. + *                      Added a new DiscoveryStatus bit for SAS IO Unit Page 0 + *                      and SAS Expander Page 0 to flag a downstream initiator + *                      when in simplified routing mode. + *                      Removed SATA Init Failure defines for DiscoveryStatus + *                      fields of SAS IO Unit Page 0 and SAS Expander Page 0. + *                      Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. + *                      Added PortGroups, DmaGroup, and ControlGroup fields to + *                      SAS Device Page 0. + *  05-06-09  02.00.11  Added structures and defines for IO Unit Page 5 and IO + *                      Unit Page 6. + *                      Added expander reduced functionality data to SAS + *                      Expander Page 0. + *                      Added SAS PHY Page 2 and SAS PHY Page 3. + *  -------------------------------------------------------------------------- + +mpi2_init.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  10-31-07  02.00.01  Fixed name for pMpi2SCSITaskManagementRequest_t. + *  12-18-07  02.00.02  Modified Task Management Target Reset Method defines. + *  02-29-08  02.00.03  Added Query Task Set and Query Unit Attention. + *  03-03-08  02.00.04  Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. + *  05-21-08  02.00.05  Fixed typo in name of Mpi2SepRequest_t. + *  10-02-08  02.00.06  Removed Untagged and No Disconnect values from SCSI IO + *                      Control field Task Attribute flags. + *                      Moved LUN field defines to mpi2.h becasue they are + *                      common to many structures. + *  05-06-09  02.00.07  Changed task management type of Query Unit Attention to + *                      Query Asynchronous Event. + *                      Defined two new bits in the SlotStatus field of the SCSI + *                      Enclosure Processor Request and Reply. + *  -------------------------------------------------------------------------- + +mpi2_ioc.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  06-04-07  02.00.01  In IOCFacts Reply structure, renamed MaxDevices to + *                      MaxTargets. + *                      Added TotalImageSize field to FWDownload Request. + *                      Added reserved words to FWUpload Request. + *  06-26-07  02.00.02  Added IR Configuration Change List Event. + *  08-31-07  02.00.03  Removed SystemReplyQueueDepth field from the IOCInit + *                      request and replaced it with + *                      ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. + *                      Replaced the MinReplyQueueDepth field of the IOCFacts + *                      reply with MaxReplyDescriptorPostQueueDepth. + *                      Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum + *                      depth for the Reply Descriptor Post Queue. + *                      Added SASAddress field to Initiator Device Table + *                      Overflow Event data. + *  10-31-07  02.00.04  Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING + *                      for SAS Initiator Device Status Change Event data. + *                      Modified Reason Code defines for SAS Topology Change + *                      List Event data, including adding a bit for PHY Vacant + *                      status, and adding a mask for the Reason Code. + *                      Added define for + *                      MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. + *                      Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. + *  12-18-07  02.00.05  Added Boot Status defines for the IOCExceptions field of + *                      the IOCFacts Reply. + *                      Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. + *                      Moved MPI2_VERSION_UNION to mpi2.h. + *                      Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks + *                      instead of enables, and added SASBroadcastPrimitiveMasks + *                      field. + *                      Added Log Entry Added Event and related structure. + *  02-29-08  02.00.06  Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. + *                      Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. + *                      Added MaxVolumes and MaxPersistentEntries fields to + *                      IOCFacts reply. + *                      Added ProtocalFlags and IOCCapabilities fields to + *                      MPI2_FW_IMAGE_HEADER. + *                      Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. + *  03-03-08  02.00.07  Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to + *                      a U16 (from a U32). + *                      Removed extra 's' from EventMasks name. + *  06-27-08  02.00.08  Fixed an offset in a comment. + *  10-02-08  02.00.09  Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. + *                      Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and + *                      renamed MinReplyFrameSize to ReplyFrameSize. + *                      Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. + *                      Added two new RAIDOperation values for Integrated RAID + *                      Operations Status Event data. + *                      Added four new IR Configuration Change List Event data + *                      ReasonCode values. + *                      Added two new ReasonCode defines for SAS Device Status + *                      Change Event data. + *                      Added three new DiscoveryStatus bits for the SAS + *                      Discovery event data. + *                      Added Multiplexing Status Change bit to the PhyStatus + *                      field of the SAS Topology Change List event data. + *                      Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. + *                      BootFlags are now product-specific. + *                      Added defines for the indivdual signature bytes + *                      for MPI2_INIT_IMAGE_FOOTER. + *  01-19-09  02.00.10  Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. + *                      Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR + *                      define. + *                      Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE + *                      define. + *                      Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + *  05-06-09  02.00.11  Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + *                      Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + *                      Added two new reason codes for SAS Device Status Change + *                      Event. + *                      Added new event: SAS PHY Counter. + *  -------------------------------------------------------------------------- + +mpi2_raid.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  08-31-07  02.00.01  Modifications to RAID Action request and reply, + *                      including the Actions and ActionData. + *  02-29-08  02.00.02  Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. + *  05-21-08  02.00.03  Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that + *                      the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT + *                      can be sized by the build environment. + *  -------------------------------------------------------------------------- + +mpi2_sas.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  06-26-07  02.00.01  Added Clear All Persistent Operation to SAS IO Unit + *                      Control Request. + *  10-02-08  02.00.02  Added Set IOC Parameter Operation to SAS IO Unit Control + *                      Request. + *  -------------------------------------------------------------------------- + +mpi2_targ.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  08-31-07  02.00.01  Added Command Buffer Data Location Address Space bits to + *                      BufferPostFlags field of CommandBufferPostBase Request. + *  02-29-08  02.00.02  Modified various names to make them 32-character unique. + *  10-02-08  02.00.03  Removed NextCmdBufferOffset from + *                      MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST. + *                      Target Status Send Request only takes a single SGE for + *                      response data. + *  -------------------------------------------------------------------------- + +mpi2_tool.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  12-18-07  02.00.01  Added Diagnostic Buffer Post and Diagnostic Release + *                      structures and defines. + *  02-29-08  02.00.02  Modified various names to make them 32-character unique. + *  05-06-09  02.00.03  Added ISTWI Read Write Tool and Diagnostic CLI Tool. + *  -------------------------------------------------------------------------- + +mpi2_type.h + *  04-30-07  02.00.00  Corresponds to Fusion-MPT MPI Specification Rev A. + *  -------------------------------------------------------------------------- + +mpi2_ra.h + *  05-06-09  02.00.00  Initial version. + *  -------------------------------------------------------------------------- + +mpi2_history.txt         Parts list history + +Filename     02.00.12 +----------   -------- +mpi2.h       02.00.12 +mpi2_cnfg.h  02.00.11 +mpi2_init.h  02.00.07 +mpi2_ioc.h   02.00.11 +mpi2_raid.h  02.00.03 +mpi2_sas.h   02.00.02 +mpi2_targ.h  02.00.03 +mpi2_tool.h  02.00.03 +mpi2_type.h  02.00.00 +mpi2_ra.h    02.00.00 + +Filename     02.00.11  02.00.10  02.00.09  02.00.08  02.00.07  02.00.06 +----------   --------  --------  --------  --------  --------  -------- +mpi2.h       02.00.11  02.00.10  02.00.09  02.00.08  02.00.07  02.00.06 +mpi2_cnfg.h  02.00.10  02.00.09  02.00.08  02.00.07  02.00.06  02.00.06 +mpi2_init.h  02.00.06  02.00.06  02.00.05  02.00.05  02.00.04  02.00.03 +mpi2_ioc.h   02.00.10  02.00.09  02.00.08  02.00.07  02.00.07  02.00.06 +mpi2_raid.h  02.00.03  02.00.03  02.00.03  02.00.03  02.00.02  02.00.02 +mpi2_sas.h   02.00.02  02.00.02  02.00.01  02.00.01  02.00.01  02.00.01 +mpi2_targ.h  02.00.03  02.00.03  02.00.02  02.00.02  02.00.02  02.00.02 +mpi2_tool.h  02.00.02  02.00.02  02.00.02  02.00.02  02.00.02  02.00.02 +mpi2_type.h  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00 + +Filename     02.00.05  02.00.04  02.00.03  02.00.02  02.00.01  02.00.00 +----------   --------  --------  --------  --------  --------  -------- +mpi2.h       02.00.05  02.00.04  02.00.03  02.00.02  02.00.01  02.00.00 +mpi2_cnfg.h  02.00.05  02.00.04  02.00.03  02.00.02  02.00.01  02.00.00 +mpi2_init.h  02.00.02  02.00.01  02.00.00  02.00.00  02.00.00  02.00.00 +mpi2_ioc.h   02.00.05  02.00.04  02.00.03  02.00.02  02.00.01  02.00.00 +mpi2_raid.h  02.00.01  02.00.01  02.00.01  02.00.00  02.00.00  02.00.00 +mpi2_sas.h   02.00.01  02.00.01  02.00.01  02.00.01  02.00.00  02.00.00 +mpi2_targ.h  02.00.01  02.00.01  02.00.01  02.00.00  02.00.00  02.00.00 +mpi2_tool.h  02.00.01  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00 +mpi2_type.h  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00  02.00.00 + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index f1115f0f0eb..563e56d2e94 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2008 LSI Corporation. + *  Copyright (c) 2000-2009 LSI Corporation.   *   *   *           Name:  mpi2_init.h   *          Title:  MPI SCSI initiator mode messages and structures   *  Creation Date:  June 23, 2006   * - *    mpi2_init.h Version:  02.00.06 + *    mpi2_init.h Version:  02.00.07   *   *  Version History   *  --------------- @@ -23,6 +23,10 @@   *                      Control field Task Attribute flags.   *                      Moved LUN field defines to mpi2.h becasue they are   *                      common to many structures. + *  05-06-09  02.00.07  Changed task management type of Query Unit Attention to + *                      Query Asynchronous Event. + *                      Defined two new bits in the SlotStatus field of the SCSI + *                      Enclosure Processor Request and Reply.   *  --------------------------------------------------------------------------   */ @@ -289,7 +293,11 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST  #define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK           (0x07)  #define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA              (0x08)  #define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET         (0x09) -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION   (0x0A) +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT      (0x0A) + +/* obsolete TaskType name */ +#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION	\ +	(MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)  /* MsgFlags bits */ @@ -375,6 +383,8 @@ typedef struct _MPI2_SEP_REQUEST  #define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE               (0x00000100)  #define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED            (0x00000080)  #define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT         (0x00000040) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY       (0x00000010) +#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY         (0x00000008)  #define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING          (0x00000004)  #define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY              (0x00000002)  #define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR                (0x00000001) @@ -410,6 +420,8 @@ typedef struct _MPI2_SEP_REPLY  #define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE             (0x00000100)  #define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED          (0x00000080)  #define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT       (0x00000040) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY     (0x00000010) +#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY       (0x00000008)  #define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING        (0x00000004)  #define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY            (0x00000002)  #define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR              (0x00000001) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index 8c5d81870c0..c294128bdeb 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@   *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages   *  Creation Date:  October 11, 2006   * - *  mpi2_ioc.h Version:  02.00.10 + *  mpi2_ioc.h Version:  02.00.11   *   *  Version History   *  --------------- @@ -79,6 +79,11 @@   *                      Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE   *                      define.   *                      Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. + *  05-06-09  02.00.11  Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. + *                      Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. + *                      Added two new reason codes for SAS Device Status Change + *                      Event. + *                      Added new event: SAS PHY Counter.   *  --------------------------------------------------------------------------   */ @@ -261,6 +266,8 @@ typedef struct _MPI2_IOC_FACTS_REPLY  /* ProductID field uses MPI2_FW_HEADER_PID_ */  /* IOCCapabilities */ +#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX            (0x00008000) +#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR       (0x00004000)  #define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY           (0x00002000)  #define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID        (0x00001000)  #define MPI2_IOCFACTS_CAPABILITY_TLR                    (0x00000800) @@ -440,6 +447,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY  #define MPI2_EVENT_IR_PHYSICAL_DISK                 (0x001F)  #define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST     (0x0020)  #define MPI2_EVENT_LOG_ENTRY_ADDED                  (0x0021) +#define MPI2_EVENT_SAS_PHY_COUNTER                  (0x0022)  /* Log Entry Added Event data */ @@ -502,17 +510,19 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE    MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;  /* SAS Device Status Change Event data ReasonCode values */ -#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA               (0x05) -#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED              (0x07) -#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET    (0x08) -#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL      (0x09) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL  (0x0A) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL  (0x0B) -#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL      (0x0C) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION       (0x0D) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET   (0x0E) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL  (0x0F) -#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE        (0x10) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA                           (0x05) +#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED                          (0x07) +#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET                (0x08) +#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL                  (0x09) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL              (0x0A) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL              (0x0B) +#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL                  (0x0C) +#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION                   (0x0D) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET               (0x0E) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL              (0x0F) +#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE                    (0x10) +#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY       (0x11) +#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY   (0x12)  /* Integrated RAID Operation Status Event data */ @@ -822,6 +832,37 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE  #define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING       (0x02) +/* SAS PHY Counter Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { +    U64         TimeStamp;          /* 0x00 */ +    U32         Reserved1;          /* 0x08 */ +    U8          PhyEventCode;       /* 0x0C */ +    U8          PhyNum;             /* 0x0D */ +    U16         Reserved2;          /* 0x0E */ +    U32         PhyEventInfo;       /* 0x10 */ +    U8          CounterType;        /* 0x14 */ +    U8          ThresholdWindow;    /* 0x15 */ +    U8          TimeUnits;          /* 0x16 */ +    U8          Reserved3;          /* 0x17 */ +    U32         EventThreshold;     /* 0x18 */ +    U16         ThresholdFlags;     /* 0x1C */ +    U16         Reserved4;          /* 0x1E */ +} MPI2_EVENT_DATA_SAS_PHY_COUNTER, +  MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, +  Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; + +/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the + * PhyEventCode field + * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the + * CounterType field + * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the + * TimeUnits field + * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the + * ThresholdFlags field + * */ + +  /****************************************************************************  *  EventAck message  ****************************************************************************/ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h index 2ff4e936bd3..007e950f7bf 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h @@ -1,12 +1,12 @@  /* - *  Copyright (c) 2000-2008 LSI Corporation. + *  Copyright (c) 2000-2009 LSI Corporation.   *   *   *           Name:  mpi2_tool.h   *          Title:  MPI diagnostic tool structures and definitions   *  Creation Date:  March 26, 2007   * - *    mpi2_tool.h Version:  02.00.02 + *    mpi2_tool.h Version:  02.00.03   *   *  Version History   *  --------------- @@ -17,6 +17,7 @@   *  12-18-07  02.00.01  Added Diagnostic Buffer Post and Diagnostic Release   *                      structures and defines.   *  02-29-08  02.00.02  Modified various names to make them 32-character unique. + *  05-06-09  02.00.03  Added ISTWI Read Write Tool and Diagnostic CLI Tool.   *  --------------------------------------------------------------------------   */ @@ -32,7 +33,10 @@  /* defines for the Tools */  #define MPI2_TOOLBOX_CLEAN_TOOL                     (0x00)  #define MPI2_TOOLBOX_MEMORY_MOVE_TOOL               (0x01) +#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL          (0x03)  #define MPI2_TOOLBOX_BEACON_TOOL                    (0x05) +#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL            (0x06) +  /****************************************************************************  *  Toolbox reply @@ -112,6 +116,77 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST  /**************************************************************************** +*  Toolbox ISTWI Read Write Tool +****************************************************************************/ + +/* Toolbox ISTWI Read Write Tool request message */ +typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { +    U8                      Tool;                       /* 0x00 */ +    U8                      Reserved1;                  /* 0x01 */ +    U8                      ChainOffset;                /* 0x02 */ +    U8                      Function;                   /* 0x03 */ +    U16                     Reserved2;                  /* 0x04 */ +    U8                      Reserved3;                  /* 0x06 */ +    U8                      MsgFlags;                   /* 0x07 */ +    U8                      VP_ID;                      /* 0x08 */ +    U8                      VF_ID;                      /* 0x09 */ +    U16                     Reserved4;                  /* 0x0A */ +    U32                     Reserved5;                  /* 0x0C */ +    U32                     Reserved6;                  /* 0x10 */ +    U8                      DevIndex;                   /* 0x14 */ +    U8                      Action;                     /* 0x15 */ +    U8                      SGLFlags;                   /* 0x16 */ +    U8                      Reserved7;                  /* 0x17 */ +    U16                     TxDataLength;               /* 0x18 */ +    U16                     RxDataLength;               /* 0x1A */ +    U32                     Reserved8;                  /* 0x1C */ +    U32                     Reserved9;                  /* 0x20 */ +    U32                     Reserved10;                 /* 0x24 */ +    U32                     Reserved11;                 /* 0x28 */ +    U32                     Reserved12;                 /* 0x2C */ +    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x30 */ +} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, +  MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, +  Mpi2ToolboxIstwiReadWriteRequest_t, +  MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; + +/* values for the Action field */ +#define MPI2_TOOL_ISTWI_ACTION_READ_DATA            (0x01) +#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA           (0x02) +#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE             (0x03) +#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS          (0x10) +#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS          (0x11) +#define MPI2_TOOL_ISTWI_ACTION_RESET                (0x12) + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Toolbox ISTWI Read Write Tool reply message */ +typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { +    U8                      Tool;                       /* 0x00 */ +    U8                      Reserved1;                  /* 0x01 */ +    U8                      MsgLength;                  /* 0x02 */ +    U8                      Function;                   /* 0x03 */ +    U16                     Reserved2;                  /* 0x04 */ +    U8                      Reserved3;                  /* 0x06 */ +    U8                      MsgFlags;                   /* 0x07 */ +    U8                      VP_ID;                      /* 0x08 */ +    U8                      VF_ID;                      /* 0x09 */ +    U16                     Reserved4;                  /* 0x0A */ +    U16                     Reserved5;                  /* 0x0C */ +    U16                     IOCStatus;                  /* 0x0E */ +    U32                     IOCLogInfo;                 /* 0x10 */ +    U8                      DevIndex;                   /* 0x14 */ +    U8                      Action;                     /* 0x15 */ +    U8                      IstwiStatus;                /* 0x16 */ +    U8                      Reserved6;                  /* 0x17 */ +    U16                     TxDataCount;                /* 0x18 */ +    U16                     RxDataCount;                /* 0x1A */ +} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, +  Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; + + +/****************************************************************************  *  Toolbox Beacon Tool request  ****************************************************************************/ @@ -139,6 +214,61 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST  #define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON        (0x01) +/**************************************************************************** +*  Toolbox Diagnostic CLI Tool +****************************************************************************/ + +#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH    (0x5C) + +/* Toolbox Diagnostic CLI Tool request message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { +    U8                      Tool;                       /* 0x00 */ +    U8                      Reserved1;                  /* 0x01 */ +    U8                      ChainOffset;                /* 0x02 */ +    U8                      Function;                   /* 0x03 */ +    U16                     Reserved2;                  /* 0x04 */ +    U8                      Reserved3;                  /* 0x06 */ +    U8                      MsgFlags;                   /* 0x07 */ +    U8                      VP_ID;                      /* 0x08 */ +    U8                      VF_ID;                      /* 0x09 */ +    U16                     Reserved4;                  /* 0x0A */ +    U8                      SGLFlags;                   /* 0x0C */ +    U8                      Reserved5;                  /* 0x0D */ +    U16                     Reserved6;                  /* 0x0E */ +    U32                     DataLength;                 /* 0x10 */ +    U8                      DiagnosticCliCommand +		[MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH];     /* 0x14 */ +    MPI2_SGE_SIMPLE_UNION   SGL;                        /* 0x70 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, +  MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, +  Mpi2ToolboxDiagnosticCliRequest_t, +  MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; + +/* values for SGLFlags field are in the SGL section of mpi2.h */ + + +/* Toolbox Diagnostic CLI Tool reply message */ +typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { +    U8                      Tool;                       /* 0x00 */ +    U8                      Reserved1;                  /* 0x01 */ +    U8                      MsgLength;                  /* 0x02 */ +    U8                      Function;                   /* 0x03 */ +    U16                     Reserved2;                  /* 0x04 */ +    U8                      Reserved3;                  /* 0x06 */ +    U8                      MsgFlags;                   /* 0x07 */ +    U8                      VP_ID;                      /* 0x08 */ +    U8                      VF_ID;                      /* 0x09 */ +    U16                     Reserved4;                  /* 0x0A */ +    U16                     Reserved5;                  /* 0x0C */ +    U16                     IOCStatus;                  /* 0x0E */ +    U32                     IOCLogInfo;                 /* 0x10 */ +    U32                     ReturnedDataLength;         /* 0x14 */ +} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, +  MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, +  Mpi2ToolboxDiagnosticCliReply_t, +  MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; + +  /*****************************************************************************  *  *       Diagnostic Buffer Messages diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index d95d2f274cb..670241efa4b 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -63,7 +63,7 @@  static MPT_CALLBACK	mpt_callbacks[MPT_MAX_CALLBACKS];  #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ -#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */ +#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */  static int max_queue_depth = -1;  module_param(max_queue_depth, int, 0); @@ -543,13 +543,13 @@ mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)   * _base_display_reply_info -   * @ioc: pointer to scsi command object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   *   * Return nothing.   */  static void -_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply)  {  	MPI2DefaultReply_t *mpi_reply; @@ -572,22 +572,24 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,   * mpt2sas_base_done - base internal command completion routine   * @ioc: pointer to scsi command object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply)  {  	MPI2DefaultReply_t *mpi_reply;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) -		return; +		return 1;  	if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) -		return; +		return 1;  	ioc->base_cmds.status |= MPT2_CMD_COMPLETE;  	if (mpi_reply) { @@ -596,18 +598,20 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)  	}  	ioc->base_cmds.status &= ~MPT2_CMD_PENDING;  	complete(&ioc->base_cmds.done); +	return 1;  }  /**   * _base_async_event - main callback handler for firmware asyn events   * @ioc: pointer to scsi command object - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -static void -_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +static u8 +_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)  {  	Mpi2EventNotificationReply_t *mpi_reply;  	Mpi2EventAckRequest_t *ack_request; @@ -615,9 +619,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (!mpi_reply) -		return; +		return 1;  	if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) -		return; +		return 1;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	_base_display_event_data(ioc, mpi_reply);  #endif @@ -635,16 +639,47 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  	ack_request->Function = MPI2_FUNCTION_EVENT_ACK;  	ack_request->Event = mpi_reply->Event;  	ack_request->EventContext = mpi_reply->EventContext; -	ack_request->VF_ID = VF_ID; -	mpt2sas_base_put_smid_default(ioc, smid, VF_ID); +	ack_request->VF_ID = 0;  /* TODO */ +	ack_request->VP_ID = 0; +	mpt2sas_base_put_smid_default(ioc, smid);   out:  	/* scsih callback handler */ -	mpt2sas_scsih_event_callback(ioc, VF_ID, reply); +	mpt2sas_scsih_event_callback(ioc, msix_index, reply);  	/* ctl callback handler */ -	mpt2sas_ctl_event_callback(ioc, VF_ID, reply); +	mpt2sas_ctl_event_callback(ioc, msix_index, reply); + +	return 1; +} + +/** + * _base_get_cb_idx - obtain the callback index + * @ioc: per adapter object + * @smid: system request message index + * + * Return callback index. + */ +static u8 +_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ +	int i; +	u8 cb_idx = 0xFF; + +	if (smid >= ioc->hi_priority_smid) { +		if (smid < ioc->internal_smid) { +			i = smid - ioc->hi_priority_smid; +			cb_idx = ioc->hpr_lookup[i].cb_idx; +		} else { +			i = smid - ioc->internal_smid; +			cb_idx = ioc->internal_lookup[i].cb_idx; +		} +	} else { +		i = smid - 1; +		cb_idx = ioc->scsi_lookup[i].cb_idx; +	} +	return cb_idx;  }  /** @@ -680,7 +715,6 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)  {  	u32 him_register; -	writel(0, &ioc->chip->HostInterruptStatus);  	him_register = readl(&ioc->chip->HostInterruptMask);  	him_register &= ~MPI2_HIM_RIM;  	writel(him_register, &ioc->chip->HostInterruptMask); @@ -712,9 +746,10 @@ _base_interrupt(int irq, void *bus_id)  	u16 smid;  	u8 cb_idx;  	u32 reply; -	u8 VF_ID; +	u8 msix_index;  	struct MPT2SAS_ADAPTER *ioc = bus_id;  	Mpi2ReplyDescriptorsUnion_t *rpf; +	u8 rc;  	if (ioc->mask_interrupts)  		return IRQ_NONE; @@ -733,7 +768,7 @@ _base_interrupt(int irq, void *bus_id)  		reply = 0;  		cb_idx = 0xFF;  		smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); -		VF_ID = rpf->Default.VF_ID; +		msix_index = rpf->Default.MSIxIndex;  		if (request_desript_type ==  		    MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {  			reply = le32_to_cpu @@ -745,16 +780,18 @@ _base_interrupt(int irq, void *bus_id)  		    MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)  			goto next;  		if (smid) -			cb_idx = ioc->scsi_lookup[smid - 1].cb_idx; +			cb_idx = _base_get_cb_idx(ioc, smid);  		if (smid && cb_idx != 0xFF) { -			mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply); +			rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, +			    reply);  			if (reply) -				_base_display_reply_info(ioc, smid, VF_ID, +				_base_display_reply_info(ioc, smid, msix_index,  				    reply); -			mpt2sas_base_free_smid(ioc, smid); +			if (rc) +				mpt2sas_base_free_smid(ioc, smid);  		}  		if (!smid) -			_base_async_event(ioc, VF_ID, reply); +			_base_async_event(ioc, msix_index, reply);  		/* reply free queue handling */  		if (reply) { @@ -1191,19 +1228,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)  }  /** - * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr - * @ioc: per adapter object - * @smid: system request message index(smid zero is invalid) - * - * Returns phys pointer to message frame. - */ -dma_addr_t -mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ -	return ioc->request_dma + (smid * ioc->request_sz); -} - -/**   * mpt2sas_base_get_msg_frame - obtain request mf pointer   * @ioc: per adapter object   * @smid: system request message index(smid zero is invalid) @@ -1258,7 +1282,7 @@ mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)  }  /** - * mpt2sas_base_get_smid - obtain a free smid + * mpt2sas_base_get_smid - obtain a free smid from internal queue   * @ioc: per adapter object   * @cb_idx: callback index   * @@ -1272,6 +1296,39 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)  	u16 smid;  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +	if (list_empty(&ioc->internal_free_list)) { +		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +		printk(MPT2SAS_ERR_FMT "%s: smid not available\n", +		    ioc->name, __func__); +		return 0; +	} + +	request = list_entry(ioc->internal_free_list.next, +	    struct request_tracker, tracker_list); +	request->cb_idx = cb_idx; +	smid = request->smid; +	list_del(&request->tracker_list); +	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +	return smid; +} + +/** + * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue + * @ioc: per adapter object + * @cb_idx: callback index + * @scmd: pointer to scsi command object + * + * Returns smid (zero is invalid) + */ +u16 +mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, +    struct scsi_cmnd *scmd) +{ +	unsigned long flags; +	struct request_tracker *request; +	u16 smid; + +	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	if (list_empty(&ioc->free_list)) {  		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);  		printk(MPT2SAS_ERR_FMT "%s: smid not available\n", @@ -1281,6 +1338,36 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)  	request = list_entry(ioc->free_list.next,  	    struct request_tracker, tracker_list); +	request->scmd = scmd; +	request->cb_idx = cb_idx; +	smid = request->smid; +	list_del(&request->tracker_list); +	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +	return smid; +} + +/** + * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue + * @ioc: per adapter object + * @cb_idx: callback index + * + * Returns smid (zero is invalid) + */ +u16 +mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) +{ +	unsigned long flags; +	struct request_tracker *request; +	u16 smid; + +	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); +	if (list_empty(&ioc->hpr_free_list)) { +		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +		return 0; +	} + +	request = list_entry(ioc->hpr_free_list.next, +	    struct request_tracker, tracker_list);  	request->cb_idx = cb_idx;  	smid = request->smid;  	list_del(&request->tracker_list); @@ -1300,10 +1387,32 @@ void  mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)  {  	unsigned long flags; +	int i;  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	ioc->scsi_lookup[smid - 1].cb_idx = 0xFF; -	list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list, +	if (smid >= ioc->hi_priority_smid) { +		if (smid < ioc->internal_smid) { +			/* hi-priority */ +			i = smid - ioc->hi_priority_smid; +			ioc->hpr_lookup[i].cb_idx = 0xFF; +			list_add_tail(&ioc->hpr_lookup[i].tracker_list, +			    &ioc->hpr_free_list); +		} else { +			/* internal queue */ +			i = smid - ioc->internal_smid; +			ioc->internal_lookup[i].cb_idx = 0xFF; +			list_add_tail(&ioc->internal_lookup[i].tracker_list, +			    &ioc->internal_free_list); +		} +		spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +		return; +	} + +	/* scsiio queue */ +	i = smid - 1; +	ioc->scsi_lookup[i].cb_idx = 0xFF; +	ioc->scsi_lookup[i].scmd = NULL; +	list_add_tail(&ioc->scsi_lookup[i].tracker_list,  	    &ioc->free_list);  	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -1352,21 +1461,19 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,   * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware   * @ioc: per adapter object   * @smid: system request message index - * @vf_id: virtual function id   * @handle: device handle   *   * Return nothing.   */  void -mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, -    u16 handle) +mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)  {  	Mpi2RequestDescriptorUnion_t descriptor;  	u64 *request = (u64 *)&descriptor;  	descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; -	descriptor.SCSIIO.VF_ID = vf_id; +	descriptor.SCSIIO.MSIxIndex = 0; /* TODO */  	descriptor.SCSIIO.SMID = cpu_to_le16(smid);  	descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);  	descriptor.SCSIIO.LMID = 0; @@ -1379,20 +1486,18 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,   * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware   * @ioc: per adapter object   * @smid: system request message index - * @vf_id: virtual function id   *   * Return nothing.   */  void -mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, -    u8 vf_id) +mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)  {  	Mpi2RequestDescriptorUnion_t descriptor;  	u64 *request = (u64 *)&descriptor;  	descriptor.HighPriority.RequestFlags =  	    MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; -	descriptor.HighPriority.VF_ID = vf_id; +	descriptor.HighPriority.MSIxIndex = 0; /* TODO */  	descriptor.HighPriority.SMID = cpu_to_le16(smid);  	descriptor.HighPriority.LMID = 0;  	descriptor.HighPriority.Reserved1 = 0; @@ -1404,18 +1509,17 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,   * mpt2sas_base_put_smid_default - Default, primarily used for config pages   * @ioc: per adapter object   * @smid: system request message index - * @vf_id: virtual function id   *   * Return nothing.   */  void -mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id) +mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)  {  	Mpi2RequestDescriptorUnion_t descriptor;  	u64 *request = (u64 *)&descriptor;  	descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; -	descriptor.Default.VF_ID = vf_id; +	descriptor.Default.MSIxIndex = 0; /* TODO */  	descriptor.Default.SMID = cpu_to_le16(smid);  	descriptor.Default.LMID = 0;  	descriptor.Default.DescriptorTypeDependent = 0; @@ -1427,21 +1531,20 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)   * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware   * @ioc: per adapter object   * @smid: system request message index - * @vf_id: virtual function id   * @io_index: value used to track the IO   *   * Return nothing.   */  void  mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, -    u8 vf_id, u16 io_index) +    u16 io_index)  {  	Mpi2RequestDescriptorUnion_t descriptor;  	u64 *request = (u64 *)&descriptor;  	descriptor.SCSITarget.RequestFlags =  	    MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; -	descriptor.SCSITarget.VF_ID = vf_id; +	descriptor.SCSITarget.MSIxIndex = 0; /* TODO */  	descriptor.SCSITarget.SMID = cpu_to_le16(smid);  	descriptor.SCSITarget.LMID = 0;  	descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); @@ -1717,6 +1820,8 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)  	}  	kfree(ioc->scsi_lookup); +	kfree(ioc->hpr_lookup); +	kfree(ioc->internal_lookup);  } @@ -1736,7 +1841,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	u16 num_of_reply_frames;  	u16 chains_needed_per_io;  	u32 sz, total_sz; -	u16 i;  	u32 retry_sz;  	u16 max_request_credit; @@ -1764,7 +1868,10 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  		    MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :  		    facts->RequestCredit;  	} -	ioc->request_depth = max_request_credit; + +	ioc->hba_queue_depth = max_request_credit; +	ioc->hi_priority_depth = facts->HighPriorityCredit; +	ioc->internal_depth = ioc->hi_priority_depth + 5;  	/* request frame size */  	ioc->request_sz = facts->IOCRequestFrameSize * 4; @@ -1802,7 +1909,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	ioc->chains_needed_per_io = chains_needed_per_io;  	/* reply free queue sizing - taking into account for events */ -	num_of_reply_frames = ioc->request_depth + 32; +	num_of_reply_frames = ioc->hba_queue_depth + 32;  	/* number of replies frames can't be a multiple of 16 */  	/* decrease number of reply frames by 1 */ @@ -1823,7 +1930,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	 * frames  	 */ -	queue_size = ioc->request_depth + num_of_reply_frames + 1; +	queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1;  	/* round up to 16 byte boundary */  	if (queue_size % 16)  		queue_size += 16 - (queue_size % 16); @@ -1837,60 +1944,85 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  		if (queue_diff % 16)  			queue_diff += 16 - (queue_diff % 16); -		/* adjust request_depth, reply_free_queue_depth, +		/* adjust hba_queue_depth, reply_free_queue_depth,  		 * and queue_size  		 */ -		ioc->request_depth -= queue_diff; +		ioc->hba_queue_depth -= queue_diff;  		ioc->reply_free_queue_depth -= queue_diff;  		queue_size -= queue_diff;  	}  	ioc->reply_post_queue_depth = queue_size; -	/* max scsi host queue depth */ -	ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT; -	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth" -	    "(%d)\n", ioc->name, ioc->shost->can_queue)); -  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "  	    "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "  	    "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,  	    ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,  	    ioc->chains_needed_per_io)); +	ioc->scsiio_depth = ioc->hba_queue_depth - +	    ioc->hi_priority_depth - ioc->internal_depth; + +	/* set the scsi host can_queue depth +	 * with some internal commands that could be outstanding +	 */ +	ioc->shost->can_queue = ioc->scsiio_depth - (2); +	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " +	    "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); +  	/* contiguous pool for request and chains, 16 byte align, one extra "  	 * "frame for smid=0  	 */ -	ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth; -	sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz); +	ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; +	sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz); + +	/* hi-priority queue */ +	sz += (ioc->hi_priority_depth * ioc->request_sz); + +	/* internal queue */ +	sz += (ioc->internal_depth * ioc->request_sz);  	ioc->request_dma_sz = sz;  	ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);  	if (!ioc->request) {  		printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " -		    "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " -		    "total(%d kB)\n", ioc->name, ioc->request_depth, +		    "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " +		    "total(%d kB)\n", ioc->name, ioc->hba_queue_depth,  		    ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -		if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH) +		if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH)  			goto out;  		retry_sz += 64; -		ioc->request_depth = max_request_credit - retry_sz; +		ioc->hba_queue_depth = max_request_credit - retry_sz;  		goto retry_allocation;  	}  	if (retry_sz)  		printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " -		    "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), " -		    "total(%d kb)\n", ioc->name, ioc->request_depth, +		    "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " +		    "total(%d kb)\n", ioc->name, ioc->hba_queue_depth,  		    ioc->chains_needed_per_io, ioc->request_sz, sz/1024); -	ioc->chain = ioc->request + ((ioc->request_depth + 1) * + +	/* hi-priority queue */ +	ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * +	    ioc->request_sz); +	ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * +	    ioc->request_sz); + +	/* internal queue */ +	ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * +	    ioc->request_sz); +	ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * +	    ioc->request_sz); + +	ioc->chain = ioc->internal + (ioc->internal_depth *  	    ioc->request_sz); -	ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) * +	ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *  	    ioc->request_sz); +  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "  	    "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, -	    ioc->request, ioc->request_depth, ioc->request_sz, -	    ((ioc->request_depth + 1) * ioc->request_sz)/1024)); +	    ioc->request, ioc->hba_queue_depth, ioc->request_sz, +	    (ioc->hba_queue_depth * ioc->request_sz)/1024));  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"  	    "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,  	    ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * @@ -1899,7 +2031,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	    ioc->name, (unsigned long long) ioc->request_dma));  	total_sz += sz; -	ioc->scsi_lookup = kcalloc(ioc->request_depth, +	ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,  	    sizeof(struct request_tracker), GFP_KERNEL);  	if (!ioc->scsi_lookup) {  		printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n", @@ -1907,12 +2039,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  		goto out;  	} -	 /* initialize some bits */ -	for (i = 0; i < ioc->request_depth; i++) -		ioc->scsi_lookup[i].smid = i + 1; +	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): " +	    "depth(%d)\n", ioc->name, ioc->request, +	    ioc->scsiio_depth)); + +	/* initialize hi-priority queue smid's */ +	ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, +	    sizeof(struct request_tracker), GFP_KERNEL); +	if (!ioc->hpr_lookup) { +		printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n", +		    ioc->name); +		goto out; +	} +	ioc->hi_priority_smid = ioc->scsiio_depth + 1; +	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): " +	    "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority, +	    ioc->hi_priority_depth, ioc->hi_priority_smid)); + +	/* initialize internal queue smid's */ +	ioc->internal_lookup = kcalloc(ioc->internal_depth, +	    sizeof(struct request_tracker), GFP_KERNEL); +	if (!ioc->internal_lookup) { +		printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n", +		    ioc->name); +		goto out; +	} +	ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; +	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): " +	    "depth(%d), start smid(%d)\n", ioc->name, ioc->internal, +	     ioc->internal_depth, ioc->internal_smid));  	/* sense buffers, 4 byte align */ -	sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE; +	sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;  	ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,  	    0);  	if (!ioc->sense_dma_pool) { @@ -1929,7 +2087,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)  	}  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT  	    "sense pool(0x%p): depth(%d), element_size(%d), pool_size" -	    "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth, +	    "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth,  	    SCSI_SENSE_BUFFERSIZE, sz/1024));  	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",  	    ioc->name, (unsigned long long)ioc->sense_dma)); @@ -2304,7 +2462,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,  	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),  	    &ioc->chip->Doorbell); -	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { +	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {  		printk(MPT2SAS_ERR_FMT "doorbell handshake "  		   "int failed (line=%d)\n", ioc->name, __LINE__);  		return -EFAULT; @@ -2454,7 +2612,8 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,  	if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||  	    mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)  		ioc->ioc_link_reset_in_progress = 1; -	mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,  	    msecs_to_jiffies(10000));  	if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -2555,7 +2714,8 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,  	request = mpt2sas_base_get_msg_frame(ioc, smid);  	ioc->base_cmds.smid = smid;  	memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); -	mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,  	    msecs_to_jiffies(10000));  	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2701,13 +2861,12 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  /**   * _base_send_ioc_init - send ioc_init to firmware   * @ioc: per adapter object - * @VF_ID: virtual function id   * @sleep_flag: CAN_SLEEP or NO_SLEEP   *   * Returns 0 for success, non-zero for failure.   */  static int -_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2IOCInitRequest_t mpi_request;  	Mpi2IOCInitReply_t mpi_reply; @@ -2719,7 +2878,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)  	memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));  	mpi_request.Function = MPI2_FUNCTION_IOC_INIT;  	mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; -	mpi_request.VF_ID = VF_ID; +	mpi_request.VF_ID = 0; /* TODO */ +	mpi_request.VP_ID = 0;  	mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);  	mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); @@ -2795,13 +2955,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)  /**   * _base_send_port_enable - send port_enable(discovery stuff) to firmware   * @ioc: per adapter object - * @VF_ID: virtual function id   * @sleep_flag: CAN_SLEEP or NO_SLEEP   *   * Returns 0 for success, non-zero for failure.   */  static int -_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2PortEnableRequest_t *mpi_request;  	u32 ioc_state; @@ -2829,9 +2988,11 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)  	ioc->base_cmds.smid = smid;  	memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));  	mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; -	mpi_request->VF_ID = VF_ID; +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0; -	mpt2sas_base_put_smid_default(ioc, smid, VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,  	    300*HZ);  	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2892,13 +3053,12 @@ _base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)  /**   * _base_event_notification - send event notification   * @ioc: per adapter object - * @VF_ID: virtual function id   * @sleep_flag: CAN_SLEEP or NO_SLEEP   *   * Returns 0 for success, non-zero for failure.   */  static int -_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag) +_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	Mpi2EventNotificationRequest_t *mpi_request;  	unsigned long timeleft; @@ -2926,11 +3086,13 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)  	ioc->base_cmds.smid = smid;  	memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));  	mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; -	mpi_request->VF_ID = VF_ID; +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0;  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		mpi_request->EventMasks[i] =  		    le32_to_cpu(ioc->event_masks[i]); -	mpt2sas_base_put_smid_default(ioc, smid, VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->base_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);  	if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {  		printk(MPT2SAS_ERR_FMT "%s: timeout\n", @@ -2981,7 +3143,7 @@ mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)  		return;  	mutex_lock(&ioc->base_cmds.mutex); -	_base_event_notification(ioc, 0, CAN_SLEEP); +	_base_event_notification(ioc, CAN_SLEEP);  	mutex_unlock(&ioc->base_cmds.mutex);  } @@ -3006,7 +3168,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",  	    ioc->name)); -	writel(0, &ioc->chip->HostInterruptStatus);  	count = 0;  	do { @@ -3160,30 +3321,60 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  /**   * _base_make_ioc_operational - put controller in OPERATIONAL state   * @ioc: per adapter object - * @VF_ID: virtual function id   * @sleep_flag: CAN_SLEEP or NO_SLEEP   *   * Returns 0 for success, non-zero for failure.   */  static int -_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    int sleep_flag) +_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  {  	int r, i;  	unsigned long	flags;  	u32 reply_address; +	u16 smid; +	struct _tr_list *delayed_tr, *delayed_tr_next;  	dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,  	    __func__)); +	/* clean the delayed target reset list */ +	list_for_each_entry_safe(delayed_tr, delayed_tr_next, +	    &ioc->delayed_tr_list, list) { +		list_del(&delayed_tr->list); +		kfree(delayed_tr); +	} +  	/* initialize the scsi lookup free list */  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	INIT_LIST_HEAD(&ioc->free_list); -	for (i = 0; i < ioc->request_depth; i++) { +	smid = 1; +	for (i = 0; i < ioc->scsiio_depth; i++, smid++) {  		ioc->scsi_lookup[i].cb_idx = 0xFF; +		ioc->scsi_lookup[i].smid = smid; +		ioc->scsi_lookup[i].scmd = NULL;  		list_add_tail(&ioc->scsi_lookup[i].tracker_list,  		    &ioc->free_list);  	} + +	/* hi-priority queue */ +	INIT_LIST_HEAD(&ioc->hpr_free_list); +	smid = ioc->hi_priority_smid; +	for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { +		ioc->hpr_lookup[i].cb_idx = 0xFF; +		ioc->hpr_lookup[i].smid = smid; +		list_add_tail(&ioc->hpr_lookup[i].tracker_list, +		    &ioc->hpr_free_list); +	} + +	/* internal queue */ +	INIT_LIST_HEAD(&ioc->internal_free_list); +	smid = ioc->internal_smid; +	for (i = 0; i < ioc->internal_depth; i++, smid++) { +		ioc->internal_lookup[i].cb_idx = 0xFF; +		ioc->internal_lookup[i].smid = smid; +		list_add_tail(&ioc->internal_lookup[i].tracker_list, +		    &ioc->internal_free_list); +	}  	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);  	/* initialize Reply Free Queue */ @@ -3196,7 +3387,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	for (i = 0; i < ioc->reply_post_queue_depth; i++)  		ioc->reply_post_free[i].Words = ULLONG_MAX; -	r = _base_send_ioc_init(ioc, VF_ID, sleep_flag); +	r = _base_send_ioc_init(ioc, sleep_flag);  	if (r)  		return r; @@ -3207,14 +3398,14 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	writel(0, &ioc->chip->ReplyPostHostIndex);  	_base_unmask_interrupts(ioc); -	r = _base_event_notification(ioc, VF_ID, sleep_flag); +	r = _base_event_notification(ioc, sleep_flag);  	if (r)  		return r;  	if (sleep_flag == CAN_SLEEP)  		_base_static_config_pages(ioc); -	r = _base_send_port_enable(ioc, VF_ID, sleep_flag); +	r = _base_send_port_enable(ioc, sleep_flag);  	if (r)  		return r; @@ -3278,6 +3469,17 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	if (r)  		goto out_free_resources; +	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, +	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); +	if (!ioc->pfacts) +		goto out_free_resources; + +	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { +		r = _base_get_port_facts(ioc, i, CAN_SLEEP); +		if (r) +			goto out_free_resources; +	} +  	r = _base_allocate_memory_pools(ioc, CAN_SLEEP);  	if (r)  		goto out_free_resources; @@ -3286,7 +3488,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	/* base internal command bits */  	mutex_init(&ioc->base_cmds.mutex); -	init_completion(&ioc->base_cmds.done);  	ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->base_cmds.status = MPT2_CMD_NOT_USED; @@ -3294,7 +3495,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;  	mutex_init(&ioc->transport_cmds.mutex); -	init_completion(&ioc->transport_cmds.done);  	/* task management internal command bits */  	ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); @@ -3310,7 +3510,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);  	ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;  	mutex_init(&ioc->ctl_cmds.mutex); -	init_completion(&ioc->ctl_cmds.done);  	for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)  		ioc->event_masks[i] = -1; @@ -3327,18 +3526,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)  	_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);  	_base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);  	_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); - -	ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, -	    sizeof(Mpi2PortFactsReply_t), GFP_KERNEL); -	if (!ioc->pfacts) -		goto out_free_resources; - -	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { -		r = _base_get_port_facts(ioc, i, CAN_SLEEP); -		if (r) -			goto out_free_resources; -	} -	r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP); +	r = _base_make_ioc_operational(ioc, CAN_SLEEP);  	if (r)  		goto out_free_resources; @@ -3466,7 +3654,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)  	/* pending command count */  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	for (i = 0; i < ioc->request_depth; i++) +	for (i = 0; i < ioc->scsiio_depth; i++)  		if (ioc->scsi_lookup[i].cb_idx != 0xFF)  			ioc->pending_io_count++;  	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -3490,7 +3678,7 @@ int  mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,      enum reset_type type)  { -	int r, i; +	int r;  	unsigned long flags;  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, @@ -3513,9 +3701,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  	if (r)  		goto out;  	_base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); -	for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) -		r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID, -		    sleep_flag); +	r = _base_make_ioc_operational(ioc, sleep_flag);  	if (!r)  		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);   out: diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 2faab1e690e..0cf6bc236e4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -3,7 +3,7 @@   * for access to MPT (Message Passing Technology) firmware.   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.h - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -69,10 +69,10 @@  #define MPT2SAS_DRIVER_NAME		"mpt2sas"  #define MPT2SAS_AUTHOR	"LSI Corporation <DL-MPTFusionLinux@lsi.com>"  #define MPT2SAS_DESCRIPTION	"LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION		"01.100.06.00" -#define MPT2SAS_MAJOR_VERSION		01 +#define MPT2SAS_DRIVER_VERSION		"02.100.03.00" +#define MPT2SAS_MAJOR_VERSION		02  #define MPT2SAS_MINOR_VERSION		100 -#define MPT2SAS_BUILD_VERSION		06 +#define MPT2SAS_BUILD_VERSION		03  #define MPT2SAS_RELEASE_VERSION		00  /* @@ -264,6 +264,13 @@ struct _internal_cmd {   * SAS Topology Structures   */ +#define MPTSAS_STATE_TR_SEND		0x0001 +#define MPTSAS_STATE_TR_COMPLETE	0x0002 +#define MPTSAS_STATE_CNTRL_SEND		0x0004 +#define MPTSAS_STATE_CNTRL_COMPLETE	0x0008 + +#define MPT2SAS_REQ_SAS_CNTRL		0x0010 +  /**   * struct _sas_device - attached device information   * @list: sas device list @@ -300,6 +307,7 @@ struct _sas_device {  	u16	slot;  	u8	hidden_raid_component;  	u8	responding; +	u16	state;  };  /** @@ -436,6 +444,17 @@ struct request_tracker {  	struct list_head tracker_list;  }; +/** + * struct _tr_list - target reset list + * @handle: device handle + * @state: state machine + */ +struct _tr_list { +	struct list_head list; +	u16	handle; +	u16	state; +}; +  typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);  /** @@ -510,8 +529,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);   * @config_page_sz: config page size   * @config_page: reserve memory for config page payload   * @config_page_dma: + * @hba_queue_depth: hba request queue depth   * @sge_size: sg element size for either 32/64 bit - * @request_depth: hba request queue depth + * @scsiio_depth: SCSI_IO queue depth   * @request_sz: per request frame size   * @request: pool of request frames   * @request_dma: @@ -528,6 +548,18 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);   * @chains_needed_per_io: max chains per io   * @chain_offset_value_for_main_message: location 1st sg in main   * @chain_depth: total chains allocated + * @hi_priority_smid: + * @hi_priority: + * @hi_priority_dma: + * @hi_priority_depth: + * @hpr_lookup: + * @hpr_free_list: + * @internal_smid: + * @internal: + * @internal_dma: + * @internal_depth: + * @internal_lookup: + * @internal_free_list:   * @sense: pool of sense   * @sense_dma:   * @sense_dma_pool: @@ -597,6 +629,8 @@ struct MPT2SAS_ADAPTER {  	u8		ctl_cb_idx;  	u8		base_cb_idx;  	u8		config_cb_idx; +	u8		tm_tr_cb_idx; +	u8		tm_sas_control_cb_idx;  	struct _internal_cmd base_cmds;  	struct _internal_cmd transport_cmds;  	struct _internal_cmd tm_cmds; @@ -643,9 +677,10 @@ struct MPT2SAS_ADAPTER {  	void 		*config_page;  	dma_addr_t	config_page_dma; -	/* request */ +	/* scsiio request */ +	u16		hba_queue_depth;  	u16		sge_size; -	u16 		request_depth; +	u16 		scsiio_depth;  	u16		request_sz;  	u8		*request;  	dma_addr_t	request_dma; @@ -665,6 +700,22 @@ struct MPT2SAS_ADAPTER {  	u16		chain_offset_value_for_main_message;  	u16		chain_depth; +	/* hi-priority queue */ +	u16		hi_priority_smid; +	u8		*hi_priority; +	dma_addr_t	hi_priority_dma; +	u16		hi_priority_depth; +	struct request_tracker *hpr_lookup; +	struct list_head hpr_free_list; + +	/* internal queue */ +	u16		internal_smid; +	u8		*internal; +	dma_addr_t	internal_dma; +	u16		internal_depth; +	struct request_tracker *internal_lookup; +	struct list_head internal_free_list; +  	/* sense */  	u8		*sense;  	dma_addr_t	sense_dma; @@ -690,6 +741,8 @@ struct MPT2SAS_ADAPTER {  	struct dma_pool *reply_post_free_dma_pool;  	u32		reply_post_host_index; +	struct list_head delayed_tr_list; +  	/* diag buffer support */  	u8		*diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];  	u32		diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; @@ -701,7 +754,7 @@ struct MPT2SAS_ADAPTER {  	u32		diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];  }; -typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply); @@ -720,22 +773,28 @@ int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,  void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);  void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);  void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); -dma_addr_t mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid); -dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid); +dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, +    u16 smid); + +/* hi-priority queue */ +u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); +u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, +    struct scsi_cmnd *scmd);  u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);  void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id, +void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid,      u16 handle); -void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id); +void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid);  void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, -    u8 vf_id, u16 io_index); -void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id); +    u16 io_index); +void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid);  void mpt2sas_base_initialize_callback_handler(void);  u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);  void mpt2sas_base_release_callback_handler(u8 cb_idx); -void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply);  void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);  u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked); @@ -749,6 +808,8 @@ int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,  void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);  /* scsih shared API */ +u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +    u32 reply);  void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,      u8 type, u16 smid_task, ulong timeout);  void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); @@ -760,11 +821,11 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAP  struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(      struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);  void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);  /* config shared API */ -void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply);  int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);  int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,      Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); @@ -817,14 +878,17 @@ extern struct device_attribute *mpt2sas_host_attrs[];  extern struct device_attribute *mpt2sas_dev_attrs[];  void mpt2sas_ctl_init(void);  void mpt2sas_ctl_exit(void); -void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply);  void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); -void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply); +u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +    u32 reply);  void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,      Mpi2EventNotificationReply_t *mpi_reply);  /* transport shared API */ -void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply); +u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply);  struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,      u16 handle, u16 parent_handle);  void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, @@ -838,6 +902,8 @@ void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, u16 handle,  extern struct sas_function_template mpt2sas_transport_functions;  extern struct scsi_transport_template *mpt2sas_transport_template;  extern int scsi_internal_device_block(struct scsi_device *sdev); +extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc, +    u8 msix_index, u32 reply);  extern int scsi_internal_device_unblock(struct scsi_device *sdev);  #endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index ab8c560865d..594a389c652 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -2,7 +2,7 @@   * This module provides common API for accessing firmware configuration pages   *   * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -227,23 +227,25 @@ _config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,   * mpt2sas_config_done - config page completion routine   * @ioc: per adapter object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * Context: none.   *   * The callback handler when using _config_request.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply)  {  	MPI2DefaultReply_t *mpi_reply;  	if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) -		return; +		return 1;  	if (ioc->config_cmds.smid != smid) -		return; +		return 1;  	ioc->config_cmds.status |= MPT2_CMD_COMPLETE;  	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (mpi_reply) { @@ -257,6 +259,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)  #endif  	ioc->config_cmds.smid = USHORT_MAX;  	complete(&ioc->config_cmds.done); +	return 1;  }  /** @@ -303,6 +306,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t  	retry_count = 0;  	memset(&mem, 0, sizeof(struct config_request)); +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0; +  	if (config_page) {  		mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion;  		mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; @@ -380,7 +386,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t  	_config_display_some_debug(ioc, smid, "config_request", NULL);  #endif  	init_completion(&ioc->config_cmds.done); -	mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,  	    timeout*HZ);  	if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) { diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index c2a51018910..57d72463390 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -219,23 +219,25 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,   * mpt2sas_ctl_done - ctl module completion routine   * @ioc: per adapter object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * Context: none.   *   * The callback handler when using ioc->ctl_cb_idx.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +u8 +mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +	u32 reply)  {  	MPI2DefaultReply_t *mpi_reply;  	if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) -		return; +		return 1;  	if (ioc->ctl_cmds.smid != smid) -		return; +		return 1;  	ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (mpi_reply) { @@ -247,6 +249,7 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)  #endif  	ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;  	complete(&ioc->ctl_cmds.done); +	return 1;  }  /** @@ -328,22 +331,25 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,  /**   * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)   * @ioc: per adapter object - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * Context: interrupt.   *   * This function merely adds a new work task into ioc->firmware_event_thread.   * The tasks are worked from _firmware_event_work in user context.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +u8 +mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +	u32 reply)  {  	Mpi2EventNotificationReply_t *mpi_reply;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); +	return 1;  }  /** @@ -507,7 +513,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,  	handle = le16_to_cpu(tm_request->DevHandle);  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	for (i = ioc->request_depth; i && !found; i--) { +	for (i = ioc->scsiio_depth; i && !found; i--) {  		scmd = ioc->scsi_lookup[i - 1].scmd;  		if (scmd == NULL || scmd->device == NULL ||  		    scmd->device->hostdata == NULL) @@ -614,7 +620,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",  		    ioc->name, __func__); -	smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); +	smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); @@ -737,7 +743,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		    (u32)mpt2sas_base_get_sense_buffer_dma(ioc, smid);  		priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);  		memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); -		mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, +		mpt2sas_base_put_smid_scsi_io(ioc, smid,  		    le16_to_cpu(mpi_request->FunctionDependent1));  		break;  	} @@ -759,8 +765,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		mutex_lock(&ioc->tm_cmds.mutex);  		mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(  		    tm_request->DevHandle)); -		mpt2sas_base_put_smid_hi_priority(ioc, smid, -		    mpi_request->VF_ID); +		mpt2sas_base_put_smid_hi_priority(ioc, smid);  		break;  	}  	case MPI2_FUNCTION_SMP_PASSTHROUGH: @@ -781,7 +786,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  			ioc->ioc_link_reset_in_progress = 1;  			ioc->ignore_loginfos = 1;  		} -		mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +		mpt2sas_base_put_smid_default(ioc, smid);  		break;  	}  	case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: @@ -795,11 +800,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  			ioc->ioc_link_reset_in_progress = 1;  			ioc->ignore_loginfos = 1;  		} -		mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +		mpt2sas_base_put_smid_default(ioc, smid);  		break;  	}  	default: -		mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +		mpt2sas_base_put_smid_default(ioc, smid);  		break;  	} @@ -807,6 +812,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,  		timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;  	else  		timeout = karg.timeout; +	init_completion(&ioc->ctl_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    timeout*HZ);  	if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { @@ -1371,6 +1377,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)  	mpi_request->Flags = cpu_to_le32(karg.diagnostic_flags);  	mpi_request->BufferAddress = cpu_to_le64(request_data_dma);  	mpi_request->BufferLength = cpu_to_le32(request_data_sz); +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0;  	dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "  	    "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, @@ -1380,7 +1388,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)  		mpi_request->ProductSpecific[i] =  			cpu_to_le32(ioc->product_specific[buffer_type][i]); -	mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->ctl_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1643,8 +1652,11 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)  	mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;  	mpi_request->BufferType = buffer_type; +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0; -	mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->ctl_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1902,8 +1914,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)  	for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)  		mpi_request->ProductSpecific[i] =  			cpu_to_le32(ioc->product_specific[buffer_type][i]); +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0; -	mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->ctl_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,  	    MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2069,6 +2084,7 @@ static long  _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  {  	long ret; +  	lock_kernel();  	ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);  	unlock_kernel(); @@ -2143,6 +2159,7 @@ static long  _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)  {  	long ret; +  	lock_kernel();  	if (cmd == MPT2COMMAND32)  		ret = _ctl_compat_mpt_command(file, cmd, arg); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h index 4da11435533..211f296dd19 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h @@ -3,7 +3,7 @@   * controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h index ad325096e84..5308a25cb30 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h @@ -2,7 +2,7 @@   * Logging Support for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 774b34525bb..86ab32d7ab1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2,7 +2,7 @@   * Scsi Host Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -79,6 +79,9 @@ static u8 transport_cb_idx = -1;  static u8 config_cb_idx = -1;  static int mpt_ids; +static u8 tm_tr_cb_idx = -1 ; +static u8 tm_sas_control_cb_idx = -1; +  /* command line options */  static u32 logging_level;  MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " @@ -109,6 +112,7 @@ struct sense_info {   * @work: work object (ioc->fault_reset_work_q)   * @ioc: per adapter object   * @VF_ID: virtual function id + * @VP_ID: virtual port id   * @host_reset_handling: handling events during host reset   * @ignore: flag meaning this event has been marked to ignore   * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h @@ -121,6 +125,7 @@ struct fw_event_work {  	struct work_struct	work;  	struct MPT2SAS_ADAPTER *ioc;  	u8			VF_ID; +	u8			VP_ID;  	u8			host_reset_handling;  	u8			ignore;  	u16			event; @@ -138,8 +143,10 @@ struct fw_event_work {   * @lun: lun number   * @cdb_length: cdb length   * @cdb: cdb contents - * @valid_reply: flag set for reply message   * @timeout: timeout for this command + * @VF_ID: virtual function id + * @VP_ID: virtual port id + * @valid_reply: flag set for reply message   * @sense_length: sense length   * @ioc_status: ioc status   * @scsi_state: scsi state @@ -161,6 +168,8 @@ struct _scsi_io_transfer {  	u8	cdb_length;  	u8	cdb[32];  	u8	timeout; +	u8	VF_ID; +	u8	VP_ID;  	u8	valid_reply;    /* the following bits are only valid when 'valid_reply = 1' */  	u32	sense_length; @@ -756,66 +765,16 @@ _scsih_is_end_device(u32 device_info)  }  /** - * _scsih_scsi_lookup_get - returns scmd entry + * mptscsih_get_scsi_lookup - returns scmd entry   * @ioc: per adapter object   * @smid: system request message index - * Context: This function will acquire ioc->scsi_lookup_lock.   *   * Returns the smid stored scmd pointer.   */  static struct scsi_cmnd *  _scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)  { -	unsigned long	flags; -	struct scsi_cmnd *scmd; - -	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	scmd = ioc->scsi_lookup[smid - 1].scmd; -	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -	return scmd; -} - -/** - * mptscsih_getclear_scsi_lookup - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * Returns the smid stored scmd pointer, as well as clearing the scmd pointer. - */ -static struct scsi_cmnd * -_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ -	unsigned long	flags; -	struct scsi_cmnd *scmd; - -	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	scmd = ioc->scsi_lookup[smid - 1].scmd; -	ioc->scsi_lookup[smid - 1].scmd = NULL; -	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -	return scmd; -} - -/** - * _scsih_scsi_lookup_set - updates scmd entry in lookup - * @ioc: per adapter object - * @smid: system request message index - * @scmd: pointer to scsi command object - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will save scmd pointer in the scsi_lookup array. - * - * Return nothing. - */ -static void -_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, -    struct scsi_cmnd *scmd) -{ -	unsigned long	flags; - -	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); -	ioc->scsi_lookup[smid - 1].scmd = scmd; -	spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); +	return ioc->scsi_lookup[smid - 1].scmd;  }  /** @@ -838,9 +797,9 @@ _scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	smid = 0; -	for (i = 0; i < ioc->request_depth; i++) { +	for (i = 0; i < ioc->scsiio_depth; i++) {  		if (ioc->scsi_lookup[i].scmd == scmd) { -			smid = i + 1; +			smid = ioc->scsi_lookup[i].smid;  			goto out;  		}  	} @@ -869,7 +828,7 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	found = 0; -	for (i = 0 ; i < ioc->request_depth; i++) { +	for (i = 0 ; i < ioc->scsiio_depth; i++) {  		if (ioc->scsi_lookup[i].scmd &&  		    (ioc->scsi_lookup[i].scmd->device->id == id &&  		    ioc->scsi_lookup[i].scmd->device->channel == channel)) { @@ -903,7 +862,7 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,  	spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);  	found = 0; -	for (i = 0 ; i < ioc->request_depth; i++) { +	for (i = 0 ; i < ioc->scsiio_depth; i++) {  		if (ioc->scsi_lookup[i].scmd &&  		    (ioc->scsi_lookup[i].scmd->device->id == id &&  		    ioc->scsi_lookup[i].scmd->device->channel == channel && @@ -1113,7 +1072,7 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)  }  /** - * _scsih_change_queue_depth - changing device queue tag type + * _scsih_change_queue_type - changing device queue tag type   * @sdev: scsi device struct   * @tag_type: requested tag type   * @@ -1679,23 +1638,24 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)   * _scsih_tm_done - tm completion routine   * @ioc: per adapter object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * Context: none.   *   * The callback handler when using scsih_issue_tm.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -static void -_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +static u8 +_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  {  	MPI2DefaultReply_t *mpi_reply;  	if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) -		return; +		return 1;  	if (ioc->tm_cmds.smid != smid) -		return; +		return 1;  	ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;  	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (mpi_reply) { @@ -1704,6 +1664,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)  	}  	ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;  	complete(&ioc->tm_cmds.done); +	return 1;  }  /** @@ -1790,7 +1751,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  	u16 smid = 0;  	u32 ioc_state;  	unsigned long timeleft; -	u8 VF_ID = 0;  	if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {  		printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", @@ -1817,7 +1777,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  		goto issue_host_reset;  	} -	smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx); +	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); @@ -1825,7 +1785,8 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  	}  	dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," -	    " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid)); +	    " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, +	    smid_task));  	ioc->tm_cmds.status = MPT2_CMD_PENDING;  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);  	ioc->tm_cmds.smid = smid; @@ -1834,10 +1795,12 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,  	mpi_request->DevHandle = cpu_to_le16(handle);  	mpi_request->TaskType = type;  	mpi_request->TaskMID = cpu_to_le16(smid_task); +	mpi_request->VP_ID = 0;  /* TODO */ +	mpi_request->VF_ID = 0;  	int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);  	mpt2sas_scsih_set_tm_flag(ioc, handle);  	init_completion(&ioc->tm_cmds.done); -	mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID); +	mpt2sas_base_put_smid_hi_priority(ioc, smid);  	timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);  	mpt2sas_scsih_clear_tm_flag(ioc, handle);  	if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { @@ -2075,7 +2038,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd)  }  /** - * _scsih_abort - eh threads main host reset routine + * _scsih_host_reset - eh threads main host reset routine   * @sdev: scsi device struct   *   * Returns SUCCESS if command aborted else FAILED @@ -2354,6 +2317,231 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,  }  /** + * _scsih_tm_tr_send - send task management request + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt time. + * + * This code is to initiate the device removal handshake protocal + * with controller firmware.  This function will issue target reset + * using high priority request queue.  It will send a sas iounit + * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. + * + * This is designed to send muliple task management request at the same + * time to the fifo. If the fifo is full, we will append the request, + * and process it in a future completion. + */ +static void +_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ +	Mpi2SCSITaskManagementRequest_t *mpi_request; +	struct MPT2SAS_TARGET *sas_target_priv_data; +	u16 smid; +	struct _sas_device *sas_device; +	unsigned long flags; +	struct _tr_list *delayed_tr; + +	if (ioc->shost_recovery) { +		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", +		    __func__, ioc->name); +		return; +	} + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", +		    ioc->name, __func__); +		return; +	} +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	/* skip is hidden raid component */ +	if (sas_device->hidden_raid_component) +		return; + +	smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); +	if (!smid) { +		delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); +		if (!delayed_tr) +			return; +		INIT_LIST_HEAD(&delayed_tr->list); +		delayed_tr->handle = handle; +		delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL; +		list_add_tail(&delayed_tr->list, +		    &ioc->delayed_tr_list); +		if (sas_device->starget) +			dewtprintk(ioc, starget_printk(KERN_INFO, +			    sas_device->starget, "DELAYED:tr:handle(0x%04x), " +			    "(open)\n", sas_device->handle)); +		return; +	} + +	if (sas_device->starget && sas_device->starget->hostdata) { +		sas_target_priv_data = sas_device->starget->hostdata; +		sas_target_priv_data->tm_busy = 1; +		dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, +		    "tr:handle(0x%04x), (open)\n", sas_device->handle)); +	} + +	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); +	memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); +	mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; +	mpi_request->DevHandle = cpu_to_le16(handle); +	mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; +	sas_device->state |= MPTSAS_STATE_TR_SEND; +	sas_device->state |= MPT2SAS_REQ_SAS_CNTRL; +	mpt2sas_base_put_smid_hi_priority(ioc, smid); +} + + + +/** + * _scsih_sas_control_complete - completion routine + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * This is the sas iounit controll completion routine. + * This code is part of the code to initiate the device removal + * handshake protocal with controller firmware. + * + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function. + */ +static u8 +_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, +    u8 msix_index, u32 reply) +{ +	unsigned long flags; +	u16 handle; +	struct _sas_device *sas_device; +	Mpi2SasIoUnitControlReply_t *mpi_reply = +	    mpt2sas_base_get_reply_virt_addr(ioc, reply); + +	handle = le16_to_cpu(mpi_reply->DevHandle); + +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", +		    ioc->name, __func__); +		return 1; +	} +	sas_device->state |= MPTSAS_STATE_CNTRL_COMPLETE; +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (sas_device->starget) +		dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, +		    "sc_complete:handle(0x%04x), " +		    "ioc_status(0x%04x), loginfo(0x%08x)\n", +		    handle, le16_to_cpu(mpi_reply->IOCStatus), +		    le32_to_cpu(mpi_reply->IOCLogInfo))); +	return 1; +} + +/** + * _scsih_tm_tr_complete - + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * This is the target reset completion routine. + * This code is part of the code to initiate the device removal + * handshake protocal with controller firmware. + * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE) + * + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function. + */ +static u8 +_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, +    u32 reply) +{ +	unsigned long flags; +	u16 handle; +	struct _sas_device *sas_device; +	Mpi2SCSITaskManagementReply_t *mpi_reply = +	    mpt2sas_base_get_reply_virt_addr(ioc, reply); +	Mpi2SasIoUnitControlRequest_t *mpi_request; +	u16 smid_sas_ctrl; +	struct MPT2SAS_TARGET *sas_target_priv_data; +	struct _tr_list *delayed_tr; +	u8 rc; + +	handle = le16_to_cpu(mpi_reply->DevHandle); +	spin_lock_irqsave(&ioc->sas_device_lock, flags); +	sas_device = _scsih_sas_device_find_by_handle(ioc, handle); +	if (!sas_device) { +		spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +		printk(MPT2SAS_ERR_FMT "%s: failed finding sas_device\n", +		    ioc->name, __func__); +		return 1; +	} +	sas_device->state |= MPTSAS_STATE_TR_COMPLETE; +	spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + +	if (sas_device->starget) +		dewtprintk(ioc, starget_printk(KERN_INFO, sas_device->starget, +		    "tr_complete:handle(0x%04x), (%s) ioc_status(0x%04x), " +		    "loginfo(0x%08x), completed(%d)\n", +		    sas_device->handle, (sas_device->state & +		    MPT2SAS_REQ_SAS_CNTRL) ? "open" : "active", +		    le16_to_cpu(mpi_reply->IOCStatus), +		    le32_to_cpu(mpi_reply->IOCLogInfo), +		    le32_to_cpu(mpi_reply->TerminationCount))); + +	if (sas_device->starget && sas_device->starget->hostdata) { +		sas_target_priv_data = sas_device->starget->hostdata; +		sas_target_priv_data->tm_busy = 0; +	} + +	if (!list_empty(&ioc->delayed_tr_list)) { +		delayed_tr = list_entry(ioc->delayed_tr_list.next, +		    struct _tr_list, list); +		mpt2sas_base_free_smid(ioc, smid); +		if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL) +			_scsih_tm_tr_send(ioc, delayed_tr->handle); +		list_del(&delayed_tr->list); +		kfree(delayed_tr); +		rc = 0; /* tells base_interrupt not to free mf */ +	} else +		rc = 1; + + +	if (!(sas_device->state & MPT2SAS_REQ_SAS_CNTRL)) +		return rc; + +	if (ioc->shost_recovery) { +		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", +		    __func__, ioc->name); +		return rc; +	} + +	smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); +	if (!smid_sas_ctrl) { +		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", +		    ioc->name, __func__); +		return rc; +	} + +	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); +	memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); +	mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; +	mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; +	mpi_request->DevHandle = mpi_reply->DevHandle; +	sas_device->state |= MPTSAS_STATE_CNTRL_SEND; +	mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); +	return rc; +} + +/**   * _scsih_check_topo_delete_events - sanity check on topo events   * @ioc: per adapter object   * @event_data: the event data payload @@ -2375,6 +2563,21 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,  	u16 expander_handle;  	struct _sas_node *sas_expander;  	unsigned long flags; +	int i, reason_code; +	u16 handle; + +	for (i = 0 ; i < event_data->NumEntries; i++) { +		if (event_data->PHY[i].PhyStatus & +		    MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) +			continue; +		handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); +		if (!handle) +			continue; +		reason_code = event_data->PHY[i].PhyStatus & +		    MPI2_EVENT_SAS_TOPO_RC_MASK; +		if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) +			_scsih_tm_tr_send(ioc, handle); +	}  	expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);  	if (expander_handle < ioc->sas_hba.num_phys) { @@ -2433,8 +2636,8 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)  	u16 smid;  	u16 count = 0; -	for (smid = 1; smid <= ioc->request_depth; smid++) { -		scmd = _scsih_scsi_lookup_getclear(ioc, smid); +	for (smid = 1; smid <= ioc->scsiio_depth; smid++) { +		scmd = _scsih_scsi_lookup_get(ioc, smid);  		if (!scmd)  			continue;  		count++; @@ -2616,7 +2819,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  	if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))  		mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; -	smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx); +	smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);  	if (!smid) {  		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",  		    ioc->name, __func__); @@ -2643,7 +2846,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  	mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;  	mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +  	    MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); - +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0;  	int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)  	    mpi_request->LUN);  	memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); @@ -2657,8 +2861,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))  		}  	} -	_scsih_scsi_lookup_set(ioc, smid, scmd); -	mpt2sas_base_put_smid_scsi_io(ioc, smid, 0, +	mpt2sas_base_put_smid_scsi_io(ioc, smid,  	    sas_device_priv_data->sas_target->handle);  	return 0; @@ -2954,15 +3157,16 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)   * _scsih_io_done - scsi request callback   * @ioc: per adapter object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * - * Callback handler when using scsih_qcmd. + * Callback handler when using _scsih_qcmd.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -static void -_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply) +static u8 +_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)  {  	Mpi2SCSIIORequest_t *mpi_request;  	Mpi2SCSIIOReply_t *mpi_reply; @@ -2976,9 +3180,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)  	u32 response_code;  	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); -	scmd = _scsih_scsi_lookup_getclear(ioc, smid); +	scmd = _scsih_scsi_lookup_get(ioc, smid);  	if (scmd == NULL) -		return; +		return 1;  	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); @@ -3134,6 +3338,7 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)   out:  	scsi_dma_unmap(scmd);  	scmd->scsi_done(scmd); +	return 1;  }  /** @@ -3398,9 +3603,8 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)  		}  	} -	sas_address = le64_to_cpu(expander_pg0.SASAddress); -  	spin_lock_irqsave(&ioc->sas_node_lock, flags); +	sas_address = le64_to_cpu(expander_pg0.SASAddress);  	sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,  	    sas_address);  	spin_unlock_irqrestore(&ioc->sas_node_lock, flags); @@ -3666,6 +3870,12 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	if (ioc->remove_host)  		goto out; +	if ((sas_device->state & MPTSAS_STATE_TR_COMPLETE)) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " +		   "target_reset handle(0x%04x)\n", ioc->name, handle)); +		goto skip_tr; +	} +  	/* Target Reset to flush out all the outstanding IO */  	device_handle = (sas_device->hidden_raid_component) ?  	    sas_device->volume_handle : handle; @@ -3682,6 +3892,13 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)  		if (ioc->shost_recovery)  			goto out;  	} + skip_tr: + +	if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) { +		dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip " +		   "sas_cntrl handle(0x%04x)\n", ioc->name, handle)); +		goto out; +	}  	/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */  	dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" @@ -3690,7 +3907,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)  	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;  	mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;  	mpi_request.DevHandle = handle; -	mpi_request.VF_ID = 0; +	mpi_request.VF_ID = 0; /* TODO */ +	mpi_request.VP_ID = 0;  	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,  	    &mpi_request)) != 0) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -3800,15 +4018,12 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,  /**   * _scsih_sas_topology_change_event - handle topology changes   * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload - * fw_event: + * @fw_event: The fw_event_work object   * Context: user.   *   */  static void -_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataSasTopologyChangeList_t *event_data, +_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,      struct fw_event_work *fw_event)  {  	int i; @@ -3818,6 +4033,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	struct _sas_node *sas_expander;  	unsigned long flags;  	u8 link_rate_; +	Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) @@ -3851,15 +4067,16 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  		}  		if (ioc->shost_recovery)  			return; -		if (event_data->PHY[i].PhyStatus & -		    MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) +		phy_number = event_data->StartPhyNum + i; +		reason_code = event_data->PHY[i].PhyStatus & +		    MPI2_EVENT_SAS_TOPO_RC_MASK; +		if ((event_data->PHY[i].PhyStatus & +		    MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != +		    MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))  			continue;  		handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);  		if (!handle)  			continue; -		phy_number = event_data->StartPhyNum + i; -		reason_code = event_data->PHY[i].PhyStatus & -		    MPI2_EVENT_SAS_TOPO_RC_MASK;  		link_rate_ = event_data->PHY[i].LinkRate >> 4;  		switch (reason_code) {  		case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: @@ -3971,19 +4188,19 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,  /**   * _scsih_sas_device_status_change_event - handle device status change   * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataSasDeviceStatusChange_t *event_data) +_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -		_scsih_sas_device_status_change_event_debug(ioc, event_data); +		_scsih_sas_device_status_change_event_debug(ioc, +		     fw_event->event_data);  #endif  } @@ -4026,34 +4243,33 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,  /**   * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events   * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void  _scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, -    u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data) +    struct fw_event_work *fw_event)  {  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)  		_scsih_sas_enclosure_dev_status_change_event_debug(ioc, -		     event_data); +		     fw_event->event_data);  #endif  }  /**   * _scsih_sas_broadcast_primative_event - handle broadcast events   * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataSasBroadcastPrimitive_t *event_data) +_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  	struct scsi_cmnd *scmd;  	u16 smid, handle; @@ -4062,11 +4278,12 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	u32 termination_count;  	u32 query_count;  	Mpi2SCSITaskManagementReply_t *mpi_reply; - +#ifdef CONFIG_SCSI_MPT2SAS_LOGGING +	Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; +#endif  	dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "  	    "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,  	    event_data->PortWidth)); -  	dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,  	    __func__)); @@ -4074,7 +4291,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	termination_count = 0;  	query_count = 0;  	mpi_reply = ioc->tm_cmds.reply; -	for (smid = 1; smid <= ioc->request_depth; smid++) { +	for (smid = 1; smid <= ioc->scsiio_depth; smid++) {  		scmd = _scsih_scsi_lookup_get(ioc, smid);  		if (!scmd)  			continue; @@ -4121,23 +4338,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  /**   * _scsih_sas_discovery_event - handle discovery events   * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataSasDiscovery_t *event_data) +_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  { +	Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data; +  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {  		printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,  		    (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?  		    "start" : "stop");  	if (event_data->DiscoveryStatus) -		printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)", -		    ioc->name, le32_to_cpu(event_data->DiscoveryStatus)); +		printk("discovery_status(0x%08x)", +		    le32_to_cpu(event_data->DiscoveryStatus));  	printk("\n");  	}  #endif @@ -4488,19 +4707,19 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,  /**   * _scsih_sas_ir_config_change_event - handle ir configuration change events   * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataIrConfigChangeList_t *event_data) +_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  	Mpi2EventIrConfigElement_t *element;  	int i;  	u8 foreign_config; +	Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) @@ -4543,14 +4762,14 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  /**   * _scsih_sas_ir_volume_event - IR volume event   * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataIrVolume_t *event_data) +_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  	u64 wwid;  	unsigned long flags; @@ -4559,6 +4778,7 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	u32 state;  	int rc;  	struct MPT2SAS_TARGET *sas_target_priv_data; +	Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;  	if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)  		return; @@ -4628,14 +4848,14 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  /**   * _scsih_sas_ir_physical_disk_event - PD event   * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -   Mpi2EventDataIrPhysicalDisk_t *event_data) +_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  	u16 handle;  	u32 state; @@ -4644,6 +4864,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	Mpi2ConfigReply_t mpi_reply;  	Mpi2SasDevicePage0_t sas_device_pg0;  	u32 ioc_status; +	Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data;  	if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)  		return; @@ -4743,33 +4964,33 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,  /**   * _scsih_sas_ir_operation_status_event - handle RAID operation events   * @ioc: per adapter object - * @VF_ID: - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Return nothing.   */  static void -_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataIrOperationStatus_t *event_data) +_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, +    struct fw_event_work *fw_event)  {  #ifdef CONFIG_SCSI_MPT2SAS_LOGGING  	if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) -		_scsih_sas_ir_operation_status_event_debug(ioc, event_data); +		_scsih_sas_ir_operation_status_event_debug(ioc, +		     fw_event->event_data);  #endif  }  /**   * _scsih_task_set_full - handle task set full   * @ioc: per adapter object - * @event_data: event data payload + * @fw_event: The fw_event_work object   * Context: user.   *   * Throttle back qdepth.   */  static void -_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, -    Mpi2EventDataTaskSetFull_t *event_data) +_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work +	*fw_event)  {  	unsigned long flags;  	struct _sas_device *sas_device; @@ -4780,6 +5001,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,  	u16 handle;  	int id, channel;  	u64 sas_address; +	Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;  	current_depth = le16_to_cpu(event_data->CurrentDepth);  	handle = le16_to_cpu(event_data->DevHandle); @@ -4868,6 +5090,10 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  		if (sas_device->sas_address == sas_address &&  		    sas_device->slot == slot && sas_device->starget) {  			sas_device->responding = 1; +			sas_device->state = 0; +			starget = sas_device->starget; +			sas_target_priv_data = starget->hostdata; +			sas_target_priv_data->tm_busy = 0;  			starget_printk(KERN_INFO, sas_device->starget,  			    "handle(0x%04x), sas_addr(0x%016llx), enclosure "  			    "logical id(0x%016llx), slot(%d)\n", handle, @@ -4880,8 +5106,6 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,  			printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",  			    sas_device->handle);  			sas_device->handle = handle; -			starget = sas_device->starget; -			sas_target_priv_data = starget->hostdata;  			sas_target_priv_data->handle = handle;  			goto out;  		} @@ -5227,44 +5451,38 @@ _firmware_event_work(struct work_struct *work)  	switch (fw_event->event) {  	case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: -		_scsih_sas_topology_change_event(ioc, fw_event->VF_ID, -		    fw_event->event_data, fw_event); +		_scsih_sas_topology_change_event(ioc, fw_event);  		break;  	case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: -		_scsih_sas_device_status_change_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_device_status_change_event(ioc, +		    fw_event);  		break;  	case MPI2_EVENT_SAS_DISCOVERY: -		_scsih_sas_discovery_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_discovery_event(ioc, +		    fw_event);  		break;  	case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: -		_scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_broadcast_primative_event(ioc, +		    fw_event);  		break;  	case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:  		_scsih_sas_enclosure_dev_status_change_event(ioc, -		    fw_event->VF_ID, fw_event->event_data); +		    fw_event);  		break;  	case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: -		_scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_ir_config_change_event(ioc, fw_event);  		break;  	case MPI2_EVENT_IR_VOLUME: -		_scsih_sas_ir_volume_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_ir_volume_event(ioc, fw_event);  		break;  	case MPI2_EVENT_IR_PHYSICAL_DISK: -		_scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_ir_physical_disk_event(ioc, fw_event);  		break;  	case MPI2_EVENT_IR_OPERATION_STATUS: -		_scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_sas_ir_operation_status_event(ioc, fw_event);  		break;  	case MPI2_EVENT_TASK_SET_FULL: -		_scsih_task_set_full(ioc, fw_event->VF_ID, -		    fw_event->event_data); +		_scsih_task_set_full(ioc, fw_event);  		break;  	}  	_scsih_fw_event_free(ioc, fw_event); @@ -5273,17 +5491,19 @@ _firmware_event_work(struct work_struct *work)  /**   * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)   * @ioc: per adapter object - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   * Context: interrupt.   *   * This function merely adds a new work task into ioc->firmware_event_thread.   * The tasks are worked from _firmware_event_work in user context.   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply) +u8 +mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, +	u32 reply)  {  	struct fw_event_work *fw_event;  	Mpi2EventNotificationReply_t *mpi_reply; @@ -5294,11 +5514,11 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  	spin_lock_irqsave(&ioc->fw_event_lock, flags);  	if (ioc->fw_events_off || ioc->remove_host) {  		spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -		return; +		return 1;  	}  	spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply); +	mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);  	event = le16_to_cpu(mpi_reply->Event);  	switch (event) { @@ -5312,7 +5532,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  		if (baen_data->Primitive !=  		    MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||  		    ioc->broadcast_aen_busy) -			return; +			return 1;  		ioc->broadcast_aen_busy = 1;  		break;  	} @@ -5334,14 +5554,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  		break;  	default: /* ignore the rest */ -		return; +		return 1;  	}  	fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);  	if (!fw_event) {  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__); -		return; +		return 1;  	}  	fw_event->event_data =  	    kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC); @@ -5349,15 +5569,17 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)  		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",  		    ioc->name, __FILE__, __LINE__, __func__);  		kfree(fw_event); -		return; +		return 1;  	}  	memcpy(fw_event->event_data, mpi_reply->EventData,  	    mpi_reply->EventDataLength*4);  	fw_event->ioc = ioc; -	fw_event->VF_ID = VF_ID; +	fw_event->VF_ID = mpi_reply->VF_ID; +	fw_event->VP_ID = mpi_reply->VP_ID;  	fw_event->event = event;  	_scsih_fw_event_add(ioc, fw_event); +	return 1;  }  /* shost template */ @@ -5617,7 +5839,7 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)  }  /** - * _scsih_probe_sas - reporting raid volumes to sas transport + * _scsih_probe_sas - reporting sas devices to sas transport   * @ioc: per adapter object   *   * Called during initial loading of the driver. @@ -5714,6 +5936,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	ioc->base_cb_idx = base_cb_idx;  	ioc->transport_cb_idx = transport_cb_idx;  	ioc->config_cb_idx = config_cb_idx; +	ioc->tm_tr_cb_idx = tm_tr_cb_idx; +	ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;  	ioc->logging_level = logging_level;  	/* misc semaphores and spin locks */  	spin_lock_init(&ioc->ioc_reset_in_progress_lock); @@ -5729,6 +5953,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	INIT_LIST_HEAD(&ioc->fw_event_list);  	INIT_LIST_HEAD(&ioc->raid_device_list);  	INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); +	INIT_LIST_HEAD(&ioc->delayed_tr_list);  	/* init shost parameters */  	shost->max_cmd_len = 16; @@ -5745,6 +5970,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)  	scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION  	    | SHOST_DIF_TYPE3_PROTECTION); +	scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);  	/* event thread */  	snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), @@ -5894,6 +6120,11 @@ _scsih_init(void)  	/* ctl module callback handler */  	ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); +	tm_tr_cb_idx = mpt2sas_base_register_callback_handler( +	    _scsih_tm_tr_complete); +	tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( +	    _scsih_sas_control_complete); +  	mpt2sas_ctl_init();  	error = pci_register_driver(&scsih_driver); @@ -5924,6 +6155,9 @@ _scsih_exit(void)  	mpt2sas_base_release_callback_handler(config_cb_idx);  	mpt2sas_base_release_callback_handler(ctl_cb_idx); +	mpt2sas_base_release_callback_handler(tm_tr_cb_idx); +	mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); +  	mpt2sas_ctl_exit();  } diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 742324a0a11..eb98188c7f3 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -2,7 +2,7 @@   * SAS Transport Layer for MPT (Message Passing Technology) based controllers   *   * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2008  LSI Corporation + * Copyright (C) 2007-2009  LSI Corporation   *  (mailto:DL-MPTFusionLinux@lsi.com)   *   * This program is free software; you can redistribute it and/or @@ -212,25 +212,26 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,   * mpt2sas_transport_done -  internal transport layer callback handler.   * @ioc: per adapter object   * @smid: system request message index - * @VF_ID: virtual function id + * @msix_index: MSIX table index supplied by the OS   * @reply: reply message frame(lower 32bit addr)   *   * Callback handler when sending internal generated transport cmds.   * The callback index passed is `ioc->transport_cb_idx`   * - * Return nothing. + * Return 1 meaning mf should be freed from _base_interrupt + *        0 means the mf is freed from this function.   */ -void -mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, +u8 +mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,      u32 reply)  {  	MPI2DefaultReply_t *mpi_reply;  	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);  	if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED) -		return; +		return 1;  	if (ioc->transport_cmds.smid != smid) -		return; +		return 1;  	ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;  	if (mpi_reply) {  		memcpy(ioc->transport_cmds.reply, mpi_reply, @@ -239,6 +240,7 @@ mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,  	}  	ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;  	complete(&ioc->transport_cmds.done); +	return 1;  }  /* report manufacture request structure */ @@ -369,6 +371,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;  	mpi_request->PhysicalPort = 0xFF; +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0;  	sas_address_le = (u64 *)&mpi_request->SASAddress;  	*sas_address_le = cpu_to_le64(sas_address);  	mpi_request->RequestDataLength = sizeof(struct rep_manu_request); @@ -396,7 +400,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,  	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "  	    "send to sas_addr(0x%016llx)\n", ioc->name,  	    (unsigned long long)sas_address)); -	mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->transport_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); @@ -1106,6 +1111,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));  	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;  	mpi_request->PhysicalPort = 0xFF; +	mpi_request->VF_ID = 0; /* TODO */ +	mpi_request->VP_ID = 0;  	*((u64 *)&mpi_request->SASAddress) = (rphy) ?  	    cpu_to_le64(rphy->identify.sas_address) :  	    cpu_to_le64(ioc->sas_hba.sas_address); @@ -1147,7 +1154,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,  	dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "  	    "sending smp request\n", ioc->name, __func__)); -	mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */); +	mpt2sas_base_put_smid_default(ioc, smid); +	init_completion(&ioc->transport_cmds.done);  	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,  	    10*HZ); diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h index f8cb9defb96..1849da1f030 100644 --- a/drivers/scsi/mvsas/mv_defs.h +++ b/drivers/scsi/mvsas/mv_defs.h @@ -25,6 +25,8 @@  #ifndef _MV_DEFS_H_  #define _MV_DEFS_H_ +#define PCI_DEVICE_ID_ARECA_1300	0x1300 +#define PCI_DEVICE_ID_ARECA_1320	0x1320  enum chip_flavors {  	chip_6320, @@ -32,6 +34,8 @@ enum chip_flavors {  	chip_6485,  	chip_9480,  	chip_9180, +	chip_1300, +	chip_1320  };  /* driver compile-time configuration */ diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 8646a19f999..c790d45876c 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -32,6 +32,8 @@ static const struct mvs_chip_info mvs_chips[] = {  	[chip_6485] =	{ 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },  	[chip_9180] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },  	[chip_9480] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, }, +	[chip_1300] =	{ 1, 4, 0x400, 17, 16,  9, &mvs_64xx_dispatch, }, +	[chip_1320] =	{ 2, 4, 0x800, 17, 64,  9, &mvs_94xx_dispatch, },  };  #define SOC_SAS_NUM 2 @@ -653,6 +655,8 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = {  	{ PCI_VDEVICE(MARVELL, 0x6485), chip_6485 },  	{ PCI_VDEVICE(MARVELL, 0x9480), chip_9480 },  	{ PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, +	{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, +	{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 },  	{ }	/* terminate list */  }; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 4302f06e4ec..f7c70e2a822 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -46,6 +46,7 @@  #include <linux/mutex.h>  #include <scsi/scsi.h>  #include <scsi/scsi_host.h> +#include <scsi/scsi_device.h>  #include <scsi/scsi_tcq.h>  #include <scsi/scsi_eh.h>  #include <scsi/scsi_cmnd.h> @@ -684,7 +685,7 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)  	struct pmcraid_instance *pinstance = cmd->drv_inst;  	unsigned long lock_flags; -	dev_err(&pinstance->pdev->dev, +	dev_info(&pinstance->pdev->dev,  		"Adapter being reset due to command timeout.\n");  	/* Command timeouts result in hard reset sequence. The command that got @@ -815,8 +816,9 @@ static void pmcraid_erp_done(struct pmcraid_cmd *cmd)  	if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) {  		scsi_cmd->result |= (DID_ERROR << 16); -		pmcraid_err("command CDB[0] = %x failed with IOASC: 0x%08X\n", -			     cmd->ioa_cb->ioarcb.cdb[0], ioasc); +		scmd_printk(KERN_INFO, scsi_cmd, +			    "command CDB[0] = %x failed with IOASC: 0x%08X\n", +			    cmd->ioa_cb->ioarcb.cdb[0], ioasc);  	}  	/* if we had allocated sense buffers for request sense, copy the sense @@ -1541,13 +1543,13 @@ static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance)  	if (pinstance->ldn.hcam->notification_lost ==  	    HOSTRCB_NOTIFICATIONS_LOST) -		dev_err(&pinstance->pdev->dev, "Error notifications lost\n"); +		dev_info(&pinstance->pdev->dev, "Error notifications lost\n");  	ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc);  	if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET ||  		ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { -		dev_err(&pinstance->pdev->dev, +		dev_info(&pinstance->pdev->dev,  			"UnitAttention due to IOA Bus Reset\n");  		scsi_report_bus_reset(  			pinstance->host, @@ -1584,7 +1586,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd)  	    atomic_read(&pinstance->ccn.ignore) == 1) {  		return;  	} else if (ioasc) { -		dev_err(&pinstance->pdev->dev, +		dev_info(&pinstance->pdev->dev,  			"Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc);  		spin_lock_irqsave(pinstance->host->host_lock, lock_flags);  		pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); @@ -1634,7 +1636,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)  			return;  		}  	} else { -		dev_err(&pinstance->pdev->dev, +		dev_info(&pinstance->pdev->dev,  			"Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc);  	}  	/* send netlink message for HCAM notification if enabled */ @@ -1822,7 +1824,6 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance)  			scsi_dma_unmap(scsi_cmd);  			pmcraid_return_cmd(cmd); -  			pmcraid_info("failing(%d) CDB[0] = %x result: %x\n",  				     le32_to_cpu(resp) >> 2,  				     cmd->ioa_cb->ioarcb.cdb[0], @@ -2514,7 +2515,8 @@ static int pmcraid_reset_device(  	res = scsi_cmd->device->hostdata;  	if (!res) { -		pmcraid_err("reset_device: NULL resource pointer\n"); +		sdev_printk(KERN_ERR, scsi_cmd->device, +			    "reset_device: NULL resource pointer\n");  		return FAILED;  	} @@ -2752,8 +2754,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)  	pinstance =  		(struct pmcraid_instance *)scsi_cmd->device->host->hostdata; -	dev_err(&pinstance->pdev->dev, -		"I/O command timed out, aborting it.\n"); +	scmd_printk(KERN_INFO, scsi_cmd, +		    "I/O command timed out, aborting it.\n");  	res = scsi_cmd->device->hostdata; @@ -2824,7 +2826,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)   */  static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)  { -	pmcraid_err("Doing device reset due to an I/O command timeout.\n"); +	scmd_printk(KERN_INFO, scmd, +		    "resetting device due to an I/O command timeout.\n");  	return pmcraid_reset_device(scmd,  				    PMCRAID_INTERNAL_TIMEOUT,  				    RESET_DEVICE_LUN); @@ -2832,7 +2835,8 @@ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)  static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)  { -	pmcraid_err("Doing bus reset due to an I/O command timeout.\n"); +	scmd_printk(KERN_INFO, scmd, +		    "Doing bus reset due to an I/O command timeout.\n");  	return pmcraid_reset_device(scmd,  				    PMCRAID_RESET_BUS_TIMEOUT,  				    RESET_DEVICE_BUS); @@ -2840,7 +2844,8 @@ static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)  static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)  { -	pmcraid_err("Doing target reset due to an I/O command timeout.\n"); +	scmd_printk(KERN_INFO, scmd, +		    "Doing target reset due to an I/O command timeout.\n");  	return pmcraid_reset_device(scmd,  				    PMCRAID_INTERNAL_TIMEOUT,  				    RESET_DEVICE_TARGET); @@ -2988,11 +2993,11 @@ static int pmcraid_build_ioadl(  	nseg = scsi_dma_map(scsi_cmd);  	if (nseg < 0) { -		dev_err(&pinstance->pdev->dev, "scsi_map_dma failed!\n"); +		scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n");  		return -1;  	} else if (nseg > PMCRAID_MAX_IOADLS) {  		scsi_dma_unmap(scsi_cmd); -		dev_err(&pinstance->pdev->dev, +		scmd_printk(KERN_ERR, scsi_cmd,  			"sg count is (%d) more than allowed!\n", nseg);  		return -1;  	} @@ -5040,7 +5045,7 @@ static int pmcraid_resume(struct pci_dev *pdev)  	rc = pci_enable_device(pdev);  	if (rc) { -		pmcraid_err("pmcraid: Enable device failed\n"); +		dev_err(&pdev->dev, "resume: Enable device failed\n");  		return rc;  	} @@ -5054,7 +5059,7 @@ static int pmcraid_resume(struct pci_dev *pdev)  		rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));  	if (rc != 0) { -		dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); +		dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n");  		goto disable_device;  	} @@ -5063,7 +5068,8 @@ static int pmcraid_resume(struct pci_dev *pdev)  	rc = pmcraid_register_interrupt_handler(pinstance);  	if (rc) { -		pmcraid_err("resume: couldn't register interrupt handlers\n"); +		dev_err(&pdev->dev, +			"resume: couldn't register interrupt handlers\n");  		rc = -ENODEV;  		goto release_host;  	} @@ -5080,7 +5086,7 @@ static int pmcraid_resume(struct pci_dev *pdev)  	 * state.  	 */  	if (pmcraid_reset_bringup(pinstance)) { -		pmcraid_err("couldn't initialize IOA \n"); +		dev_err(&pdev->dev, "couldn't initialize IOA \n");  		rc = -ENODEV;  		goto release_tasklets;  	} @@ -5187,7 +5193,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)  	LIST_HEAD(old_res);  	if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) -		dev_err(&pinstance->pdev->dev, "Require microcode download\n"); +		pmcraid_err("IOA requires microcode download\n");  	/* resource list is protected by pinstance->resource_lock.  	 * init_res_table can be called from probe (user-thread) or runtime @@ -5224,8 +5230,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)  		if (!found) {  			if (list_empty(&pinstance->free_res_q)) { -				dev_err(&pinstance->pdev->dev, -					"Too many devices attached\n"); +				pmcraid_err("Too many devices attached\n");  				break;  			} @@ -5442,7 +5447,7 @@ static int __devinit pmcraid_probe(  	rc = pmcraid_register_interrupt_handler(pinstance);  	if (rc) { -		pmcraid_err("couldn't register interrupt handler\n"); +		dev_err(&pdev->dev, "couldn't register interrupt handler\n");  		goto out_scsi_host_put;  	} @@ -5466,7 +5471,7 @@ static int __devinit pmcraid_probe(  	 */  	pmcraid_info("starting IOA initialization sequence\n");  	if (pmcraid_reset_bringup(pinstance)) { -		pmcraid_err("couldn't initialize IOA \n"); +		dev_err(&pdev->dev, "couldn't initialize IOA \n");  		rc = 1;  		goto out_release_bufs;  	} @@ -5534,7 +5539,6 @@ static struct pci_driver pmcraid_driver = {  	.shutdown = pmcraid_shutdown  }; -  /**   * pmcraid_init - module load entry point   */ @@ -5566,7 +5570,6 @@ static int __init pmcraid_init(void)  		goto out_unreg_chrdev;  	} -  	error = pmcraid_netlink_init();  	if (error) @@ -5584,6 +5587,7 @@ static int __init pmcraid_init(void)  out_unreg_chrdev:  	unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); +  out_init:  	return error;  } diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 42b799abba5..e07b3617f01 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -568,7 +568,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,  	if (req == NULL) {  		qla_printk(KERN_WARNING, ha, "could not allocate memory"  			"for request que\n"); -		goto que_failed; +		goto failed;  	}  	req->length = REQUEST_ENTRY_CNT_24XX; @@ -632,6 +632,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,  que_failed:  	qla25xx_free_req_que(base_vha, req); +failed:  	return 0;  } @@ -659,7 +660,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,  	if (rsp == NULL) {  		qla_printk(KERN_WARNING, ha, "could not allocate memory for"  				" response que\n"); -		goto que_failed; +		goto failed;  	}  	rsp->length = RESPONSE_ENTRY_CNT_MQ; @@ -728,6 +729,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,  que_failed:  	qla25xx_free_rsp_que(base_vha, rsp); +failed:  	return 0;  } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index b6e03074cb8..dd098cad337 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -241,10 +241,7 @@ scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)   */  struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)  { -	struct scsi_cmnd *cmd; -	unsigned char *buf; - -	cmd = scsi_host_alloc_command(shost, gfp_mask); +	struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);  	if (unlikely(!cmd)) {  		unsigned long flags; @@ -258,9 +255,15 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)  		spin_unlock_irqrestore(&shost->free_list_lock, flags);  		if (cmd) { +			void *buf, *prot; +  			buf = cmd->sense_buffer; +			prot = cmd->prot_sdb; +  			memset(cmd, 0, sizeof(*cmd)); +  			cmd->sense_buffer = buf; +			cmd->prot_sdb = prot;  		}  	} diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index fb9af207d61..c4103bef41b 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -50,6 +50,7 @@  #include <scsi/scsi_host.h>  #include <scsi/scsicam.h>  #include <scsi/scsi_eh.h> +#include <scsi/scsi_dbg.h>  #include "sd.h"  #include "scsi_logging.h" @@ -64,6 +65,7 @@ static const char * scsi_debug_version_date = "20070104";  #define PARAMETER_LIST_LENGTH_ERR 0x1a  #define INVALID_OPCODE 0x20  #define ADDR_OUT_OF_RANGE 0x21 +#define INVALID_COMMAND_OPCODE 0x20  #define INVALID_FIELD_IN_CDB 0x24  #define INVALID_FIELD_IN_PARAM_LIST 0x26  #define POWERON_RESET 0x29 @@ -180,7 +182,7 @@ static int sdebug_sectors_per;		/* sectors per cylinder */  #define SDEBUG_SENSE_LEN 32  #define SCSI_DEBUG_CANQUEUE  255 -#define SCSI_DEBUG_MAX_CMD_LEN 16 +#define SCSI_DEBUG_MAX_CMD_LEN 32  struct sdebug_dev_info {  	struct list_head dev_list; @@ -296,9 +298,25 @@ static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,  }  static void get_data_transfer_info(unsigned char *cmd, -				   unsigned long long *lba, unsigned int *num) +				   unsigned long long *lba, unsigned int *num, +				   u32 *ei_lba)  { +	*ei_lba = 0; +  	switch (*cmd) { +	case VARIABLE_LENGTH_CMD: +		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 | +			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 | +			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 | +			(u64)cmd[13] << 48 | (u64)cmd[12] << 56; + +		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | +			(u32)cmd[21] << 16 | (u32)cmd[20] << 24; + +		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | +			(u32)cmd[28] << 24; +		break; +  	case WRITE_16:  	case READ_16:  		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 | @@ -1589,7 +1607,7 @@ static int do_device_access(struct scsi_cmnd *scmd,  }  static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, -			    unsigned int sectors) +			    unsigned int sectors, u32 ei_lba)  {  	unsigned int i, resid;  	struct scatterlist *psgl; @@ -1636,13 +1654,23 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,  			return 0x01;  		} -		if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && +		if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&  		    be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {  			printk(KERN_ERR "%s: REF check failed on sector %lu\n",  			       __func__, (unsigned long)sector);  			dif_errors++;  			return 0x03;  		} + +		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && +		    be32_to_cpu(sdt[i].ref_tag) != ei_lba) { +			printk(KERN_ERR "%s: REF check failed on sector %lu\n", +			       __func__, (unsigned long)sector); +			dif_errors++; +			return 0x03; +		} + +		ei_lba++;  	}  	resid = sectors * 8; /* Bytes of protection data to copy into sgl */ @@ -1670,7 +1698,8 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,  }  static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, -		     unsigned int num, struct sdebug_dev_info *devip) +		     unsigned int num, struct sdebug_dev_info *devip, +		     u32 ei_lba)  {  	unsigned long iflags;  	int ret; @@ -1699,7 +1728,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,  	/* DIX + T10 DIF */  	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { -		int prot_ret = prot_verify_read(SCpnt, lba, num); +		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);  		if (prot_ret) {  			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); @@ -1735,7 +1764,7 @@ void dump_sector(unsigned char *buf, int len)  }  static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, -			     unsigned int sectors) +			     unsigned int sectors, u32 ei_lba)  {  	int i, j, ret;  	struct sd_dif_tuple *sdt; @@ -1749,11 +1778,6 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,  	sector = do_div(tmp_sec, sdebug_store_sectors); -	if (((SCpnt->cmnd[1] >> 5) & 7) != 1) { -		printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n"); -		return 0; -	} -  	BUG_ON(scsi_sg_count(SCpnt) == 0);  	BUG_ON(scsi_prot_sg_count(SCpnt) == 0); @@ -1808,7 +1832,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,  				goto out;  			} -			if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION && +			if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&  			    be32_to_cpu(sdt->ref_tag)  			    != (start_sec & 0xffffffff)) {  				printk(KERN_ERR @@ -1819,6 +1843,16 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,  				goto out;  			} +			if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && +			    be32_to_cpu(sdt->ref_tag) != ei_lba) { +				printk(KERN_ERR +				       "%s: REF check failed on sector %lu\n", +				       __func__, (unsigned long)sector); +				ret = 0x03; +				dump_sector(daddr, scsi_debug_sector_size); +				goto out; +			} +  			/* Would be great to copy this in bigger  			 * chunks.  However, for the sake of  			 * correctness we need to verify each sector @@ -1832,6 +1866,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,  				sector = 0;	/* Force wrap */  			start_sec++; +			ei_lba++;  			daddr += scsi_debug_sector_size;  			ppage_offset += sizeof(struct sd_dif_tuple);  		} @@ -1853,7 +1888,8 @@ out:  }  static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, -		      unsigned int num, struct sdebug_dev_info *devip) +		      unsigned int num, struct sdebug_dev_info *devip, +		      u32 ei_lba)  {  	unsigned long iflags;  	int ret; @@ -1864,7 +1900,7 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,  	/* DIX + T10 DIF */  	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { -		int prot_ret = prot_verify_write(SCpnt, lba, num); +		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);  		if (prot_ret) {  			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); @@ -2872,11 +2908,12 @@ static int __init scsi_debug_init(void)  	case SD_DIF_TYPE0_PROTECTION:  	case SD_DIF_TYPE1_PROTECTION: +	case SD_DIF_TYPE2_PROTECTION:  	case SD_DIF_TYPE3_PROTECTION:  		break;  	default: -		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n"); +		printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");  		return -EINVAL;  	} @@ -3121,6 +3158,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  	int len, k;  	unsigned int num;  	unsigned long long lba; +	u32 ei_lba;  	int errsts = 0;  	int target = SCpnt->device->id;  	struct sdebug_dev_info *devip = NULL; @@ -3254,14 +3292,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  	case READ_16:  	case READ_12:  	case READ_10: +		/* READ{10,12,16} and DIF Type 2 are natural enemies */ +		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && +		    cmd[1] & 0xe0) { +			mk_sense_buffer(devip, ILLEGAL_REQUEST, +					INVALID_COMMAND_OPCODE, 0); +			errsts = check_condition_result; +			break; +		} + +		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || +		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && +		    (cmd[1] & 0xe0) == 0) +			printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); + +		/* fall through */  	case READ_6: +read:  		errsts = check_readiness(SCpnt, 0, devip);  		if (errsts)  			break;  		if (scsi_debug_fake_rw)  			break; -		get_data_transfer_info(cmd, &lba, &num); -		errsts = resp_read(SCpnt, lba, num, devip); +		get_data_transfer_info(cmd, &lba, &num, &ei_lba); +		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);  		if (inj_recovered && (0 == errsts)) {  			mk_sense_buffer(devip, RECOVERED_ERROR,  					THRESHOLD_EXCEEDED, 0); @@ -3288,14 +3342,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  	case WRITE_16:  	case WRITE_12:  	case WRITE_10: +		/* WRITE{10,12,16} and DIF Type 2 are natural enemies */ +		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && +		    cmd[1] & 0xe0) { +			mk_sense_buffer(devip, ILLEGAL_REQUEST, +					INVALID_COMMAND_OPCODE, 0); +			errsts = check_condition_result; +			break; +		} + +		if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || +		     scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && +		    (cmd[1] & 0xe0) == 0) +			printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); + +		/* fall through */  	case WRITE_6: +write:  		errsts = check_readiness(SCpnt, 0, devip);  		if (errsts)  			break;  		if (scsi_debug_fake_rw)  			break; -		get_data_transfer_info(cmd, &lba, &num); -		errsts = resp_write(SCpnt, lba, num, devip); +		get_data_transfer_info(cmd, &lba, &num, &ei_lba); +		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);  		if (inj_recovered && (0 == errsts)) {  			mk_sense_buffer(devip, RECOVERED_ERROR,  					THRESHOLD_EXCEEDED, 0); @@ -3341,15 +3411,38 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  			break;  		if (scsi_debug_fake_rw)  			break; -		get_data_transfer_info(cmd, &lba, &num); -		errsts = resp_read(SCpnt, lba, num, devip); +		get_data_transfer_info(cmd, &lba, &num, &ei_lba); +		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);  		if (errsts)  			break; -		errsts = resp_write(SCpnt, lba, num, devip); +		errsts = resp_write(SCpnt, lba, num, devip, ei_lba);  		if (errsts)  			break;  		errsts = resp_xdwriteread(SCpnt, lba, num, devip);  		break; +	case VARIABLE_LENGTH_CMD: +		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { + +			if ((cmd[10] & 0xe0) == 0) +				printk(KERN_ERR +				       "Unprotected RD/WR to DIF device\n"); + +			if (cmd[9] == READ_32) { +				BUG_ON(SCpnt->cmd_len < 32); +				goto read; +			} + +			if (cmd[9] == WRITE_32) { +				BUG_ON(SCpnt->cmd_len < 32); +				goto write; +			} +		} + +		mk_sense_buffer(devip, ILLEGAL_REQUEST, +				INVALID_FIELD_IN_CDB, 0); +		errsts = check_condition_result; +		break; +  	default:  		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)  			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 877204daf54..1b0060b791e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -725,6 +725,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,  		case NEEDS_RETRY:  		case FAILED:  			break; +		case ADD_TO_MLQUEUE: +			rtn = NEEDS_RETRY; +			break;  		default:  			rtn = FAILED;  			break; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index b98885de687..a67fed10598 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3586,6 +3586,7 @@ enum fc_dispatch_result {  /**   * fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD + * @q:		fc host request queue   * @shost:	scsi host rport attached to   * @job:	bsg job to be processed   */ @@ -3693,6 +3694,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)  /**   * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD + * @q:		rport request queue   * @shost:	scsi host rport attached to   * @rport:	rport request destined to   * @job:	bsg job to be processed diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8dd96dcd716..9093c7261f3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -116,6 +116,9 @@ static DEFINE_IDA(sd_index_ida);   * object after last put) */  static DEFINE_MUTEX(sd_ref_mutex); +struct kmem_cache *sd_cdb_cache; +mempool_t *sd_cdb_pool; +  static const char *sd_cache_types[] = {  	"write through", "none", "write back",  	"write back, no read (daft)" @@ -370,6 +373,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)  	mutex_unlock(&sd_ref_mutex);  } +static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) +{ +	unsigned int prot_op = SCSI_PROT_NORMAL; +	unsigned int dix = scsi_prot_sg_count(scmd); + +	if (scmd->sc_data_direction == DMA_FROM_DEVICE) { +		if (dif && dix) +			prot_op = SCSI_PROT_READ_PASS; +		else if (dif && !dix) +			prot_op = SCSI_PROT_READ_STRIP; +		else if (!dif && dix) +			prot_op = SCSI_PROT_READ_INSERT; +	} else { +		if (dif && dix) +			prot_op = SCSI_PROT_WRITE_PASS; +		else if (dif && !dix) +			prot_op = SCSI_PROT_WRITE_INSERT; +		else if (!dif && dix) +			prot_op = SCSI_PROT_WRITE_STRIP; +	} + +	scsi_set_prot_op(scmd, prot_op); +	scsi_set_prot_type(scmd, dif); +} +  /**   *	sd_init_command - build a scsi (read or write) command from   *	information in the request structure. @@ -388,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	sector_t threshold;  	unsigned int this_count = blk_rq_sectors(rq);  	int ret, host_dif; +	unsigned char protect;  	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {  		ret = scsi_setup_blk_pc_cmnd(sdp, rq); @@ -520,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */  	host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);  	if (host_dif) -		SCpnt->cmnd[1] = 1 << 5; +		protect = 1 << 5;  	else -		SCpnt->cmnd[1] = 0; +		protect = 0; -	if (block > 0xffffffff) { +	if (host_dif == SD_DIF_TYPE2_PROTECTION) { +		SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC); + +		if (unlikely(SCpnt->cmnd == NULL)) { +			ret = BLKPREP_DEFER; +			goto out; +		} + +		SCpnt->cmd_len = SD_EXT_CDB_SIZE; +		memset(SCpnt->cmnd, 0, SCpnt->cmd_len); +		SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD; +		SCpnt->cmnd[7] = 0x18; +		SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32; +		SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0); + +		/* LBA */ +		SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; +		SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; +		SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; +		SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0; +		SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff; +		SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff; +		SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff; +		SCpnt->cmnd[19] = (unsigned char) block & 0xff; + +		/* Expected Indirect LBA */ +		SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff; +		SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff; +		SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff; +		SCpnt->cmnd[23] = (unsigned char) block & 0xff; + +		/* Transfer length */ +		SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff; +		SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff; +		SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff; +		SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; +	} else if (block > 0xffffffff) {  		SCpnt->cmnd[0] += READ_16 - READ_6; -		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; +		SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);  		SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;  		SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;  		SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; @@ -547,7 +612,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  			this_count = 0xffff;  		SCpnt->cmnd[0] += READ_10 - READ_6; -		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; +		SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);  		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;  		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;  		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; @@ -578,8 +643,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)  	/* If DIF or DIX is enabled, tell HBA how to handle request */  	if (host_dif || scsi_prot_sg_count(SCpnt)) -		sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt), -			  sdkp->protection_type); +		sd_prot_op(SCpnt, host_dif);  	/*  	 * We shouldn't disconnect in the middle of a sector, so with a dumb @@ -1023,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)  	int result = SCpnt->result;  	unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);  	struct scsi_sense_hdr sshdr; +	struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);  	int sense_valid = 0;  	int sense_deferred = 0; @@ -1084,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)  	if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))  		sd_dif_complete(SCpnt, good_bytes); +	if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type) +	    == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) +		mempool_free(SCpnt->cmnd, sd_cdb_pool); +  	return good_bytes;  } @@ -1238,34 +1307,28 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)  	u8 type;  	if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) -		type = 0; -	else -		type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ +		return; -	sdkp->protection_type = type; +	type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ -	switch (type) { -	case SD_DIF_TYPE0_PROTECTION: -	case SD_DIF_TYPE1_PROTECTION: -	case SD_DIF_TYPE3_PROTECTION: -		break; +	if (type == sdkp->protection_type || !sdkp->first_scan) +		return; -	case SD_DIF_TYPE2_PROTECTION: -		sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 "	\ -			  "protection which is currently unsupported. "	\ -			  "Disabling disk!\n"); -		goto disable; +	sdkp->protection_type = type; -	default: -		sd_printk(KERN_ERR, sdkp, "formatted with unknown "	\ -			  "protection type %d. Disabling disk!\n", type); -		goto disable; +	if (type > SD_DIF_TYPE3_PROTECTION) { +		sd_printk(KERN_ERR, sdkp, "formatted with unsupported "	\ +			  "protection type %u. Disabling disk!\n", type); +		sdkp->capacity = 0; +		return;  	} -	return; - -disable: -	sdkp->capacity = 0; +	if (scsi_host_dif_capable(sdp->host, type)) +		sd_printk(KERN_NOTICE, sdkp, +			  "Enabling DIF Type %u protection\n", type); +	else +		sd_printk(KERN_NOTICE, sdkp, +			  "Disabling DIF Type %u protection\n", type);  }  static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, @@ -2300,8 +2363,24 @@ static int __init init_sd(void)  	if (err)  		goto err_out_class; +	sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE, +					 0, 0, NULL); +	if (!sd_cdb_cache) { +		printk(KERN_ERR "sd: can't init extended cdb cache\n"); +		goto err_out_class; +	} + +	sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache); +	if (!sd_cdb_pool) { +		printk(KERN_ERR "sd: can't init extended cdb pool\n"); +		goto err_out_cache; +	} +  	return 0; +err_out_cache: +	kmem_cache_destroy(sd_cdb_cache); +  err_out_class:  	class_unregister(&sd_disk_class);  err_out: @@ -2321,6 +2400,9 @@ static void __exit exit_sd(void)  	SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); +	mempool_destroy(sd_cdb_pool); +	kmem_cache_destroy(sd_cdb_cache); +  	scsi_unregister_driver(&sd_template.gendrv);  	class_unregister(&sd_disk_class); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 8474b5bad3f..e374804d26f 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -37,6 +37,11 @@   */  #define SD_LAST_BUGGY_SECTORS	8 +enum { +	SD_EXT_CDB_SIZE = 32,	/* Extended CDB size */ +	SD_MEMPOOL_SIZE = 2,	/* CDB pool size */ +}; +  struct scsi_disk {  	struct scsi_driver *driver;	/* always &sd_template */  	struct scsi_device *device; @@ -101,16 +106,12 @@ struct sd_dif_tuple {  #ifdef CONFIG_BLK_DEV_INTEGRITY -extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int);  extern void sd_dif_config_host(struct scsi_disk *);  extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);  extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);  #else /* CONFIG_BLK_DEV_INTEGRITY */ -static inline void sd_dif_op(struct scsi_cmnd *cmd, unsigned int a, unsigned int b, unsigned int c) -{ -}  static inline void sd_dif_config_host(struct scsi_disk *disk)  {  } diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 82f14a9482d..88da9774571 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -320,15 +320,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)  		dif = 0; dix = 1;  	} -	if (type) { -		if (dif) -			sd_printk(KERN_NOTICE, sdkp, -				  "Enabling DIF Type %d protection\n", type); -		else -			sd_printk(KERN_NOTICE, sdkp, -				  "Disabling DIF Type %d protection\n", type); -	} -  	if (!dix)  		return; @@ -360,62 +351,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)  }  /* - * DIF DMA operation magic decoder ring. - */ -void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type) -{ -	int csum_convert, prot_op; - -	prot_op = 0; - -	/* Convert checksum? */ -	if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC) -		csum_convert = 1; -	else -		csum_convert = 0; - -	BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6)); - -	switch (scmd->cmnd[0]) { -	case READ_6: -	case READ_10: -	case READ_12: -	case READ_16: -		if (dif && dix) -			if (csum_convert) -				prot_op = SCSI_PROT_READ_CONVERT; -			else -				prot_op = SCSI_PROT_READ_PASS; -		else if (dif && !dix) -			prot_op = SCSI_PROT_READ_STRIP; -		else if (!dif && dix) -			prot_op = SCSI_PROT_READ_INSERT; - -		break; - -	case WRITE_6: -	case WRITE_10: -	case WRITE_12: -	case WRITE_16: -		if (dif && dix) -			if (csum_convert) -				prot_op = SCSI_PROT_WRITE_CONVERT; -			else -				prot_op = SCSI_PROT_WRITE_PASS; -		else if (dif && !dix) -			prot_op = SCSI_PROT_WRITE_INSERT; -		else if (!dif && dix) -			prot_op = SCSI_PROT_WRITE_STRIP; - -		break; -	} - -	scsi_set_prot_op(scmd, prot_op); -	if (dif) -		scsi_set_prot_type(scmd, type); -} - -/*   * The virtual start sector is the one that was originally submitted   * by the block layer.	Due to partitioning, MD/DM cloning, etc. the   * actual physical start sector is likely to be different.  Remap diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 747a5e5c127..040f751809e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1708,11 +1708,6 @@ static int sg_finish_rem_req(Sg_request * srp)  	Sg_scatter_hold *req_schp = &srp->data;  	SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used)); -	if (srp->res_used) -		sg_unlink_reserve(sfp, srp); -	else -		sg_remove_scat(req_schp); -  	if (srp->rq) {  		if (srp->bio)  			ret = blk_rq_unmap_user(srp->bio); @@ -1720,6 +1715,11 @@ static int sg_finish_rem_req(Sg_request * srp)  		blk_put_request(srp->rq);  	} +	if (srp->res_used) +		sg_unlink_reserve(sfp, srp); +	else +		sg_remove_scat(req_schp); +  	sg_remove_request(sfp, srp);  	return ret; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index eb61f7a70e1..d6f340f48a3 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -684,14 +684,20 @@ static void get_sectorsize(struct scsi_cd *cd)  		cd->capacity = 0x1fffff;  		sector_size = 2048;	/* A guess, just in case */  	} else { -#if 0 -		if (cdrom_get_last_written(&cd->cdi, -					   &cd->capacity)) -#endif -			cd->capacity = 1 + ((buffer[0] << 24) | -						    (buffer[1] << 16) | -						    (buffer[2] << 8) | -						    buffer[3]); +		long last_written; + +		cd->capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) | +				    (buffer[2] << 8) | buffer[3]); +		/* +		 * READ_CAPACITY doesn't return the correct size on +		 * certain UDF media.  If last_written is larger, use +		 * it instead. +		 * +		 * http://bugzilla.kernel.org/show_bug.cgi?id=9668 +		 */ +		if (!cdrom_get_last_written(&cd->cdi, &last_written)) +			cd->capacity = max_t(long, cd->capacity, last_written); +  		sector_size = (buffer[4] << 24) |  		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];  		switch (sector_size) { diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b33d04250bb..12d58a7ed6b 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -2859,11 +2859,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon  			ioctl_result = st_int_ioctl(STp, MTBSF, 1);  		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { -			int old_block_size = STp->block_size;  			STp->block_size = arg & MT_ST_BLKSIZE_MASK;  			if (STp->block_size != 0) { -				if (old_block_size == 0) -					normalize_buffer(STp->buffer);  				(STp->buffer)->buffer_blocks =  				    (STp->buffer)->buffer_size / STp->block_size;  			} diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 887e57e3e22..a72edd4ecee 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -303,6 +303,7 @@ struct iscsi_session {  	int			cmds_max;	/* size of cmds array */  	struct iscsi_task	**cmds;		/* Original Cmds arr */  	struct iscsi_pool	cmdpool;	/* PDU's pool */ +	void			*dd_data;	/* LLD private data */  };  enum { @@ -363,7 +364,7 @@ extern int iscsi_target_alloc(struct scsi_target *starget);   */  extern struct iscsi_cls_session *  iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost, -		    uint16_t, int, uint32_t, unsigned int); +		    uint16_t, int, int, uint32_t, unsigned int);  extern void iscsi_session_teardown(struct iscsi_cls_session *);  extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);  extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 084478e14d2..34c46ab5c31 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -129,6 +129,9 @@ struct scsi_cmnd;  #define MI_REPORT_TARGET_PGS  0x0a  /* values for maintenance out */  #define MO_SET_TARGET_PGS     0x0a +/* values for variable length command */ +#define READ_32		      0x09 +#define WRITE_32	      0x0b  /* Values for T10/04-262r7 */  #define	ATA_16		      0x85	/* 16-byte pass-thru */ diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 3878d1dc7f5..a5e885a111d 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -229,10 +229,6 @@ enum scsi_prot_operations {  	/* OS-HBA: Protected, HBA-Target: Protected */  	SCSI_PROT_READ_PASS,  	SCSI_PROT_WRITE_PASS, - -	/* OS-HBA: Protected, HBA-Target: Protected, checksum conversion */ -	SCSI_PROT_READ_CONVERT, -	SCSI_PROT_WRITE_CONVERT,  };  static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op) diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index b62a097b3ec..6e728b17690 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -798,9 +798,15 @@ static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost)  static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type)  {  	switch (target_type) { -	case 1: return shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION; -	case 2: return shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION; -	case 3: return shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION; +	case 1: +		if (shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION) +			return target_type; +	case 2: +		if (shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION) +			return target_type; +	case 3: +		if (shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION) +			return target_type;  	}  	return 0; @@ -808,13 +814,14 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign  static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type)  { +#if defined(CONFIG_BLK_DEV_INTEGRITY)  	switch (target_type) {  	case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION;  	case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION;  	case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION;  	case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION;  	} - +#endif  	return 0;  }  |