From 901a920f0759c6ea94255f3c2cd6ec324f7e4752 Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Tue, 28 Feb 2006 19:25:19 -0500 Subject: [SCSI] lpfc 8.1.2: Fixed system panic in lpfc_sli_brdreset during dynamic add of LP11K Fixed system panic in lpfc_sli_brdreset during dynamic add of LP11K Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b7a603a45328..369487e8f450 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1462,9 +1462,23 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) phba->pci_bar2_map = pci_resource_start(phba->pcidev, 2); bar2map_len = pci_resource_len(phba->pcidev, 2); - /* Map HBA SLIM and Control Registers to a kernel virtual address. */ + /* Map HBA SLIM to a kernel virtual address. */ phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); + if (!phba->slim_memmap_p) { + error = -ENODEV; + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for SLIM memory.\n"); + goto out_idr_remove; + } + + /* Map HBA Control Registers to a kernel virtual address. */ phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len); + if (!phba->ctrl_regs_memmap_p) { + error = -ENODEV; + dev_printk(KERN_ERR, &pdev->dev, + "ioremap failed for HBA control registers.\n"); + goto out_iounmap_slim; + } /* Allocate memory for SLI-2 structures */ phba->slim2p = dma_alloc_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE, @@ -1643,6 +1657,7 @@ out_free_slim: phba->slim2p_mapping); out_iounmap: iounmap(phba->ctrl_regs_memmap_p); +out_iounmap_slim: iounmap(phba->slim_memmap_p); out_idr_remove: idr_remove(&lpfc_hba_index, phba->brd_no); -- cgit v1.2.3 From 7f0b5b1913ba20ae035adbaeca176e78a53fa7a8 Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Tue, 28 Feb 2006 19:25:24 -0500 Subject: [SCSI] lpfc 8.1.2: Correct use of the hostdata field in scsi_host Correct use of the hostdata field in scsi_host Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 64 +++++++++++++++++++++---------------------- drivers/scsi/lpfc/lpfc_init.c | 3 +- drivers/scsi/lpfc/lpfc_scsi.c | 14 +++++----- 3 files changed, 40 insertions(+), 41 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b897e522a966..c8fb43d60882 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -79,7 +79,7 @@ static ssize_t lpfc_serialnum_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); } @@ -87,7 +87,7 @@ static ssize_t lpfc_modeldesc_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); } @@ -95,7 +95,7 @@ static ssize_t lpfc_modelname_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); } @@ -103,7 +103,7 @@ static ssize_t lpfc_programtype_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); } @@ -111,7 +111,7 @@ static ssize_t lpfc_portnum_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); } @@ -119,7 +119,7 @@ static ssize_t lpfc_fwrev_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; char fwrev[32]; lpfc_decode_firmware_rev(phba, fwrev, 1); return snprintf(buf, PAGE_SIZE, "%s\n",fwrev); @@ -130,7 +130,7 @@ lpfc_hdw_show(struct class_device *cdev, char *buf) { char hdw[9]; struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; lpfc_vpd_t *vp = &phba->vpd; lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); return snprintf(buf, PAGE_SIZE, "%s\n", hdw); @@ -139,14 +139,14 @@ static ssize_t lpfc_option_rom_version_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); } static ssize_t lpfc_state_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; int len = 0; switch (phba->hba_state) { case LPFC_INIT_START: @@ -194,7 +194,7 @@ static ssize_t lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt + phba->fc_unmap_cnt); } @@ -203,7 +203,7 @@ lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf) static int lpfc_issue_lip(struct Scsi_Host *host) { - struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata; LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; @@ -235,7 +235,7 @@ static ssize_t lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); } @@ -243,7 +243,7 @@ static ssize_t lpfc_board_online_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; if (phba->fc_flag & FC_OFFLINE_MODE) return snprintf(buf, PAGE_SIZE, "0\n"); @@ -256,7 +256,7 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; struct completion online_compl; int val=0, status=0; @@ -282,7 +282,7 @@ static ssize_t lpfc_poll_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll); } @@ -292,7 +292,7 @@ lpfc_poll_store(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; uint32_t creg_val; uint32_t old_val; int val=0; @@ -349,7 +349,7 @@ static ssize_t \ lpfc_##attr##_show(struct class_device *cdev, char *buf) \ { \ struct Scsi_Host *host = class_to_shost(cdev);\ - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\ int val = 0;\ val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ @@ -361,7 +361,7 @@ static ssize_t \ lpfc_##attr##_show(struct class_device *cdev, char *buf) \ { \ struct Scsi_Host *host = class_to_shost(cdev);\ - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\ int val = 0;\ val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%#x\n",\ @@ -404,7 +404,7 @@ static ssize_t \ lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \ { \ struct Scsi_Host *host = class_to_shost(cdev);\ - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\ int val=0;\ if (!isdigit(buf[0]))\ return -EINVAL;\ @@ -685,7 +685,7 @@ sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count) size_t buf_off; struct Scsi_Host *host = class_to_shost(container_of(kobj, struct class_device, kobj)); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; if ((off + count) > FF_REG_AREA_SIZE) return -ERANGE; @@ -718,7 +718,7 @@ sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count) uint32_t * tmp_ptr; struct Scsi_Host *host = class_to_shost(container_of(kobj, struct class_device, kobj)); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; if (off > FF_REG_AREA_SIZE) return -ERANGE; @@ -773,7 +773,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct Scsi_Host * host = class_to_shost(container_of(kobj, struct class_device, kobj)); - struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata; struct lpfcMboxq * mbox = NULL; if ((count + off) > MAILBOX_CMD_SIZE) @@ -826,7 +826,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) struct Scsi_Host *host = class_to_shost(container_of(kobj, struct class_device, kobj)); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; int rc; if (off > sizeof(MAILBOX_t)) @@ -1001,7 +1001,7 @@ lpfc_free_sysfs_attr(struct lpfc_hba *phba) static void lpfc_get_host_port_id(struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata; /* note: fc_myDID already in cpu endianness */ fc_host_port_id(shost) = phba->fc_myDID; } @@ -1009,7 +1009,7 @@ lpfc_get_host_port_id(struct Scsi_Host *shost) static void lpfc_get_host_port_type(struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata; spin_lock_irq(shost->host_lock); @@ -1034,7 +1034,7 @@ lpfc_get_host_port_type(struct Scsi_Host *shost) static void lpfc_get_host_port_state(struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata; spin_lock_irq(shost->host_lock); @@ -1075,7 +1075,7 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) static void lpfc_get_host_speed(struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata; spin_lock_irq(shost->host_lock); @@ -1102,7 +1102,7 @@ lpfc_get_host_speed(struct Scsi_Host *shost) static void lpfc_get_host_fabric_name (struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata; u64 node_name; spin_lock_irq(shost->host_lock); @@ -1124,7 +1124,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) static struct fc_host_statistics * lpfc_get_stats(struct Scsi_Host *shost) { - struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_sli *psli = &phba->sli; struct fc_host_statistics *hs = &phba->link_stats; LPFC_MBOXQ_t *pmboxq; @@ -1214,7 +1214,7 @@ static void lpfc_get_starget_port_id(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; uint32_t did = -1; struct lpfc_nodelist *ndlp = NULL; @@ -1235,7 +1235,7 @@ static void lpfc_get_starget_node_name(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; u64 node_name = 0; struct lpfc_nodelist *ndlp = NULL; @@ -1256,7 +1256,7 @@ static void lpfc_get_starget_port_name(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; u64 port_name = 0; struct lpfc_nodelist *ndlp = NULL; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 369487e8f450..5e92c451f96e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1553,7 +1553,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list); host->transportt = lpfc_transport_template; - host->hostdata[0] = (unsigned long)phba; pci_set_drvdata(pdev, host); error = scsi_add_host(host, &pdev->dev); if (error) @@ -1675,7 +1674,7 @@ static void __devexit lpfc_pci_remove_one(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); - struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; unsigned long iflag; lpfc_free_sysfs_attr(phba); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index dafabeefc5b3..fd7540ea4e19 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -743,7 +743,7 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) const char * lpfc_info(struct Scsi_Host *host) { - struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata; int len; static char lpfcinfobuf[384]; @@ -803,7 +803,7 @@ static int lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) { struct lpfc_hba *phba = - (struct lpfc_hba *) cmnd->device->host->hostdata[0]; + (struct lpfc_hba *) cmnd->device->host->hostdata; struct lpfc_sli *psli = &phba->sli; struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; @@ -877,7 +877,7 @@ static int lpfc_abort_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring]; struct lpfc_iocbq *iocb; struct lpfc_iocbq *abtsiocb; @@ -981,7 +981,7 @@ static int lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_scsi_buf *lpfc_cmd; struct lpfc_iocbq *iocbq, *iocbqrsp; struct lpfc_rport_data *rdata = cmnd->device->hostdata; @@ -1094,7 +1094,7 @@ static int lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_nodelist *ndlp = NULL; int match; int ret = FAILED, i, err_count = 0; @@ -1195,7 +1195,7 @@ out: static int lpfc_slave_alloc(struct scsi_device *sdev) { - struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata; struct lpfc_scsi_buf *scsi_buf = NULL; struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); uint32_t total = 0, i; @@ -1251,7 +1251,7 @@ lpfc_slave_alloc(struct scsi_device *sdev) static int lpfc_slave_configure(struct scsi_device *sdev) { - struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata[0]; + struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata; struct fc_rport *rport = starget_to_rport(sdev->sdev_target); if (sdev->tagged_supported) -- cgit v1.2.3 From 41415862a23f422b80eccc92cf885935139e2415 Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Tue, 28 Feb 2006 19:25:27 -0500 Subject: [SCSI] lpfc 8.1.2: Add ERROR and WARM_START modes for diagnostic purposes. Add ERROR and WARM_START modes for diagnostic purposes. Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 34 +++-- drivers/scsi/lpfc/lpfc_attr.c | 64 +++++++- drivers/scsi/lpfc/lpfc_crtn.h | 9 +- drivers/scsi/lpfc/lpfc_disc.h | 18 ++- drivers/scsi/lpfc/lpfc_hbadisc.c | 32 +++- drivers/scsi/lpfc/lpfc_hw.h | 4 +- drivers/scsi/lpfc/lpfc_init.c | 57 +++++-- drivers/scsi/lpfc/lpfc_mbox.c | 13 +- drivers/scsi/lpfc/lpfc_sli.c | 311 +++++++++++++++++++++++++-------------- 9 files changed, 390 insertions(+), 152 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 214ab436e035..c4cca9124f45 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -175,25 +175,27 @@ struct lpfc_hba { uint16_t pci_cfg_value; struct semaphore hba_can_block; - uint32_t hba_state; - -#define LPFC_INIT_START 1 /* Initial state after board reset */ -#define LPFC_INIT_MBX_CMDS 2 /* Initialize HBA with mbox commands */ -#define LPFC_LINK_DOWN 3 /* HBA initialized, link is down */ -#define LPFC_LINK_UP 4 /* Link is up - issue READ_LA */ -#define LPFC_LOCAL_CFG_LINK 5 /* local NPORT Id configured */ -#define LPFC_FLOGI 6 /* FLOGI sent to Fabric */ -#define LPFC_FABRIC_CFG_LINK 7 /* Fabric assigned NPORT Id + int32_t hba_state; + +#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */ +#define LPFC_WARM_START 1 /* HBA state after selective reset */ +#define LPFC_INIT_START 2 /* Initial state after board reset */ +#define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */ +#define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */ +#define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */ +#define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */ +#define LPFC_FLOGI 7 /* FLOGI sent to Fabric */ +#define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id configured */ -#define LPFC_NS_REG 8 /* Register with NameServer */ -#define LPFC_NS_QRY 9 /* Query NameServer for NPort ID list */ -#define LPFC_BUILD_DISC_LIST 10 /* Build ADISC and PLOGI lists for +#define LPFC_NS_REG 9 /* Register with NameServer */ +#define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */ +#define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for * device authentication / discovery */ -#define LPFC_DISC_AUTH 11 /* Processing ADISC list */ -#define LPFC_CLEAR_LA 12 /* authentication cmplt - issue +#define LPFC_DISC_AUTH 12 /* Processing ADISC list */ +#define LPFC_CLEAR_LA 13 /* authentication cmplt - issue CLEAR_LA */ #define LPFC_HBA_READY 32 -#define LPFC_HBA_ERROR 0xff +#define LPFC_HBA_ERROR -1 uint8_t fc_linkspeed; /* Link speed after last READ_LA */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c8fb43d60882..e7aca3c4b26e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -149,6 +149,8 @@ lpfc_state_show(struct class_device *cdev, char *buf) struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; int len = 0; switch (phba->hba_state) { + case LPFC_STATE_UNKNOWN: + case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: @@ -278,6 +280,58 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf, return -EIO; } +static ssize_t +lpfc_board_mode_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + char * state; + + if (phba->hba_state == LPFC_HBA_ERROR) + state = "error"; + else if (phba->hba_state == LPFC_WARM_START) + state = "warm start"; + else if (phba->hba_state == LPFC_INIT_START) + state = "offline"; + else + state = "online"; + + return snprintf(buf, PAGE_SIZE, "%s\n", state); +} + +static ssize_t +lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) +{ + struct Scsi_Host *host = class_to_shost(cdev); + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + struct completion online_compl; + int status=0; + + init_completion(&online_compl); + + if(strncmp(buf, "online", sizeof("online") - 1) == 0) + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_OFFLINE); + else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_WARM_START); + else if (strncmp(buf, "error", sizeof("error") - 1) == 0) + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_KILL); + else + return -EINVAL; + + wait_for_completion(&online_compl); + + if (!status) + return strlen(buf); + else + return -EIO; +} + static ssize_t lpfc_poll_show(struct class_device *cdev, char *buf) { @@ -480,6 +534,8 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, NULL); static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, lpfc_board_online_show, lpfc_board_online_store); +static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, + lpfc_board_mode_show, lpfc_board_mode_store); static int lpfc_poll = 0; module_param(lpfc_poll, int, 0); @@ -674,6 +730,7 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_nport_evt_cnt, &class_device_attr_management_version, &class_device_attr_board_online, + &class_device_attr_board_mode, &class_device_attr_lpfc_poll, &class_device_attr_lpfc_poll_tmo, NULL, @@ -883,8 +940,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) case MBX_DUMP_MEMORY: case MBX_DOWN_LOAD: case MBX_UPDATE_CFG: + case MBX_KILL_BOARD: case MBX_LOAD_AREA: case MBX_LOAD_EXP_ROM: + case MBX_BEACON: + case MBX_DEL_LD_ENTRY: break; case MBX_READ_SPARM64: case MBX_READ_LA: @@ -1042,6 +1102,8 @@ lpfc_get_host_port_state(struct Scsi_Host *shost) fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; else { switch (phba->hba_state) { + case LPFC_STATE_UNKNOWN: + case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 0ae49811b916..cafddf2f1af8 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -107,6 +107,7 @@ void lpfc_fdmi_tmo_handler(struct lpfc_hba *); int lpfc_config_port_prep(struct lpfc_hba *); int lpfc_config_port_post(struct lpfc_hba *); int lpfc_hba_down_prep(struct lpfc_hba *); +int lpfc_hba_down_post(struct lpfc_hba *); void lpfc_hba_init(struct lpfc_hba *, uint32_t *); int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); @@ -123,6 +124,7 @@ irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *); void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); @@ -135,6 +137,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); + +int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); +int lpfc_sli_brdkill(struct lpfc_hba *); +int lpfc_sli_brdreset(struct lpfc_hba *); +int lpfc_sli_brdrestart(struct lpfc_hba *); int lpfc_sli_hba_setup(struct lpfc_hba *); int lpfc_sli_hba_down(struct lpfc_hba *); int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index ed6c81660e03..4dfcd4eda2fc 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -28,18 +28,24 @@ * This is used by Fibre Channel protocol to support FCP. */ +/* worker thread events */ +enum lpfc_work_type { + LPFC_EVT_NODEV_TMO, + LPFC_EVT_ONLINE, + LPFC_EVT_OFFLINE, + LPFC_EVT_WARM_START, + LPFC_EVT_KILL, + LPFC_EVT_ELS_RETRY, +}; + /* structure used to queue event to the discovery tasklet */ struct lpfc_work_evt { struct list_head evt_listp; void * evt_arg1; void * evt_arg2; - uint32_t evt; + enum lpfc_work_type evt; }; -#define LPFC_EVT_NODEV_TMO 0x1 -#define LPFC_EVT_ONLINE 0x2 -#define LPFC_EVT_OFFLINE 0x3 -#define LPFC_EVT_ELS_RETRY 0x4 struct lpfc_nodelist { struct list_head nlp_listp; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 5c396171ebe8..55454923029d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -120,11 +120,33 @@ lpfc_work_list_done(struct lpfc_hba * phba) free_evt = 0; break; case LPFC_EVT_ONLINE: - *(int *)(evtp->evt_arg1) = lpfc_online(phba); + if (phba->hba_state < LPFC_LINK_DOWN) + *(int *)(evtp->evt_arg1) = lpfc_online(phba); + else + *(int *)(evtp->evt_arg1) = 0; complete((struct completion *)(evtp->evt_arg2)); break; case LPFC_EVT_OFFLINE: - *(int *)(evtp->evt_arg1) = lpfc_offline(phba); + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + *(int *)(evtp->evt_arg1) = + lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY); + complete((struct completion *)(evtp->evt_arg2)); + break; + case LPFC_EVT_WARM_START: + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + lpfc_sli_brdreset(phba); + lpfc_hba_down_post(phba); + *(int *)(evtp->evt_arg1) = + lpfc_sli_brdready(phba, HS_MBRDY); + complete((struct completion *)(evtp->evt_arg2)); + break; + case LPFC_EVT_KILL: + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + *(int *)(evtp->evt_arg1) = lpfc_sli_brdkill(phba); complete((struct completion *)(evtp->evt_arg2)); break; } @@ -287,6 +309,10 @@ lpfc_linkdown(struct lpfc_hba * phba) LPFC_MBOXQ_t *mb; int rc, i; + if (phba->hba_state == LPFC_LINK_DOWN) { + return 0; + } + psli = &phba->sli; /* sysfs or selective reset may call this routine to clean up */ diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index e613dd07d2ad..98d39cea7954 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -1233,7 +1233,9 @@ typedef struct { /* FireFly BIU registers */ #define MBX_SET_MASK 0x20 #define MBX_SET_SLIM 0x21 #define MBX_UNREG_D_ID 0x23 +#define MBX_KILL_BOARD 0x24 #define MBX_CONFIG_FARP 0x25 +#define MBX_BEACON 0x2A #define MBX_LOAD_AREA 0x81 #define MBX_RUN_BIU_DIAG64 0x84 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5e92c451f96e..391ca50293f2 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -459,9 +459,45 @@ lpfc_hba_down_prep(struct lpfc_hba * phba) lpfc_els_flush_cmd(phba); lpfc_disc_flush_list(phba); + /* Disable SLI2 since we disabled interrupts */ + phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; return (0); } +/************************************************************************/ +/* */ +/* lpfc_hba_down_post */ +/* This routine will do uninitialization after the HBA is reset */ +/* when bringing down the SLI Layer. */ +/* This routine returns 0 on success. Any other return value */ +/* indicates an error. */ +/* */ +/************************************************************************/ +int +lpfc_hba_down_post(struct lpfc_hba * phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + struct lpfc_dmabuf *mp, *next_mp; + int i; + + /* Cleanup preposted buffers on the ELS ring */ + pring = &psli->ring[LPFC_ELS_RING]; + list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { + list_del(&mp->list); + pring->postbufq_cnt--; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + + for (i = 0; i < psli->num_rings; i++) { + pring = &psli->ring[i]; + lpfc_sli_abort_iocb_ring(phba, pring); + } + + return 0; +} + /************************************************************************/ /* */ /* lpfc_handle_eratt */ @@ -476,20 +512,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - /* - * If a reset is sent to the HBA restore PCI configuration registers. - */ - if ( phba->hba_state == LPFC_INIT_START ) { - mdelay(1); - readl(phba->HCregaddr); /* flush */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - - /* Restore PCI cmd register */ - pci_write_config_word(phba->pcidev, - PCI_COMMAND, phba->pci_cfg_value); - } - if (phba->work_hs & HS_FFER6) { /* Re-establishing Link */ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, @@ -516,6 +538,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba) * attempt to restart it. */ lpfc_offline(phba); + lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { /* Initialize the HBA */ mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); return; @@ -532,7 +555,8 @@ lpfc_handle_eratt(struct lpfc_hba * phba) phba->work_status[0], phba->work_status[1]); lpfc_offline(phba); - + phba->hba_state = LPFC_HBA_ERROR; + lpfc_hba_down_post(phba); } } @@ -1695,6 +1719,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) * the HBA. */ lpfc_sli_hba_down(phba); + lpfc_sli_brdrestart(phba); /* Release the irq reservation */ free_irq(phba->pcidev->irq, phba); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 6c4b21a32c7f..df88b78707de 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -636,6 +636,17 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) phba->brd_no); } +void +lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +{ + MAILBOX_t *mb = &pmb->mb; + + memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); + mb->mbxCommand = MBX_KILL_BOARD; + mb->mbxOwner = OWN_HOST; + return; +} + void lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1f876328b44b..d6ffe26ae123 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -513,7 +513,9 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_SET_MASK: case MBX_SET_SLIM: case MBX_UNREG_D_ID: + case MBX_KILL_BOARD: case MBX_CONFIG_FARP: + case MBX_BEACON: case MBX_LOAD_AREA: case MBX_RUN_BIU_DIAG64: case MBX_CONFIG_PORT: @@ -1512,98 +1514,162 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return errcnt; } -/****************************************************************************** -* lpfc_sli_send_reset -* -* Note: After returning from this function, the HBA cannot be accessed for -* 1 ms. Since we do not wish to delay in interrupt context, it is the -* responsibility of the caller to perform the mdelay(1) and flush via readl(). -******************************************************************************/ -static int -lpfc_sli_send_reset(struct lpfc_hba * phba, uint16_t skip_post) +int +lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask) { - MAILBOX_t *swpmb; - volatile uint32_t word0; - void __iomem *to_slim; - unsigned long flags = 0; + uint32_t status; + int i = 0; + int retval = 0; - spin_lock_irqsave(phba->host->host_lock, flags); + /* Read the HBA Host Status Register */ + status = readl(phba->HSregaddr); - /* A board reset must use REAL SLIM. */ - phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; + /* + * Check status register every 100ms for 5 retries, then every + * 500ms for 5, then every 2.5 sec for 5, then reset board and + * every 2.5 sec for 4. + * Break our of the loop if errors occurred during init. + */ + while (((status & mask) != mask) && + !(status & HS_FFERM) && + i++ < 20) { - word0 = 0; - swpmb = (MAILBOX_t *) & word0; - swpmb->mbxCommand = MBX_RESTART; - swpmb->mbxHc = 1; + if (i <= 5) + msleep(10); + else if (i <= 10) + msleep(500); + else + msleep(2500); - to_slim = phba->MBslimaddr; - writel(*(uint32_t *) swpmb, to_slim); - readl(to_slim); /* flush */ + if (i == 15) { + phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */ + lpfc_sli_brdrestart(phba); + } + /* Read the HBA Host Status Register */ + status = readl(phba->HSregaddr); + } - /* Only skip post after fc_ffinit is completed */ - if (skip_post) { - word0 = 1; /* This is really setting up word1 */ - } else { - word0 = 0; /* This is really setting up word1 */ + /* Check to see if any errors occurred during init */ + if ((status & HS_FFERM) || (i >= 20)) { + phba->hba_state = LPFC_HBA_ERROR; + retval = 1; } - to_slim = phba->MBslimaddr + sizeof (uint32_t); - writel(*(uint32_t *) swpmb, to_slim); - readl(to_slim); /* flush */ - /* Turn off parity checking and serr during the physical reset */ - pci_read_config_word(phba->pcidev, PCI_COMMAND, &phba->pci_cfg_value); - pci_write_config_word(phba->pcidev, PCI_COMMAND, - (phba->pci_cfg_value & - ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); + return retval; +} - writel(HC_INITFF, phba->HCregaddr); +int +lpfc_sli_brdkill(struct lpfc_hba * phba) +{ + struct lpfc_sli *psli; + LPFC_MBOXQ_t *pmb; + uint32_t status; + uint32_t ha_copy; + int retval; + int i = 0; - phba->hba_state = LPFC_INIT_START; - spin_unlock_irqrestore(phba->host->host_lock, flags); + psli = &phba->sli; - return 0; + /* Kill HBA */ + lpfc_printf_log(phba, + KERN_INFO, + LOG_SLI, + "%d:0329 Kill HBA Data: x%x x%x\n", + phba->brd_no, + phba->hba_state, + psli->sli_flag); + + if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, + GFP_ATOMIC)) == 0) { + return 1; + } + + /* Disable the error attention */ + spin_lock_irq(phba->host->host_lock); + status = readl(phba->HCregaddr); + status &= ~HC_ERINT_ENA; + writel(status, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + spin_unlock_irq(phba->host->host_lock); + + lpfc_kill_board(phba, pmb); + pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + + if (retval != MBX_SUCCESS) { + if (retval != MBX_BUSY) + mempool_free(pmb, phba->mbox_mem_pool); + return 1; + } + + mempool_free(pmb, phba->mbox_mem_pool); + + /* There is no completion for a KILL_BOARD mbox cmd. Check for an error + * attention every 100ms for 3 seconds. If we don't get ERATT after + * 3 seconds we still set HBA_ERROR state because the status of the + * board is now undefined. + */ + ha_copy = readl(phba->HAregaddr); + + while ((i++ < 30) && !(ha_copy & HA_ERATT)) { + mdelay(100); + ha_copy = readl(phba->HAregaddr); + } + + del_timer_sync(&psli->mbox_tmo); + + spin_lock_irq(phba->host->host_lock); + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(phba->host->host_lock); + + psli->mbox_active = NULL; + lpfc_hba_down_post(phba); + phba->hba_state = LPFC_HBA_ERROR; + + return (ha_copy & HA_ERATT ? 0 : 1); } -static int -lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post) +int +lpfc_sli_brdreset(struct lpfc_hba * phba) { + struct lpfc_sli *psli; struct lpfc_sli_ring *pring; + uint16_t cfg_value; int i; - struct lpfc_dmabuf *mp, *next_mp; - unsigned long flags = 0; - - lpfc_sli_send_reset(phba, skip_post); - mdelay(1); - spin_lock_irqsave(phba->host->host_lock, flags); - /* Risk the write on flush case ie no delay after the readl */ - readl(phba->HCregaddr); /* flush */ - /* Now toggle INITFF bit set by lpfc_sli_send_reset */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ + psli = &phba->sli; - /* Restore PCI cmd register */ - pci_write_config_word(phba->pcidev, PCI_COMMAND, phba->pci_cfg_value); + /* Reset HBA */ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no, + phba->hba_state, psli->sli_flag); /* perform board reset */ phba->fc_eventTag = 0; phba->fc_myDID = 0; - phba->fc_prevDID = Mask_DID; + phba->fc_prevDID = 0; - /* Reset HBA */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_SLI, - "%d:0325 Reset HBA Data: x%x x%x x%x\n", - phba->brd_no, - phba->hba_state, - phba->sli.sli_flag, - skip_post); + psli->sli_flag = 0; + + /* Turn off parity checking and serr during the physical reset */ + pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); + pci_write_config_word(phba->pcidev, PCI_COMMAND, + (cfg_value & + ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); + + /* Now toggle INITFF bit in the Host Control Register */ + writel(HC_INITFF, phba->HCregaddr); + mdelay(1); + readl(phba->HCregaddr); /* flush */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + + /* Restore PCI cmd register */ + pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); /* Initialize relevant SLI info */ - for (i = 0; i < phba->sli.num_rings; i++) { - pring = &phba->sli.ring[i]; + for (i = 0; i < psli->num_rings; i++) { + pring = &psli->ring[i]; pring->flag = 0; pring->rspidx = 0; pring->next_cmdidx = 0; @@ -1611,27 +1677,62 @@ lpfc_sli_brdreset(struct lpfc_hba * phba, uint16_t skip_post) pring->cmdidx = 0; pring->missbufcnt = 0; } - spin_unlock_irqrestore(phba->host->host_lock, flags); - if (skip_post) { - mdelay(100); + phba->hba_state = LPFC_WARM_START; + return 0; +} + +int +lpfc_sli_brdrestart(struct lpfc_hba * phba) +{ + MAILBOX_t *mb; + struct lpfc_sli *psli; + uint16_t skip_post; + volatile uint32_t word0; + void __iomem *to_slim; + + spin_lock_irq(phba->host->host_lock); + + psli = &phba->sli; + + /* Restart HBA */ + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no, + phba->hba_state, psli->sli_flag); + + word0 = 0; + mb = (MAILBOX_t *) &word0; + mb->mbxCommand = MBX_RESTART; + mb->mbxHc = 1; + + to_slim = phba->MBslimaddr; + writel(*(uint32_t *) mb, to_slim); + readl(to_slim); /* flush */ + + /* Only skip post after fc_ffinit is completed */ + if (phba->hba_state) { + skip_post = 1; + word0 = 1; /* This is really setting up word1 */ } else { - mdelay(2000); + skip_post = 0; + word0 = 0; /* This is really setting up word1 */ } + to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t); + writel(*(uint32_t *) mb, to_slim); + readl(to_slim); /* flush */ - spin_lock_irqsave(phba->host->host_lock, flags); - /* Cleanup preposted buffers on the ELS ring */ - pring = &phba->sli.ring[LPFC_ELS_RING]; - list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { - list_del(&mp->list); - pring->postbufq_cnt--; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - spin_unlock_irqrestore(phba->host->host_lock, flags); + lpfc_sli_brdreset(phba); - for (i = 0; i < phba->sli.num_rings; i++) - lpfc_sli_abort_iocb_ring(phba, &phba->sli.ring[i]); + phba->hba_state = LPFC_INIT_START; + + spin_unlock_irq(phba->host->host_lock); + + if (skip_post) + mdelay(100); + else + mdelay(2000); + + lpfc_hba_down_post(phba); return 0; } @@ -1691,7 +1792,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) } if (i == 15) { - lpfc_sli_brdreset(phba, 0); + phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */ + lpfc_sli_brdrestart(phba); } /* Read the HBA Host Status Register */ status = readl(phba->HSregaddr); @@ -1735,8 +1837,8 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) } while (resetcount < 2 && !done) { - phba->hba_state = 0; - lpfc_sli_brdreset(phba, 0); + phba->hba_state = LPFC_STATE_UNKNOWN; + lpfc_sli_brdrestart(phba); msleep(2500); rc = lpfc_sli_chipset_init(phba); if (rc) @@ -1920,6 +2022,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) mb = &pmbox->mb; status = MBX_SUCCESS; + if (phba->hba_state == LPFC_HBA_ERROR) { + spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); + + /* Mbox command cannot issue */ + LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) + return (MBX_NOT_FINISHED); + } + if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { /* Polling for a mbox command when another one is already active * is not allowed in SLI. Also, the driver must have established @@ -2002,7 +2112,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* If we are not polling, we MUST be in SLI2 mode */ if (flag != MBX_POLL) { - if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { + if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) && + (mb->mbxCommand != MBX_KILL_BOARD)) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); @@ -2035,7 +2146,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* First copy command data to host SLIM area */ lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); } else { - if (mb->mbxCommand == MBX_CONFIG_PORT) { + if (mb->mbxCommand == MBX_CONFIG_PORT || + mb->mbxCommand == MBX_KILL_BOARD) { /* copy command data into host mbox for cmpl */ lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); @@ -2086,8 +2198,9 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) ha_copy = readl(phba->HAregaddr); /* Wait for command to complete */ - while (((word0 & OWN_CHIP) == OWN_CHIP) - || !(ha_copy & HA_MBATT)) { + while (((word0 & OWN_CHIP) == OWN_CHIP) || + (!(ha_copy & HA_MBATT) && + (phba->hba_state > LPFC_WARM_START))) { if (i++ >= 100) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(phba->host->host_lock, @@ -2455,15 +2568,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) spin_unlock_irqrestore(phba->host->host_lock, flags); - /* - * Provided the hba is not in an error state, reset it. It is not - * capable of IO anymore. - */ - if (phba->hba_state != LPFC_HBA_ERROR) { - phba->hba_state = LPFC_INIT_START; - lpfc_sli_brdreset(phba, 1); - } - return 1; } @@ -2976,13 +3080,6 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) /* Clear Chip error bit */ writel(HA_ERATT, phba->HAregaddr); readl(phba->HAregaddr); /* flush */ - - /* - * Reseting the HBA is the only reliable way - * to shutdown interrupt when there is a - * ERROR. - */ - lpfc_sli_send_reset(phba, 1); } spin_lock(phba->host->host_lock); -- cgit v1.2.3 From 74b72a59b8d42d31aa6ffac8f10ca7a784be392c Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Tue, 28 Feb 2006 22:33:04 -0500 Subject: [PATCH] lpfc 8.1.3: Derive supported speeds from LMT field in the READ_CONFIG Derive supported speeds from LMT field in the READ_CONFIG Driver was keying off internal cores. Use what the firmware reports instead. Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_ct.c | 24 +++--- drivers/scsi/lpfc/lpfc_hw.h | 14 ++-- drivers/scsi/lpfc/lpfc_init.c | 182 +++++++++++++++++++++++++----------------- 3 files changed, 126 insertions(+), 94 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 0c982bbc4c77..f3b280313a74 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1014,19 +1014,19 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED); ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - if (FC_JEDEC_ID(vp->rev.biuRev) == VIPER_JEDEC_ID) + + ae->un.SupportSpeed = 0; + if (phba->lmt & LMT_10Gb) ae->un.SupportSpeed = HBA_PORTSPEED_10GBIT; - else if (FC_JEDEC_ID(vp->rev.biuRev) == HELIOS_JEDEC_ID) - ae->un.SupportSpeed = HBA_PORTSPEED_4GBIT; - else if ((FC_JEDEC_ID(vp->rev.biuRev) == - CENTAUR_2G_JEDEC_ID) - || (FC_JEDEC_ID(vp->rev.biuRev) == - PEGASUS_JEDEC_ID) - || (FC_JEDEC_ID(vp->rev.biuRev) == - THOR_JEDEC_ID)) - ae->un.SupportSpeed = HBA_PORTSPEED_2GBIT; - else - ae->un.SupportSpeed = HBA_PORTSPEED_1GBIT; + if (phba->lmt & LMT_8Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT; + if (phba->lmt & LMT_4Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT; + if (phba->lmt & LMT_2Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT; + if (phba->lmt & LMT_1Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT; + pab->ab.EntryCnt++; size += FOURBYTES + 4; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 98d39cea7954..54d04188f7cc 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1711,13 +1711,13 @@ typedef struct { uint32_t rttov; uint32_t altov; uint32_t lmt; -#define LMT_RESERVED 0x0 /* Not used */ -#define LMT_266_10bit 0x1 /* 265.625 Mbaud 10 bit iface */ -#define LMT_532_10bit 0x2 /* 531.25 Mbaud 10 bit iface */ -#define LMT_1063_20bit 0x3 /* 1062.5 Mbaud 20 bit iface */ -#define LMT_1063_10bit 0x4 /* 1062.5 Mbaud 10 bit iface */ -#define LMT_2125_10bit 0x8 /* 2125 Mbaud 10 bit iface */ -#define LMT_4250_10bit 0x40 /* 4250 Mbaud 10 bit iface */ +#define LMT_RESERVED 0x000 /* Not used */ +#define LMT_1Gb 0x004 +#define LMT_2Gb 0x008 +#define LMT_4Gb 0x040 +#define LMT_8Gb 0x080 +#define LMT_10Gb 0x100 + uint32_t rsvd2; uint32_t rsvd3; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 391ca50293f2..5fd98a345347 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -42,7 +42,7 @@ #include "lpfc_crtn.h" #include "lpfc_version.h" -static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *); +static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); static int lpfc_post_rcv_buf(struct lpfc_hba *); @@ -161,9 +161,6 @@ lpfc_config_port_prep(struct lpfc_hba * phba) memcpy(phba->RandomData, (char *)&mb->un.varWords[24], sizeof (phba->RandomData)); - /* Get the default values for Model Name and Description */ - lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - /* Get adapter VPD information */ pmb->context2 = kmalloc(DMP_RSP_SIZE, GFP_KERNEL); if (!pmb->context2) @@ -182,16 +179,15 @@ lpfc_config_port_prep(struct lpfc_hba * phba) "mbxCmd x%x DUMP VPD, mbxStatus x%x\n", phba->brd_no, mb->mbxCommand, mb->mbxStatus); - kfree(lpfc_vpd_data); - lpfc_vpd_data = NULL; - break; + mb->un.varDmp.word_cnt = 0; } - + if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) + mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset, mb->un.varDmp.word_cnt); offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt); - lpfc_parse_vpd(phba, lpfc_vpd_data); + } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); + lpfc_parse_vpd(phba, lpfc_vpd_data, offset); kfree(lpfc_vpd_data); out_free_context2: @@ -327,13 +323,22 @@ lpfc_config_port_post(struct lpfc_hba * phba) mb->un.varRdConfig.max_xri + 1; phba->lmt = mb->un.varRdConfig.lmt; - /* HBA is not 4GB capable, or HBA is not 2GB capable, - don't let link speed ask for it */ - if ((((phba->lmt & LMT_4250_10bit) != LMT_4250_10bit) && - (phba->cfg_link_speed > LINK_SPEED_2G)) || - (((phba->lmt & LMT_2125_10bit) != LMT_2125_10bit) && - (phba->cfg_link_speed > LINK_SPEED_1G))) { - /* Reset link speed to auto. 1G/2GB HBA cfg'd for 4G */ + + /* Get the default values for Model Name and Description */ + lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); + + if ((phba->cfg_link_speed > LINK_SPEED_10G) + || ((phba->cfg_link_speed == LINK_SPEED_1G) + && !(phba->lmt & LMT_1Gb)) + || ((phba->cfg_link_speed == LINK_SPEED_2G) + && !(phba->lmt & LMT_2Gb)) + || ((phba->cfg_link_speed == LINK_SPEED_4G) + && !(phba->lmt & LMT_4Gb)) + || ((phba->cfg_link_speed == LINK_SPEED_8G) + && !(phba->lmt & LMT_8Gb)) + || ((phba->cfg_link_speed == LINK_SPEED_10G) + && !(phba->lmt & LMT_10Gb))) { + /* Reset link speed to auto */ lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT, @@ -647,7 +652,7 @@ lpfc_handle_latt_err_exit: /* */ /************************************************************************/ static int -lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd) +lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len) { uint8_t lenlo, lenhi; uint32_t Length; @@ -666,9 +671,10 @@ lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd) phba->brd_no, (uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2], (uint32_t) vpd[3]); - do { + while (!finished && (index < (len - 4))) { switch (vpd[index]) { case 0x82: + case 0x91: index += 1; lenlo = vpd[index]; index += 1; @@ -684,7 +690,8 @@ lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd) lenhi = vpd[index]; index += 1; Length = ((((unsigned short)lenhi) << 8) + lenlo); - + if (Length > len - index) + Length = len - index; while (Length > 0) { /* Look for Serial Number */ if ((vpd[index] == 'S') && (vpd[index+1] == 'N')) { @@ -778,7 +785,7 @@ lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd) index ++; break; } - } while (!finished && (index < 108)); + } return(1); } @@ -790,124 +797,153 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) uint16_t dev_id = phba->pcidev->device; uint16_t dev_subid = phba->pcidev->subsystem_device; uint8_t hdrtype = phba->pcidev->hdr_type; - char *model_str = ""; + int max_speed; + char * ports = (hdrtype == 0x80) ? "2-port " : ""; + struct { + char * name; + int max_speed; + char * ports; + char * bus; + } m; + + if (mdp && mdp[0] != '\0' + && descp && descp[0] != '\0') + return; + + if (phba->lmt & LMT_10Gb) + max_speed = 10; + else if (phba->lmt & LMT_8Gb) + max_speed = 8; + else if (phba->lmt & LMT_4Gb) + max_speed = 4; + else if (phba->lmt & LMT_2Gb) + max_speed = 2; + else + max_speed = 1; vp = &phba->vpd; switch (dev_id) { case PCI_DEVICE_ID_FIREFLY: - model_str = "LP6000 1Gb PCI"; + m = (typeof(m)){"LP6000", max_speed, "", "PCI"}; break; case PCI_DEVICE_ID_SUPERFLY: if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) - model_str = "LP7000 1Gb PCI"; + m = (typeof(m)){"LP7000", max_speed, "", "PCI"}; else - model_str = "LP7000E 1Gb PCI"; + m = (typeof(m)){"LP7000E", max_speed, "", "PCI"}; break; case PCI_DEVICE_ID_DRAGONFLY: - model_str = "LP8000 1Gb PCI"; + m = (typeof(m)){"LP8000", max_speed, "", "PCI"}; break; case PCI_DEVICE_ID_CENTAUR: if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) - model_str = "LP9002 2Gb PCI"; + m = (typeof(m)){"LP9002", max_speed, "", "PCI"}; else - model_str = "LP9000 1Gb PCI"; + m = (typeof(m)){"LP9000", max_speed, "", "PCI"}; break; case PCI_DEVICE_ID_RFLY: - model_str = "LP952 2Gb PCI"; + m = (typeof(m)){"LP952", max_speed, "", "PCI"}; break; case PCI_DEVICE_ID_PEGASUS: - model_str = "LP9802 2Gb PCI-X"; + m = (typeof(m)){"LP9802", max_speed, "", "PCI-X"}; break; case PCI_DEVICE_ID_THOR: if (hdrtype == 0x80) - model_str = "LP10000DC 2Gb 2-port PCI-X"; + m = (typeof(m)){"LP10000DC", + max_speed, ports, "PCI-X"}; else - model_str = "LP10000 2Gb PCI-X"; + m = (typeof(m)){"LP10000", + max_speed, ports, "PCI-X"}; break; case PCI_DEVICE_ID_VIPER: - model_str = "LPX1000 10Gb PCI-X"; + m = (typeof(m)){"LPX1000", max_speed, "", "PCI-X"}; break; case PCI_DEVICE_ID_PFLY: - model_str = "LP982 2Gb PCI-X"; + m = (typeof(m)){"LP982", max_speed, "", "PCI-X"}; break; case PCI_DEVICE_ID_TFLY: if (hdrtype == 0x80) - model_str = "LP1050DC 2Gb 2-port PCI-X"; + m = (typeof(m)){"LP1050DC", max_speed, ports, "PCI-X"}; else - model_str = "LP1050 2Gb PCI-X"; + m = (typeof(m)){"LP1050", max_speed, ports, "PCI-X"}; break; case PCI_DEVICE_ID_HELIOS: if (hdrtype == 0x80) - model_str = "LP11002 4Gb 2-port PCI-X2"; + m = (typeof(m)){"LP11002", max_speed, ports, "PCI-X2"}; else - model_str = "LP11000 4Gb PCI-X2"; + m = (typeof(m)){"LP11000", max_speed, ports, "PCI-X2"}; break; case PCI_DEVICE_ID_HELIOS_SCSP: - model_str = "LP11000-SP 4Gb PCI-X2"; + m = (typeof(m)){"LP11000-SP", max_speed, ports, "PCI-X2"}; break; case PCI_DEVICE_ID_HELIOS_DCSP: - model_str = "LP11002-SP 4Gb 2-port PCI-X2"; + m = (typeof(m)){"LP11002-SP", max_speed, ports, "PCI-X2"}; break; case PCI_DEVICE_ID_NEPTUNE: if (hdrtype == 0x80) - model_str = "LPe1002 4Gb 2-port"; + m = (typeof(m)){"LPe1002", max_speed, ports, "PCIe"}; else - model_str = "LPe1000 4Gb PCIe"; + m = (typeof(m)){"LPe1000", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_NEPTUNE_SCSP: - model_str = "LPe1000-SP 4Gb PCIe"; + m = (typeof(m)){"LPe1000-SP", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_NEPTUNE_DCSP: - model_str = "LPe1002-SP 4Gb 2-port PCIe"; + m = (typeof(m)){"LPe1002-SP", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_BMID: - model_str = "LP1150 4Gb PCI-X2"; + m = (typeof(m)){"LP1150", max_speed, ports, "PCI-X2"}; break; case PCI_DEVICE_ID_BSMB: - model_str = "LP111 4Gb PCI-X2"; + m = (typeof(m)){"LP111", max_speed, ports, "PCI-X2"}; break; case PCI_DEVICE_ID_ZEPHYR: if (hdrtype == 0x80) - model_str = "LPe11002 4Gb 2-port PCIe"; + m = (typeof(m)){"LPe11002", max_speed, ports, "PCIe"}; else - model_str = "LPe11000 4Gb PCIe"; + m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_ZEPHYR_SCSP: - model_str = "LPe11000-SP 4Gb PCIe"; + m = (typeof(m)){"LPe11000", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - model_str = "LPe11002-SP 4Gb 2-port PCIe"; + m = (typeof(m)){"LPe11002-SP", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_ZMID: - model_str = "LPe1150 4Gb PCIe"; + m = (typeof(m)){"LPe1150", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_ZSMB: - model_str = "LPe111 4Gb PCIe"; + m = (typeof(m)){"LPe111", max_speed, ports, "PCIe"}; break; case PCI_DEVICE_ID_LP101: - model_str = "LP101 2Gb PCI-X"; + m = (typeof(m)){"LP101", max_speed, ports, "PCI-X"}; break; case PCI_DEVICE_ID_LP10000S: - model_str = "LP10000-S 2Gb PCI"; + m = (typeof(m)){"LP10000-S", max_speed, ports, "PCI"}; break; case PCI_DEVICE_ID_LP11000S: case PCI_DEVICE_ID_LPE11000S: switch (dev_subid) { case PCI_SUBSYSTEM_ID_LP11000S: - model_str = "LP11002-S 4Gb PCI-X2"; + m = (typeof(m)){"LP11000-S", max_speed, + ports, "PCI-X2"}; break; case PCI_SUBSYSTEM_ID_LP11002S: - model_str = "LP11000-S 4Gb 2-port PCI-X2"; + m = (typeof(m)){"LP11002-S", max_speed, + ports, "PCI-X2"}; break; case PCI_SUBSYSTEM_ID_LPE11000S: - model_str = "LPe11002-S 4Gb PCIe"; + m = (typeof(m)){"LPe11000-S", max_speed, + ports, "PCIe"}; break; case PCI_SUBSYSTEM_ID_LPE11002S: - model_str = "LPe11002-S 4Gb 2-port PCIe"; + m = (typeof(m)){"LPe11002-S", max_speed, + ports, "PCIe"}; break; case PCI_SUBSYSTEM_ID_LPE11010S: - model_str = "LPe11010-S 4Gb 10-port PCIe"; + m = (typeof(m)){"LPe11010-S", max_speed, + "10-port ", "PCIe"}; break; default: break; @@ -916,10 +952,13 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) default: break; } - if (mdp) - sscanf(model_str, "%s", mdp); - if (descp) - sprintf(descp, "Emulex %s Fibre Channel Adapter", model_str); + + if (mdp && mdp[0] == '\0') + snprintf(mdp, 79,"%s", m.name); + if (descp && descp[0] == '\0') + snprintf(descp, 255, + "Emulex %s %dGb %s%s Fibre Channel Adapter", + m.name, m.max_speed, m.ports, m.bus); } /**************************************************/ @@ -1627,21 +1666,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host)); fc_host_supported_speeds(host) = 0; - switch (FC_JEDEC_ID(phba->vpd.rev.biuRev)) { - case VIPER_JEDEC_ID: + if (phba->lmt & LMT_10Gb) fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT; - break; - case HELIOS_JEDEC_ID: + if (phba->lmt & LMT_4Gb) fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT; - /* Fall through */ - case CENTAUR_2G_JEDEC_ID: - case PEGASUS_JEDEC_ID: - case THOR_JEDEC_ID: + if (phba->lmt & LMT_2Gb) fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT; - /* Fall through */ - default: - fc_host_supported_speeds(host) = FC_PORTSPEED_1GBIT; - } + if (phba->lmt & LMT_1Gb) + fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT; fc_host_maxframe_size(host) = ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | -- cgit v1.2.3 From 719396b48ce6310ab43d7432b6d7f2a330a831b3 Mon Sep 17 00:00:00 2001 From: Jamie Wellnitz Date: Tue, 28 Feb 2006 22:33:05 -0500 Subject: [PATCH] lpfc 8.1.3: PCI hrd_type should be obtained with pci_read_config_byte() macro PCI hrd_type should be obtained with pci_read_config_byte() macro Driver keys off of this field to report the proper adapter type. The pci subsystem explicitly clears the multiport bit in the copy of the field given the driver. Thus, to properly name the card, obtain it from config space. Signed-off-by: Jamie Wellnitz Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5fd98a345347..71d2c8d3b001 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -796,9 +796,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) lpfc_vpd_t *vp; uint16_t dev_id = phba->pcidev->device; uint16_t dev_subid = phba->pcidev->subsystem_device; - uint8_t hdrtype = phba->pcidev->hdr_type; + uint8_t hdrtype; int max_speed; - char * ports = (hdrtype == 0x80) ? "2-port " : ""; + char * ports; struct { char * name; int max_speed; @@ -806,6 +806,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) char * bus; } m; + pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); + ports = (hdrtype == 0x80) ? "2-port " : ""; if (mdp && mdp[0] != '\0' && descp && descp[0] != '\0') return; -- cgit v1.2.3 From 286fc8f8ea7ef58b54f150fc900ce019af483e89 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 6 Mar 2006 10:20:56 -0600 Subject: [SCSI] lpfc: minor syntax fixes Stop gcc complaining about undefined variables Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_init.c | 2 ++ drivers/scsi/lpfc/lpfc_scsi.h | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 71d2c8d3b001..a2e15436730e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -948,10 +948,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) "10-port ", "PCIe"}; break; default: + m = (typeof(m)){ 0 }; break; } break; default: + m = (typeof(m)){ 0 }; break; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index acd64c49e849..cdcd2535803f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -23,10 +23,13 @@ struct lpfc_hba; #define list_remove_head(list, entry, type, member) \ + do { \ + entry = NULL; \ if (!list_empty(list)) { \ entry = list_entry((list)->next, type, member); \ list_del_init(&entry->member); \ - } + } \ + } while(0) #define list_get_first(list, type, member) \ (list_empty(list)) ? NULL : \ -- cgit v1.2.3 From 9290831f00879d4a66d3bffb609949d5ea5576fb Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 7 Mar 2006 15:04:13 -0500 Subject: [SCSI] lpfc 8.1.4 : Introduce lpfc_reset_barrier() function for resets on dual channel adapters Introduce lpfc_reset_barrier() function for resets on dual channel adapters Workaround for a hardware errata on dual channel asics. There is a potential for the chip to lock up on a reset if a shared dma engine is in use. The (ugly) work around requires a reset process which uses a mailbox command to synchronize the independent channels prior to the reset to avoid the issue. Unfortunately, the timing windows required to ensure this workaround succeeds are very specific, meaning we can't release the cpu during the barrier. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 4 +- drivers/scsi/lpfc/lpfc_init.c | 4 +- drivers/scsi/lpfc/lpfc_sli.c | 99 +++++++++++++++++++++++++++++++++++++--- 5 files changed, 100 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_init.c') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 2f67a8a92599..087c44539a16 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -197,6 +197,7 @@ struct lpfc_hba { #define LPFC_HBA_READY 32 #define LPFC_HBA_ERROR -1 + int32_t stopped; /* HBA has not been restarted since last ERATT */ uint8_t fc_linkspeed; /* Link speed after last READ_LA */ uint32_t fc_eventTag; /* event tag for link attention */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index f716c1d85f41..fad607b2e6f4 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -139,6 +139,7 @@ struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); +void lpfc_reset_barrier(struct lpfc_hba * phba); int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); int lpfc_sli_brdkill(struct lpfc_hba *); int lpfc_sli_brdreset(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 82704148d5d4..f54089fe4732 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -155,6 +155,7 @@ lpfc_work_list_done(struct lpfc_hba * phba) case LPFC_EVT_WARM_START: if (phba->hba_state >= LPFC_LINK_DOWN) lpfc_offline(phba); + lpfc_reset_barrier(phba); lpfc_sli_brdreset(phba); lpfc_hba_down_post(phba); *(int *)(evtp->evt_arg1) = @@ -164,7 +165,8 @@ lpfc_work_list_done(struct lpfc_hba * phba) case LPFC_EVT_KILL: if (phba->hba_state >= LPFC_LINK_DOWN) lpfc_offline(phba); - *(int *)(evtp->evt_arg1) = lpfc_sli_brdkill(phba); + *(int *)(evtp->evt_arg1) + = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba); complete((struct completion *)(evtp->evt_arg2)); break; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a2e15436730e..66d5d003555d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -464,8 +464,6 @@ lpfc_hba_down_prep(struct lpfc_hba * phba) lpfc_els_flush_cmd(phba); lpfc_disc_flush_list(phba); - /* Disable SLI2 since we disabled interrupts */ - phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE; return (0); } @@ -526,6 +524,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba) phba->work_status[0], phba->work_status[1]); spin_lock_irq(phba->host->host_lock); phba->fc_flag |= FC_ESTABLISH_LINK; + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(phba->host->host_lock); /* @@ -559,6 +558,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba) phba->brd_no, phba->work_hs, phba->work_status[0], phba->work_status[1]); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; lpfc_offline(phba); phba->hba_state = LPFC_HBA_ERROR; lpfc_hba_down_post(phba); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 764aadbec71b..bb69a7a1ec59 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1566,6 +1566,79 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask) return retval; } +#define BARRIER_TEST_PATTERN (0xdeadbeef) + +void lpfc_reset_barrier(struct lpfc_hba * phba) +{ + uint32_t * resp_buf; + uint32_t * mbox_buf; + volatile uint32_t mbox; + uint32_t hc_copy; + int i; + uint8_t hdrtype; + + pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); + if (hdrtype != 0x80 || + (FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID && + FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID)) + return; + + /* + * Tell the other part of the chip to suspend temporarily all + * its DMA activity. + */ + resp_buf = (uint32_t *)phba->MBslimaddr; + + /* Disable the error attention */ + hc_copy = readl(phba->HCregaddr); + writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ + + if (readl(phba->HAregaddr) & HA_ERATT) { + /* Clear Chip error bit */ + writel(HA_ERATT, phba->HAregaddr); + phba->stopped = 1; + } + + mbox = 0; + ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD; + ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP; + + writel(BARRIER_TEST_PATTERN, (resp_buf + 1)); + mbox_buf = (uint32_t *)phba->MBslimaddr; + writel(mbox, mbox_buf); + + for (i = 0; + readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++) + mdelay(1); + + if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) { + if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE || + phba->stopped) + goto restore_hc; + else + goto clear_errat; + } + + ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; + for (i = 0; readl(resp_buf) != mbox && i < 500; i++) + mdelay(1); + +clear_errat: + + while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500) + mdelay(1); + + if (readl(phba->HAregaddr) & HA_ERATT) { + writel(HA_ERATT, phba->HAregaddr); + phba->stopped = 1; + } + +restore_hc: + writel(hc_copy, phba->HCregaddr); + readl(phba->HCregaddr); /* flush */ +} + int lpfc_sli_brdkill(struct lpfc_hba * phba) { @@ -1588,9 +1661,8 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) psli->sli_flag); if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_ATOMIC)) == 0) { + GFP_KERNEL)) == 0) return 1; - } /* Disable the error attention */ spin_lock_irq(phba->host->host_lock); @@ -1610,6 +1682,8 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) return 1; } + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + mempool_free(pmb, phba->mbox_mem_pool); /* There is no completion for a KILL_BOARD mbox cmd. Check for an error @@ -1625,7 +1699,10 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) } del_timer_sync(&psli->mbox_tmo); - + if (ha_copy & HA_ERATT) { + writel(HA_ERATT, phba->HAregaddr); + phba->stopped = 1; + } spin_lock_irq(phba->host->host_lock); psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irq(phba->host->host_lock); @@ -1665,6 +1742,7 @@ lpfc_sli_brdreset(struct lpfc_hba * phba) (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; /* Now toggle INITFF bit in the Host Control Register */ writel(HC_INITFF, phba->HCregaddr); mdelay(1); @@ -1713,6 +1791,8 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) mb->mbxCommand = MBX_RESTART; mb->mbxHc = 1; + lpfc_reset_barrier(phba); + to_slim = phba->MBslimaddr; writel(*(uint32_t *) mb, to_slim); readl(to_slim); /* flush */ @@ -1730,7 +1810,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) readl(to_slim); /* flush */ lpfc_sli_brdreset(phba); - + phba->stopped = 0; phba->hba_state = LPFC_INIT_START; spin_unlock_irq(phba->host->host_lock); @@ -2038,6 +2118,13 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) return (MBX_NOT_FINISHED); } + if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && + !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { + spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); + LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) + return (MBX_NOT_FINISHED); + } + if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { /* Polling for a mbox command when another one is already active * is not allowed in SLI. Also, the driver must have established @@ -2154,8 +2241,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* First copy command data to host SLIM area */ lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); } else { - if (mb->mbxCommand == MBX_CONFIG_PORT || - mb->mbxCommand == MBX_KILL_BOARD) { + if (mb->mbxCommand == MBX_CONFIG_PORT) { /* copy command data into host mbox for cmpl */ lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); @@ -3121,6 +3207,7 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) /* Clear Chip error bit */ writel(HA_ERATT, phba->HAregaddr); readl(phba->HAregaddr); /* flush */ + phba->stopped = 1; } spin_lock(phba->host->host_lock); -- cgit v1.2.3