* [PATCH] mptfusion - fc transport attributes
@ 2005-12-17 0:15 Michael Reed
2005-12-27 17:15 ` James Smart
0 siblings, 1 reply; 4+ messages in thread
From: Michael Reed @ 2005-12-17 0:15 UTC (permalink / raw)
To: linux-scsi; +Cc: James.Smart, Jeremy Higdon, Moore, Eric Dean, Gary Hagensen
[-- Attachment #1: Type: text/plain, Size: 1354 bytes --]
Hello,
Attached is a patch which implements fibre channel transport attributes
for LSI's MPT Fusion driver. This patch is dependent upon the following
patches submitted by LSI's Eric Moore on 11/16/2005 but which have not
as yet advanced to the 2.6.15-rc5-git series.
2-module-fix.patch
3-probe-fix.patch
4-spi-fix.patch
5-dvprep-fix.patch
6-mapping-fix.patch
7-bump-fix.patch
For correct operation of the fc transport, I also recommend installing
James Smart's fix of 12/15/2005 which stops recursion on the workqueue.
[PATCH] fix for fc transport recursion problem.
In addition, I also recommend my patch of 12/16/2005 to stop the scsi eh
from taking targets offline while they remain blocked by the transport.
[PATCH] Make scsi error recovery play nice with devices blocked by transport
James Smart had previously reviewed my transport attributes RFC and I have
addressed his comments in the patch.
- module parameter text has been revised
- shifting of wwn remains as board returns
it little endian, not off the wire and
I wish to avoid ia64 access errors
- show_rport_dev_loss_tmo attribute exported
- set_port_dev_loss_tmo function implemented
- revised usage of dd_data and dd_fcrport_size
- added calls to fc_remote_port_chkready()
- removed some unnecessary sanity tests
Signed-off-by: Michael Reed <mdr@sgi.com>
[-- Attachment #2: lsi_fc_transport.patch --]
[-- Type: text/x-patch, Size: 27805 bytes --]
diff -ru 1/drivers/message/fusion/mptbase.c 2/drivers/message/fusion/mptbase.c
--- 1/drivers/message/fusion/mptbase.c 2005-12-16 17:01:09.000000000 -0600
+++ 2/drivers/message/fusion/mptbase.c 2005-12-16 17:06:13.000000000 -0600
@@ -148,7 +148,6 @@
static int WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag);
static int GetLanConfigPages(MPT_ADAPTER *ioc);
-static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
static int GetIoUnitPage2(MPT_ADAPTER *ioc);
int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum);
@@ -1245,6 +1244,8 @@
ioc->pcidev = pdev;
ioc->diagPending = 0;
spin_lock_init(&ioc->diagLock);
+ spin_lock_init(&ioc->work_lock);
+ spin_lock_init(&ioc->fc_rport_lock);
spin_lock_init(&ioc->initializing_hba_lock);
/* Initialize the event logging.
@@ -1268,6 +1269,10 @@
*/
INIT_LIST_HEAD(&ioc->configQ);
+ /* Initialize the fc rport list head.
+ */
+ INIT_LIST_HEAD(&ioc->l.fc_rports);
+
/* Find lookup slot. */
INIT_LIST_HEAD(&ioc->list);
ioc->id = mpt_ids++;
@@ -1880,7 +1885,7 @@
* (FCPortPage0_t stuff)
*/
for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
- (void) GetFcPortPage0(ioc, ii);
+ (void) mptbase_GetFcPortPage0(ioc, ii);
}
if ((ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) &&
@@ -4199,7 +4204,7 @@
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
- * GetFcPortPage0 - Fetch FCPort config Page0.
+ * mptbase_GetFcPortPage0 - Fetch FCPort config Page0.
* @ioc: Pointer to MPT_ADAPTER structure
* @portnum: IOC Port number
*
@@ -4209,8 +4214,8 @@
* -EAGAIN if no msg frames currently available
* -EFAULT for non-successful reply or no reply (timeout)
*/
-static int
-GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
+int
+mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
{
ConfigPageHeader_t hdr;
CONFIGPARMS cfg;
@@ -4220,6 +4225,8 @@
int data_sz;
int copy_sz;
int rc;
+ int count=400;
+
/* Get FCPort Page 0 header */
hdr.PageVersion = 0;
@@ -4243,6 +4250,8 @@
rc = -ENOMEM;
ppage0_alloc = (FCPortPage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
if (ppage0_alloc) {
+
+ try_again:
memset((u8 *)ppage0_alloc, 0, data_sz);
cfg.physAddr = page0_dma;
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
@@ -4274,6 +4283,16 @@
pp0dest->DiscoveredPortsCount = le32_to_cpu(pp0dest->DiscoveredPortsCount);
pp0dest->MaxInitiators = le32_to_cpu(pp0dest->MaxInitiators);
+ /* if still doing discovery, hang loose a while until finished */
+ if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+ if (count-- > 0) {
+ msleep_interruptible(100);
+ goto try_again;
+ }
+ else
+ printk(MYIOC_s_INFO_FMT "Firmware discovery not complete.\n",
+ ioc->name);
+ }
}
pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
@@ -6358,6 +6377,7 @@
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
EXPORT_SYMBOL(mpt_alt_ioc_wait);
+EXPORT_SYMBOL(mptbase_GetFcPortPage0);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -ru 1/drivers/message/fusion/mptbase.h 2/drivers/message/fusion/mptbase.h
--- 1/drivers/message/fusion/mptbase.h 2005-12-16 17:02:19.000000000 -0600
+++ 2/drivers/message/fusion/mptbase.h 2005-12-16 17:06:13.000000000 -0600
@@ -499,6 +499,22 @@
int isRaid; /* bit field, 1 if RAID */
}RaidCfgData;
+#define MPT_RPORT_INFO_FLAGS_REGISTERED 0x01 /* rport registered */
+#define MPT_RPORT_INFO_FLAGS_MISSING 0x02 /* missing from DevPage0 scan */
+#define MPT_RPORT_INFO_FLAGS_MAPPED_VDEV 0x04 /* target mapped in vdev */
+
+/*
+ * data allocated for each fc rport device
+ */
+struct mptfc_rport_info
+{
+ struct list_head list;
+ struct fc_rport *rport;
+ VirtDevice *vdev;
+ FCDevicePage0_t pg0;
+ u8 flags;
+};
+
/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
*/
@@ -611,7 +627,18 @@
int initializing_hba_lock_flag;
struct list_head list;
struct net_device *netdev;
+
+ union {
struct list_head sas_topology;
+ struct list_head fc_rports; /* list of wwpn / sdev target / rport ptr */
+ } l;
+
+ spinlock_t fc_rport_lock; /* for all accesses of list and ri flags */
+
+ spinlock_t work_lock;
+ int work_count;
+ struct work_struct work_task; /* for use by personality, i.e., fc, sas, spi, lan */
+
MPT_SAS_MGMT sas_mgmt;
} MPT_ADAPTER;
@@ -999,6 +1026,7 @@
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc);
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
+extern int mptbase_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum);
extern int mpt_alt_ioc_wait(MPT_ADAPTER *ioc);
/*
diff -ru 1/drivers/message/fusion/mptfc.c 2/drivers/message/fusion/mptfc.c
--- 1/drivers/message/fusion/mptfc.c 2005-12-16 17:01:59.000000000 -0600
+++ 2/drivers/message/fusion/mptfc.c 2005-12-16 17:06:13.000000000 -0600
@@ -55,12 +55,14 @@
#include <linux/reboot.h> /* notifier code */
#include <linux/sched.h>
#include <linux/workqueue.h>
+#include <linux/sort.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
#include "mptbase.h"
#include "mptscsih.h"
@@ -79,19 +81,31 @@
module_param(mpt_pq_filter, int, 0);
MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
+#define MPTFC_DEV_LOSS_TMO (60)
+static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
+module_param(mptfc_dev_loss_tmo, int, 0);
+MODULE_PARM_DESC(mptfc_dev_loss_tmo, " Initial time the driver programs the transport to"
+ " wait for an rport to return following a device"
+ " loss event. Default=60.");
+
static int mptfcDoneCtx = -1;
static int mptfcTaskCtx = -1;
static int mptfcInternalCtx = -1; /* Used only for internal commands */
+int mptfc_slave_alloc(struct scsi_device *device);
+static int mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *));
+static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout);
+static void __devexit mptfc_remove(struct pci_dev *pdev);
+
static struct scsi_host_template mptfc_driver_template = {
.module = THIS_MODULE,
.proc_name = "mptfc",
.proc_info = mptscsih_proc_info,
.name = "MPT FC Host",
.info = mptscsih_info,
- .queuecommand = mptscsih_qcmd,
+ .queuecommand = mptfc_qcmd,
.target_alloc = mptscsih_target_alloc,
- .slave_alloc = mptscsih_slave_alloc,
+ .slave_alloc = mptfc_slave_alloc,
.slave_configure = mptscsih_slave_configure,
.target_destroy = mptscsih_target_destroy,
.slave_destroy = mptscsih_slave_destroy,
@@ -132,15 +146,451 @@
};
MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+static struct scsi_transport_template *mptfc_transport_template = NULL;
+
+struct fc_function_template mptfc_transport_functions = {
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+
+ .get_host_port_id = NULL,
+ .show_host_port_id = 1,
+
+ .dd_fcrport_size = 8,
+ .show_rport_supported_classes = 1,
+
+ .get_starget_node_name = NULL,
+ .show_starget_node_name = 1,
+ .get_starget_port_name = NULL,
+ .show_starget_port_name = 1,
+ .get_starget_port_id = NULL,
+ .show_starget_port_id = 1,
+
+ .get_rport_dev_loss_tmo = NULL,
+ .set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+};
+
+/* FIXME! values controlling firmware RESCAN event
+ * need to be set low to allow dev_loss_tmo to
+ * work as expected. Currently, firmware doesn't
+ * notify driver of RESCAN event until some number
+ * of seconds elapse. This value can be set via
+ * lsiutil.
+ */
+static void
+mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
+{
+ if (timeout > 0)
+ rport->dev_loss_tmo = timeout;
+ else
+ rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+}
+
+static int
+mptfc_FcDevPage0_cmp_func(const void *a, const void *b)
+{
+ FCDevicePage0_t **aa=(FCDevicePage0_t **)a;
+ FCDevicePage0_t **bb=(FCDevicePage0_t **)b;
+
+ if ((*aa)->CurrentBus == (*bb)->CurrentBus) {
+ if ((*aa)->CurrentTargetID == (*bb)->CurrentTargetID)
+ return 0;
+ if ((*aa)->CurrentTargetID < (*bb)->CurrentTargetID)
+ return -1;
+ return 1;
+ }
+ if ((*aa)->CurrentBus < (*bb)->CurrentBus)
+ return -1;
+ return 1;
+}
+
+static int
+mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
+ void(*func)(MPT_ADAPTER *ioc,int channel, FCDevicePage0_t *arg))
+{
+ ConfigPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ FCDevicePage0_t *ppage0_alloc, *fc;
+ dma_addr_t page0_dma;
+ int data_sz;
+ int ii;
+
+ FCDevicePage0_t *p0_array=NULL, *p_p0;
+ FCDevicePage0_t **pp0_array=NULL, **p_pp0;
+
+ int rc = -ENOMEM;
+ U32 port_id = 0xffffff;
+ int num_targ = 0;
+ int max_bus = ioc->facts.MaxBuses;
+ int max_targ = ioc->facts.MaxDevices;
+
+ if (max_bus == 0 || max_targ == 0)
+ goto out;
+
+ data_sz = sizeof(FCDevicePage0_t) * max_bus * max_targ;
+ p_p0 = p0_array = kmalloc(data_sz,GFP_KERNEL);
+ if (!p0_array)
+ goto out;
+ memset((u8 *)p0_array, 0, data_sz);
+
+ data_sz = sizeof(FCDevicePage0_t *) * max_bus * max_targ;
+ p_pp0 = pp0_array = kmalloc(data_sz,GFP_KERNEL);
+ if (!pp0_array)
+ goto out;
+ memset((u8 *)pp0_array, 0, data_sz);
+
+ do {
+ /* Get FC Device Page 0 header */
+ hdr.PageVersion = 0;
+ hdr.PageLength = 0;
+ hdr.PageNumber = 0;
+ hdr.PageType = MPI_CONFIG_PAGETYPE_FC_DEVICE;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.dir = 0;
+ cfg.pageAddr = port_id;
+ cfg.timeout = 0;
+
+ if ((rc = mpt_config(ioc, &cfg)) != 0)
+ break;
+
+ if (hdr.PageLength <= 0)
+ break;
+ else {
+ data_sz = hdr.PageLength * 4;
+ ppage0_alloc = (FCDevicePage0_t *)
+ pci_alloc_consistent(ioc->pcidev, data_sz, &page0_dma);
+ rc = -ENOMEM;
+ if (ppage0_alloc) {
+ memset((u8 *)ppage0_alloc, 0, data_sz);
+ cfg.physAddr = page0_dma;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ if ((rc = mpt_config(ioc, &cfg)) == 0) {
+ le32_to_cpus(ppage0_alloc->PortIdentifier);
+ le32_to_cpus(ppage0_alloc->WWNN.Low);
+ le32_to_cpus(ppage0_alloc->WWNN.High);
+ le32_to_cpus(ppage0_alloc->WWPN.Low);
+ le32_to_cpus(ppage0_alloc->WWPN.High);
+ le16_to_cpus(ppage0_alloc->BBCredit);
+ le16_to_cpus(ppage0_alloc->MaxRxFrameSize);
+
+ port_id = ppage0_alloc->PortIdentifier;
+ num_targ++;
+ *p_p0 = *ppage0_alloc; /* save data */
+ *p_pp0++ = p_p0++; /* save addr */
+ }
+ pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma);
+ if (rc != 0)
+ break;
+ }
+ else break;
+ }
+ } while (port_id <= 0xffff00);
+
+ if (num_targ) {
+ /* sort array */
+ if (num_targ > 1)
+ sort (pp0_array,num_targ,sizeof(FCDevicePage0_t *),
+ mptfc_FcDevPage0_cmp_func, NULL);
+ /* call caller's func for each targ */
+ for (ii=0; ii<num_targ; ii++) {
+ fc = *(pp0_array+ii);
+ func(ioc,ioc_port,fc);
+ }
+ }
+
+ out:
+ if (pp0_array)
+ kfree(pp0_array);
+ if (p0_array)
+ kfree(p0_array);
+ return rc;
+}
+
+static int
+mptfc_generate_rport_identifiers(FCDevicePage0_t *pg0, struct fc_rport_identifiers *rid)
+{
+ /* not currently usable */
+ if (pg0->Flags & (MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID |
+ MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID))
+ return -1;
+
+ if (!(pg0->Flags & MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID))
+ return -1;
+
+ if (!(pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET))
+ return -1;
+
+ /* board data structure already normalized to platform endianness
+ * shifted to avoid unaligned access on 64 bit architecture */
+ rid->node_name = ((u64)pg0->WWNN.High) << 32 | (u64)pg0->WWNN.Low;
+ rid->port_name = ((u64)pg0->WWPN.High) << 32 | (u64)pg0->WWPN.Low;
+ rid->port_id = pg0->PortIdentifier;
+ rid->roles = FC_RPORT_ROLE_UNKNOWN;
+ rid->roles |= FC_RPORT_ROLE_FCP_TARGET;
+ if (pg0->Protocol & MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR)
+ rid->roles |= FC_RPORT_ROLE_FCP_INITIATOR;
+
+ return 0;
+}
+
+static void
+mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0)
+{
+ struct fc_rport_identifiers rport_ids;
+ struct fc_rport *rport;
+ struct mptfc_rport_info *ri;
+ int match=0;
+ u64 port_name;
+ unsigned long flags;
+
+ if (mptfc_generate_rport_identifiers(pg0,&rport_ids) < 0)
+ return;
+
+ /* scan list looking for a match */
+ spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+ list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+ port_name = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+ if (port_name == rport_ids.port_name) { /* match */
+ list_move_tail(&ri->list,&ioc->l.fc_rports);
+ match = 1;
+ break;
+ }
+ }
+ if (!match) { /* allocate one */
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+ ri = kmalloc(sizeof(struct mptfc_rport_info), GFP_KERNEL);
+ if (!ri)
+ return;
+ memset(ri, 0, sizeof(struct mptfc_rport_info));
+ spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+ list_add_tail(&ri->list,&ioc->l.fc_rports);
+ }
+
+ ri->pg0 = *pg0; /* add/update pg0 data */
+ ri->flags &= ~MPT_RPORT_INFO_FLAGS_MISSING;
+
+ if (!(ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED)) {
+ ri->flags |= MPT_RPORT_INFO_FLAGS_REGISTERED;
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+ rport = fc_remote_port_add(ioc->sh,channel,&rport_ids);
+ spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+ if (rport) {
+ if (*((struct mptfc_rport_info **)rport->dd_data) != ri) {
+ ri->flags &= ~MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+ ri->vdev = NULL;
+ ri->rport = rport;
+ *((struct mptfc_rport_info **)rport->dd_data) = ri;
+ }
+ rport->dev_loss_tmo = mptfc_dev_loss_tmo;
+ /* if already mapped, remap here. If not mapped,
+ * slave_alloc will allocate vdev and map */
+ if (ri->flags & MPT_RPORT_INFO_FLAGS_MAPPED_VDEV) {
+ ri->vdev->target_id = ri->pg0.CurrentTargetID;
+ ri->vdev->bus_id = ri->pg0.CurrentBus;
+ ri->vdev->vtarget->target_id = ri->vdev->target_id;
+ ri->vdev->vtarget->bus_id = ri->vdev->bus_id;
+ }
+ #ifdef MPT_DEBUG
+ printk ("mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
+ "rport tid %d, tmo %d\n",
+ ioc->sh->host_no,
+ pg0->PortIdentifier,
+ pg0->WWNN,
+ pg0->WWPN,
+ pg0->CurrentTargetID,
+ ri->rport->scsi_target_id,
+ ri->rport->dev_loss_tmo);
+ #endif
+ }
+ else {
+ list_del(&ri->list);
+ kfree(ri);
+ ri = NULL;
+ }
+ }
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+}
+
/*
- * mptfc_probe - Installs scsi devices per bus.
- * @pdev: Pointer to pci_dev structure
- *
- * Returns 0 for success, non-zero for failure.
- *
+ * OS entry point to allow host driver to alloc memory
+ * for each scsi device. Called once per device the bus scan.
+ * Return non-zero if allocation fails.
+ * Init memory once per LUN.
*/
+int
+mptfc_slave_alloc(struct scsi_device *sdev)
+{
+ MPT_SCSI_HOST *hd;
+ VirtTarget *vtarget;
+ VirtDevice *vdev;
+ struct scsi_target *starget;
+ struct fc_rport *rport;
+ struct mptfc_rport_info *ri;
+ unsigned long flags;
+
+
+ rport=starget_to_rport(scsi_target(sdev));
+
+ if (!rport || fc_remote_port_chkready(rport))
+ return -ENXIO;
+
+ hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
+
+ vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL);
+ if (!vdev) {
+ printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+ hd->ioc->name, sizeof(VirtDevice));
+ return -ENOMEM;
+ }
+ memset(vdev, 0, sizeof(VirtDevice));
+
+ spin_lock_irqsave(&hd->ioc->fc_rport_lock,flags);
+
+ if (!(ri=*((struct mptfc_rport_info **)rport->dd_data))) {
+ spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+ kfree(vdev);
+ return -ENODEV;
+ }
+
+ sdev->hostdata = vdev;
+ starget = scsi_target(sdev);
+ vtarget = starget->hostdata;
+ if (vtarget->num_luns == 0) {
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES | MPT_TARGET_FLAGS_VALID_INQUIRY;
+ hd->Targets[sdev->id] = vtarget;
+ }
+
+ vtarget->target_id = vdev->target_id;
+ vtarget->bus_id = vdev->bus_id;
+
+ vdev->vtarget = vtarget;
+ vdev->ioc_id = hd->ioc->id;
+ vdev->lun = sdev->lun;
+ vdev->target_id = ri->pg0.CurrentTargetID;
+ vdev->bus_id = ri->pg0.CurrentBus;
+
+ ri->flags |= MPT_RPORT_INFO_FLAGS_MAPPED_VDEV;
+ ri->vdev = vdev;
+
+ spin_unlock_irqrestore(&hd->ioc->fc_rport_lock,flags);
+
+ vtarget->num_luns++;
+
+#ifdef MPT_DEBUG
+ printk ("mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, CurrentTargetID %d, "
+ "%x %llx %llx\n",sdev->host->host_no,
+ vtarget->num_luns,
+ sdev->id, ri->pg0.CurrentTargetID,
+ ri->pg0.PortIdentifier,ri->pg0.WWPN,ri->pg0.WWNN);
+#endif
+
+ return 0;
+}
+
+static int
+mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+ struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device));
+ int err;
+
+ err = fc_remote_port_chkready(rport);
+ if (unlikely(err)) {
+ SCpnt->result = err;
+ done(SCpnt);
+ return 0;
+ }
+ return mptscsih_qcmd(SCpnt,done);
+}
+
+static void
+mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
+{
+ unsigned class=0, cos=0;
+
+ /* don't know what to do as only one scsi (fc) host was allocated */
+ if (portnum != 0)
+ return;
+
+ class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
+ cos |= FC_COS_CLASS1;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
+ cos |= FC_COS_CLASS2;
+ if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
+ cos |= FC_COS_CLASS3;
+
+ fc_host_node_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
+ | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
+
+ fc_host_port_name(ioc->sh) = (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
+ | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
+
+ fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
+
+ fc_host_supported_classes(ioc->sh) = cos;
+
+ fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
+}
+
+static void
+mptfc_rescan_devices(void *arg)
+{
+ MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
+ int ii;
+ int work_to_do;
+ unsigned long flags;
+ struct mptfc_rport_info *ri;
+
+ do {
+ /* start by tagging all ports as missing */
+ spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+ list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+ if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+ ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
+ }
+ }
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+ /* now rescan devices known to adapter, will reregister existing rports */
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ (void) mptbase_GetFcPortPage0(ioc, ii);
+ mptfc_init_host_attr(ioc,ii); /* refresh */
+ mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+ }
+
+ /* delete devices still missing */
+ spin_lock_irqsave(&ioc->fc_rport_lock,flags);
+ list_for_each_entry(ri, &ioc->l.fc_rports, list) {
+ /* if newly missing, delete it */
+ if ((ri->flags & (MPT_RPORT_INFO_FLAGS_REGISTERED |
+ MPT_RPORT_INFO_FLAGS_MISSING))
+ == (MPT_RPORT_INFO_FLAGS_REGISTERED | MPT_RPORT_INFO_FLAGS_MISSING)) {
+ ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|MPT_RPORT_INFO_FLAGS_MISSING);
+ fc_remote_port_delete(ri->rport);
+ /* remote port not really deleted 'cause binding is by WWPN
+ * and driver only registers FCP_TARGETs */
+ #ifdef MPT_DEBUG
+ printk ("mptfc_rescan.%d: %llx deleted\n",ioc->sh->host_no,ri->pg0.WWPN);
+ #endif
+ }
+ }
+ spin_unlock_irqrestore(&ioc->fc_rport_lock,flags);
+
+ /* allow multiple passes as target state might have changed during scan */
+ spin_lock_irqsave(&ioc->work_lock,flags);
+ if (ioc->work_count > 2) /* don't need THAT many passes */
+ ioc->work_count = 2;
+ work_to_do = --ioc->work_count;
+ spin_unlock_irqrestore(&ioc->work_lock,flags);
+ } while (work_to_do);
+}
+
static int
mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
@@ -155,10 +605,10 @@
u8 *mem;
int error=0;
int r;
-
+
if ((r = mpt_attach(pdev,id)) != 0)
return r;
-
+
ioc = pci_get_drvdata(pdev);
ioc->DoneCtx = mptfcDoneCtx;
ioc->TaskCtx = mptfcTaskCtx;
@@ -194,7 +644,7 @@
printk(MYIOC_s_WARN_FMT
"Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n",
ioc->name, ioc);
- return 0;
+ return -ENODEV;
}
sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST));
@@ -207,6 +657,8 @@
goto out_mptfc_probe;
}
+ INIT_WORK(&ioc->work_task, mptfc_rescan_devices,(void *)ioc);
+
spin_lock_irqsave(&ioc->FreeQlock, flags);
/* Attach the SCSI Host to the IOC structure
@@ -332,6 +784,7 @@
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
+ sh->transportt = mptfc_transport_template;
error = scsi_add_host (sh, &ioc->pcidev->dev);
if(error) {
dprintk((KERN_ERR MYNAM
@@ -339,7 +792,11 @@
goto out_mptfc_probe;
}
- scsi_scan_host(sh);
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ mptfc_init_host_attr(ioc,ii);
+ mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
+ }
+
return 0;
out_mptfc_probe:
@@ -352,7 +809,7 @@
.name = "mptfc",
.id_table = mptfc_pci_table,
.probe = mptfc_probe,
- .remove = __devexit_p(mptscsih_remove),
+ .remove = __devexit_p(mptfc_remove),
.shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
@@ -370,9 +827,18 @@
static int __init
mptfc_init(void)
{
+ int error;
show_mptmod_ver(my_NAME, my_VERSION);
+ /* sanity check module parameter */
+ if (mptfc_dev_loss_tmo == 0)
+ mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO;
+
+ mptfc_transport_template = fc_attach_transport(&mptfc_transport_functions);
+ if (!mptfc_transport_template)
+ return -ENODEV;
+
mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER);
mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
@@ -387,7 +853,33 @@
": Registered for IOC reset notifications\n"));
}
- return pci_register_driver(&mptfc_driver);
+ error = pci_register_driver(&mptfc_driver);
+ if (error) {
+ fc_release_transport(mptfc_transport_template);
+ }
+
+ return error;
+}
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ * mptfc_remove - Removed fc infrastructure for devices
+ * @pdev: Pointer to pci_dev structure
+ *
+ */
+static void __devexit mptfc_remove(struct pci_dev *pdev)
+{
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
+ struct mptfc_rport_info *p, *n;
+
+ fc_remove_host(ioc->sh);
+
+ list_for_each_entry_safe(p, n, &ioc->l.fc_rports, list) {
+ list_del(&p->list);
+ kfree(p);
+ }
+
+ mptscsih_remove(pdev);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -400,7 +892,8 @@
mptfc_exit(void)
{
pci_unregister_driver(&mptfc_driver);
-
+ fc_release_transport(mptfc_transport_template);
+
mpt_reset_deregister(mptfcDoneCtx);
dprintk((KERN_INFO MYNAM
": Deregistered for IOC reset notifications\n"));
diff -ru 1/drivers/message/fusion/mptsas.c 2/drivers/message/fusion/mptsas.c
--- 1/drivers/message/fusion/mptsas.c 2005-12-16 17:01:59.000000000 -0600
+++ 2/drivers/message/fusion/mptsas.c 2005-12-16 17:06:13.000000000 -0600
@@ -257,7 +257,7 @@
}
rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
- list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ list_for_each_entry(p, &hd->ioc->l.sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
if (p->phy_info[i].attached.sas_address ==
rphy->identify.sas_address) {
@@ -994,7 +994,7 @@
if (error)
goto out_free_port_info;
- list_add_tail(&port_info->list, &ioc->sas_topology);
+ list_add_tail(&port_info->list, &ioc->l.sas_topology);
for (i = 0; i < port_info->num_phys; i++) {
mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
@@ -1047,7 +1047,7 @@
*handle = port_info->handle;
- list_add_tail(&port_info->list, &ioc->sas_topology);
+ list_add_tail(&port_info->list, &ioc->l.sas_topology);
for (i = 0; i < port_info->num_phys; i++) {
struct device *parent;
@@ -1079,7 +1079,7 @@
* HBA phys.
*/
parent = &ioc->sh->shost_gendev;
- list_for_each_entry(p, &ioc->sas_topology, list) {
+ list_for_each_entry(p, &ioc->l.sas_topology, list) {
for (j = 0; j < p->num_phys; j++) {
if (port_info->phy_info[i].identify.handle ==
p->phy_info[j].attached.handle)
@@ -1202,7 +1202,7 @@
*/
sh->unique_id = ioc->id;
- INIT_LIST_HEAD(&ioc->sas_topology);
+ INIT_LIST_HEAD(&ioc->l.sas_topology);
init_MUTEX(&ioc->sas_mgmt.mutex);
init_completion(&ioc->sas_mgmt.done);
@@ -1339,7 +1339,7 @@
sas_remove_host(ioc->sh);
- list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
+ list_for_each_entry_safe(p, n, &ioc->l.sas_topology, list) {
list_del(&p->list);
kfree(p);
}
diff -ru 1/drivers/message/fusion/mptscsih.c 2/drivers/message/fusion/mptscsih.c
--- 1/drivers/message/fusion/mptscsih.c 2005-12-16 17:01:59.000000000 -0600
+++ 2/drivers/message/fusion/mptscsih.c 2005-12-16 17:06:13.000000000 -0600
@@ -58,6 +58,7 @@
#include <linux/workqueue.h>
#include <scsi/scsi.h>
+#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
@@ -893,6 +894,7 @@
* when a lun is disable by mid-layer.
* Do NOT access the referenced scsi_cmnd structure or
* members. Will cause either a paging or NULL ptr error.
+ * (BUT, BUT, BUT, the code does reference it! - mdr)
* @hd: Pointer to a SCSI HOST structure
* @vdevice: per device private data
*
@@ -2559,13 +2561,25 @@
hd->cmdPtr = NULL;
}
- /* 7. Set flag to force DV and re-read IOC Page 3
+ /* 7. SPI: Set flag to force DV and re-read IOC Page 3
*/
if (ioc->bus_type == SPI) {
ioc->spi_data.forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3;
ddvtprintk(("Set reload IOC Pg3 Flag\n"));
}
+ /* 7. FC: Rescan for blocked rports which might have returned.
+ */
+ else if (ioc->bus_type == FC) {
+ int work_count;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->work_lock,flags);
+ work_count = ++ioc->work_count;
+ spin_unlock_irqrestore(&ioc->work_lock,flags);
+ if (work_count == 1)
+ schedule_work(&ioc->work_task);
+ }
dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
}
@@ -2589,6 +2603,8 @@
{
MPT_SCSI_HOST *hd;
u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
+ int work_count;
+ unsigned long flags;
devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
ioc->name, event));
@@ -2610,11 +2626,18 @@
/* FIXME! */
break;
+ case MPI_EVENT_RESCAN: /* 06 */
+ spin_lock_irqsave(&ioc->work_lock,flags);
+ work_count = ++ioc->work_count;
+ spin_unlock_irqrestore(&ioc->work_lock,flags);
+ if (work_count == 1)
+ schedule_work(&ioc->work_task);
+ break;
+
/*
* CHECKME! Don't think we need to do
* anything for these, but...
*/
- case MPI_EVENT_RESCAN: /* 06 */
case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */
case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */
/*
@@ -3954,8 +3977,6 @@
/* Search IOC page 3 to determine if this is hidden physical disk
*/
-/* Search IOC page 3 to determine if this is hidden physical disk
- */
static int
mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id)
{
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] mptfusion - fc transport attributes
2005-12-17 0:15 [PATCH] mptfusion - fc transport attributes Michael Reed
@ 2005-12-27 17:15 ` James Smart
2006-01-06 21:23 ` Michael Reed
0 siblings, 1 reply; 4+ messages in thread
From: James Smart @ 2005-12-27 17:15 UTC (permalink / raw)
To: Michael Reed; +Cc: linux-scsi, Jeremy Higdon, Moore, Eric Dean, Gary Hagensen
> +static void
> +mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
> +{
> + if (timeout > 0)
> + rport->dev_loss_tmo = timeout;
> + else
> + rport->dev_loss_tmo = mptfc_dev_loss_tmo;
> +}
The only function of the if-test here is checking for 0 or >0, as
the fc transport ensures it is nothing else. What bothers me is
if the value is 0, then you are overriding it with the mptfc default
value without any warning or error report to the user.
Perhaps we should be dealing with a zero value differently in the transport.
The rest looks ok...
-- james s
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] mptfusion - fc transport attributes
2005-12-27 17:15 ` James Smart
@ 2006-01-06 21:23 ` Michael Reed
2006-01-09 14:51 ` James Smart
0 siblings, 1 reply; 4+ messages in thread
From: Michael Reed @ 2006-01-06 21:23 UTC (permalink / raw)
To: James.Smart; +Cc: linux-scsi, Jeremy Higdon, Moore, Eric Dean, Gary Hagensen
lpfc and qla2x00 have something similar. I chose the driver default instead of
1. Is setting it to one correct for the api?
static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
/*
* The driver doesn't have a per-target timeout setting. Set
* this value globally. lpfc_nodev_tmo should be greater then 0.
*/
if (timeout)
lpfc_nodev_tmo = timeout;
else
lpfc_nodev_tmo = 1;
rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
}
Mike
James Smart wrote:
>
>> +static void
>> +mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
>> +{
>> + if (timeout > 0)
>> + rport->dev_loss_tmo = timeout;
>> + else
>> + rport->dev_loss_tmo = mptfc_dev_loss_tmo;
>> +}
>
> The only function of the if-test here is checking for 0 or >0, as
> the fc transport ensures it is nothing else. What bothers me is
> if the value is 0, then you are overriding it with the mptfc default
> value without any warning or error report to the user.
>
> Perhaps we should be dealing with a zero value differently in the
> transport.
>
> The rest looks ok...
>
> -- james s
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] mptfusion - fc transport attributes
2006-01-06 21:23 ` Michael Reed
@ 2006-01-09 14:51 ` James Smart
0 siblings, 0 replies; 4+ messages in thread
From: James Smart @ 2006-01-09 14:51 UTC (permalink / raw)
To: Michael Reed; +Cc: linux-scsi, Jeremy Higdon, Moore, Eric Dean, Gary Hagensen
As we are all trying to avoid a value of zero, we should just make the
transport set function validate the range so that
1 <= dev_loss_tmo <= whatever_the_max_define_is
-- james s
Michael Reed wrote:
> lpfc and qla2x00 have something similar. I chose the driver default instead of
> 1. Is setting it to one correct for the api?
>
> static void
> lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
> {
> /*
> * The driver doesn't have a per-target timeout setting. Set
> * this value globally. lpfc_nodev_tmo should be greater then 0.
> */
> if (timeout)
> lpfc_nodev_tmo = timeout;
> else
> lpfc_nodev_tmo = 1;
> rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
> }
>
> Mike
>
> James Smart wrote:
>>> +static void
>>> +mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
>>> +{
>>> + if (timeout > 0)
>>> + rport->dev_loss_tmo = timeout;
>>> + else
>>> + rport->dev_loss_tmo = mptfc_dev_loss_tmo;
>>> +}
>> The only function of the if-test here is checking for 0 or >0, as
>> the fc transport ensures it is nothing else. What bothers me is
>> if the value is 0, then you are overriding it with the mptfc default
>> value without any warning or error report to the user.
>>
>> Perhaps we should be dealing with a zero value differently in the
>> transport.
>>
>> The rest looks ok...
>>
>> -- james s
>> -
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2006-01-09 14:51 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-17 0:15 [PATCH] mptfusion - fc transport attributes Michael Reed
2005-12-27 17:15 ` James Smart
2006-01-06 21:23 ` Michael Reed
2006-01-09 14:51 ` James Smart
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox