From d334aa79786a878e90af5b5c1b14109c1df85820 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Thu, 22 Apr 2010 10:47:40 -0600 Subject: [SCSI] mpt2sas: DIF Type 2 Protection Support Adding DIF Type 2 protection support, as well as turning on 32 byte cdb's, and setting the cdb length for > 16 byte in the SCSI_IO->control parameter. Signed-off-by: Martin Petersen Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 ++-- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index b4afe431ac1..0f41fcd4e52 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "05.100.00.02" +#define MPT2SAS_DRIVER_VERSION "05.100.00.03" #define MPT2SAS_MAJOR_VERSION 05 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 02 +#define MPT2SAS_RELEASE_VERSION 03 /* * Set MPT2SAS_SG_DEPTH value based on user input. diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index c5ff26a2a51..456ea7c3b09 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2858,9 +2858,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) unsigned char prot_op = scsi_get_prot_op(scmd); unsigned char prot_type = scsi_get_prot_type(scmd); - if (prot_type == SCSI_PROT_DIF_TYPE0 || - prot_type == SCSI_PROT_DIF_TYPE2 || - prot_op == SCSI_PROT_NORMAL) + if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) return; if (prot_op == SCSI_PROT_READ_STRIP) @@ -2882,7 +2880,13 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; mpi_request->CDB.EEDP32.PrimaryReferenceTag = cpu_to_be32(scsi_get_lba(scmd)); + break; + + case SCSI_PROT_DIF_TYPE2: + eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | + MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; break; case SCSI_PROT_DIF_TYPE3: @@ -3013,7 +3017,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; /* Make sure Device is not raid volume */ if (!_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device)) + sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); @@ -3025,6 +3029,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); _scsih_setup_eedp(scmd, mpi_request); + if (scmd->cmd_len == 32) + mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) @@ -6567,7 +6573,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->delayed_tr_list); /* init shost parameters */ - shost->max_cmd_len = 16; + shost->max_cmd_len = 32; shost->max_lun = max_lun; shost->transportt = mpt2sas_transport_template; shost->unique_id = ioc->id; @@ -6580,7 +6586,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) } scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION); + | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION); scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); /* event thread */ -- cgit v1.2.3-70-g09d2 From 2a1b7e575b80ceb19ea50bfa86ce0053ea57181d Mon Sep 17 00:00:00 2001 From: Ryan Kuester Date: Mon, 26 Apr 2010 18:11:54 -0500 Subject: [SCSI] mptsas: fix hangs caused by ATA pass-through I may have an explanation for the LSI 1068 HBA hangs provoked by ATA pass-through commands, in particular by smartctl. First, my version of the symptoms. On an LSI SAS1068E B3 HBA running 01.29.00.00 firmware, with SATA disks, and with smartd running, I'm seeing occasional task, bus, and host resets, some of which lead to hard faults of the HBA requiring a reboot. Abusively looping the smartctl command, # while true; do smartctl -a /dev/sdb > /dev/null; done dramatically increases the frequency of these failures to nearly one per minute. A high IO load through the HBA while looping smartctl seems to improve the chance of a full scsi host reset or a non-recoverable hang. I reduced what smartctl was doing down to a simple test case which causes the hang with a single IO when pointed at the sd interface. See the code at the bottom of this e-mail. It uses an SG_IO ioctl to issue a single pass-through ATA identify device command. If the buffer userspace gives for the read data has certain alignments, the task is issued to the HBA but the HBA fails to respond. If run against the sg interface, neither the test code nor smartctl causes a hang. sd and sg handle the SG_IO ioctl slightly differently. Unless you specifically set a flag to do direct IO, sg passes a buffer of its own, which is page-aligned, to the block layer and later copies the result into the userspace buffer regardless of its alignment. sd, on the other hand, always does direct IO unless the userspace buffer fails an alignment test at block/blk-map.c line 57, in which case a page-aligned buffer is created and used for the transfer. The alignment test currently checks for word-alignment, the default setup by scsi_lib.c; therefore, userspace buffers of almost any alignment are given directly to the HBA as DMA targets. The LSI 1068 hardware doesn't seem to like at least a couple of the alignments which cross a page boundary (see the test code below). Curiously, many page-boundary-crossing alignments do work just fine. So, either the hardware has an bug handling certain alignments or the hardware has a stricter alignment requirement than the driver is advertising. If stricter alignment is required, then in no case should misaligned buffers from userspace be allowed through without being bounced or at least causing an error to be returned. It seems the mptsas driver could use blk_queue_dma_alignment() to advertise a stricter alignment requirement. If it does, sd does the right thing and bounces misaligned buffers (see block/blk-map.c line 57). The following patch to 2.6.34-rc5 makes my symptoms go away. I'm sure this is the wrong place for this code, but it gets my idea across. Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 5c53624e0e8..407cb84822d 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2459,6 +2459,8 @@ mptscsih_slave_configure(struct scsi_device *sdev) ioc->name,sdev->tagged_supported, sdev->simple_tags, sdev->ordered_tags)); + blk_queue_dma_alignment (sdev->request_queue, 512 - 1); + return 0; } -- cgit v1.2.3-70-g09d2 From 1db90ea239b85479daedb978ea2f0a61776f074f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 27 May 2010 14:33:47 +0200 Subject: [SCSI] hptiop: Eliminate a NULL pointer dereference The end of the function is reachable both when host is and is not NULL. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r exists@ expression E,E1; identifier f; statement S1,S2,S3; @@ if ((E == NULL && ...) || ...) { ... when != if (...) S1 else S2 when != E = E1 * E->f ... when any return ...; } else S3 // Signed-off-by: Julia Lawall Signed-off-by: James Bottomley --- drivers/scsi/hptiop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 645f7cdf21a..0729f150b33 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1157,7 +1157,7 @@ free_pci_regions: disable_pci_device: pci_disable_device(pcidev); - dprintk("scsi%d: hptiop_probe fail\n", host->host_no); + dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0); return -ENODEV; } -- cgit v1.2.3-70-g09d2 From 55c06c7171f63aaac1f9009729d1cb5107fa0626 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:12:46 -0500 Subject: [SCSI] hpsa: save pdev pointer in per hba structure early to avoid passing it around so much. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 75 +++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index c016426b31b..d6f897016e2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3209,8 +3209,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) * controllers that are capable. If not, we use IO-APIC mode. */ -static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, - struct pci_dev *pdev, u32 board_id) +static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, u32 board_id) { #ifdef CONFIG_PCI_MSI int err; @@ -3223,9 +3222,9 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, (board_id == 0x40800E11) || (board_id == 0x40820E11) || (board_id == 0x40830E11)) goto default_int_mode; - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { - dev_info(&pdev->dev, "MSIX\n"); - err = pci_enable_msix(pdev, hpsa_msix_entries, 4); + if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { + dev_info(&h->pdev->dev, "MSIX\n"); + err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4); if (!err) { h->intr[0] = hpsa_msix_entries[0].vector; h->intr[1] = hpsa_msix_entries[1].vector; @@ -3235,29 +3234,29 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, return; } if (err > 0) { - dev_warn(&pdev->dev, "only %d MSI-X vectors " + dev_warn(&h->pdev->dev, "only %d MSI-X vectors " "available\n", err); goto default_int_mode; } else { - dev_warn(&pdev->dev, "MSI-X init failed %d\n", + dev_warn(&h->pdev->dev, "MSI-X init failed %d\n", err); goto default_int_mode; } } - if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) { - dev_info(&pdev->dev, "MSI\n"); - if (!pci_enable_msi(pdev)) + if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { + dev_info(&h->pdev->dev, "MSI\n"); + if (!pci_enable_msi(h->pdev)) h->msi_vector = 1; else - dev_warn(&pdev->dev, "MSI init failed\n"); + dev_warn(&h->pdev->dev, "MSI init failed\n"); } default_int_mode: #endif /* CONFIG_PCI_MSI */ /* if we get here we're going to use the default interrupt mode */ - h->intr[PERF_MODE_INT] = pdev->irq; + h->intr[PERF_MODE_INT] = h->pdev->irq; } -static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) +static int __devinit hpsa_pci_init(struct ctlr_info *h) { ushort subsystem_vendor_id, subsystem_device_id, command; u32 board_id, scratchpad = 0; @@ -3267,8 +3266,8 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) u32 trans_offset; int i, prod_index, err; - subsystem_vendor_id = pdev->subsystem_vendor; - subsystem_device_id = pdev->subsystem_device; + subsystem_vendor_id = h->pdev->subsystem_vendor; + subsystem_device_id = h->pdev->subsystem_device; board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) | subsystem_vendor_id); @@ -3282,7 +3281,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) prod_index--; if (subsystem_vendor_id != PCI_VENDOR_ID_HP || !hpsa_allow_any) { - dev_warn(&pdev->dev, "unrecognized board ID:" + dev_warn(&h->pdev->dev, "unrecognized board ID:" " 0x%08lx, ignoring.\n", (unsigned long) board_id); return -ENODEV; @@ -3291,41 +3290,42 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) /* check to see if controller has been disabled * BEFORE trying to enable it */ - (void)pci_read_config_word(pdev, PCI_COMMAND, &command); + (void)pci_read_config_word(h->pdev, PCI_COMMAND, &command); if (!(command & 0x02)) { - dev_warn(&pdev->dev, "controller appears to be disabled\n"); + dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); return -ENODEV; } - err = pci_enable_device(pdev); + err = pci_enable_device(h->pdev); if (err) { - dev_warn(&pdev->dev, "unable to enable PCI device\n"); + dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); return err; } - err = pci_request_regions(pdev, "hpsa"); + err = pci_request_regions(h->pdev, "hpsa"); if (err) { - dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n"); + dev_err(&h->pdev->dev, + "cannot obtain PCI resources, aborting\n"); return err; } /* If the kernel supports MSI/MSI-X we will try to enable that, * else we use the IO-APIC interrupt assigned to us by system ROM. */ - hpsa_interrupt_mode(h, pdev, board_id); + hpsa_interrupt_mode(h, board_id); /* find the memory BAR */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) + if (pci_resource_flags(h->pdev, i) & IORESOURCE_MEM) break; } if (i == DEVICE_COUNT_RESOURCE) { - dev_warn(&pdev->dev, "no memory BAR found\n"); + dev_warn(&h->pdev->dev, "no memory BAR found\n"); err = -ENODEV; goto err_out_free_res; } - h->paddr = pci_resource_start(pdev, i); /* addressing mode bits + h->paddr = pci_resource_start(h->pdev, i); /* addressing mode bits * already removed */ @@ -3339,7 +3339,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS); } if (scratchpad != HPSA_FIRMWARE_READY) { - dev_warn(&pdev->dev, "board not ready, timed out.\n"); + dev_warn(&h->pdev->dev, "board not ready, timed out.\n"); err = -ENODEV; goto err_out_free_res; } @@ -3347,20 +3347,20 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) /* get the address index number */ cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET); cfg_base_addr &= (u32) 0x0000ffff; - cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr); + cfg_base_addr_index = find_PCI_BAR_index(h->pdev, cfg_base_addr); if (cfg_base_addr_index == -1) { - dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n"); + dev_warn(&h->pdev->dev, "cannot find cfg_base_addr_index\n"); err = -ENODEV; goto err_out_free_res; } cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET); - h->cfgtable = remap_pci_mem(pci_resource_start(pdev, + h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable)); /* Find performant mode table. */ trans_offset = readl(&(h->cfgtable->TransMethodOffset)); - h->transtable = remap_pci_mem(pci_resource_start(pdev, + h->transtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index)+cfg_offset+trans_offset, sizeof(*h->transtable)); @@ -3392,7 +3392,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) (readb(&h->cfgtable->Signature[1]) != 'I') || (readb(&h->cfgtable->Signature[2]) != 'S') || (readb(&h->cfgtable->Signature[3]) != 'S')) { - dev_warn(&pdev->dev, "not a valid CISS config table\n"); + dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); err = -ENODEV; goto err_out_free_res; } @@ -3434,11 +3434,12 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev) } #ifdef HPSA_DEBUG - print_cfg_table(&pdev->dev, h->cfgtable); + print_cfg_table(&h->pdev->dev, h->cfgtable); #endif /* HPSA_DEBUG */ if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { - dev_warn(&pdev->dev, "unable to get board into simple mode\n"); + dev_warn(&h->pdev->dev, + "unable to get board into simple mode\n"); err = -ENODEV; goto err_out_free_res; } @@ -3449,7 +3450,7 @@ err_out_free_res: * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo */ - pci_release_regions(pdev); + pci_release_regions(h->pdev); return err; } @@ -3507,17 +3508,17 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, if (!h) return -ENOMEM; + h->pdev = pdev; h->busy_initializing = 1; INIT_HLIST_HEAD(&h->cmpQ); INIT_HLIST_HEAD(&h->reqQ); - rc = hpsa_pci_init(h, pdev); + rc = hpsa_pci_init(h); if (rc != 0) goto clean1; sprintf(h->devname, "hpsa%d", number_of_controllers); h->ctlr = number_of_controllers; number_of_controllers++; - h->pdev = pdev; /* configure PCI DMA stuff */ rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); -- cgit v1.2.3-70-g09d2 From e5c880d1d5923c341ac7ba537fb1e6b73c5977a2 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:12:52 -0500 Subject: [SCSI] hpsa: factor out hpsa_lookup_board_id Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 58 ++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d6f897016e2..b6c6e7f88fa 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3256,37 +3256,44 @@ default_int_mode: h->intr[PERF_MODE_INT] = h->pdev->irq; } +static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id) +{ + int i; + u32 subsystem_vendor_id, subsystem_device_id; + + subsystem_vendor_id = pdev->subsystem_vendor; + subsystem_device_id = pdev->subsystem_device; + *board_id = ((subsystem_device_id << 16) & 0xffff0000) | + subsystem_vendor_id; + + for (i = 0; i < ARRAY_SIZE(products); i++) + if (*board_id == products[i].board_id) + return i; + + if (subsystem_vendor_id != PCI_VENDOR_ID_HP || !hpsa_allow_any) { + dev_warn(&pdev->dev, "unrecognized board ID: " + "0x%08x, ignoring.\n", *board_id); + return -ENODEV; + } + return ARRAY_SIZE(products) - 1; /* generic unknown smart array */ +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { - ushort subsystem_vendor_id, subsystem_device_id, command; - u32 board_id, scratchpad = 0; + ushort command; + u32 scratchpad = 0; u64 cfg_offset; u32 cfg_base_addr; u64 cfg_base_addr_index; u32 trans_offset; int i, prod_index, err; - subsystem_vendor_id = h->pdev->subsystem_vendor; - subsystem_device_id = h->pdev->subsystem_device; - board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) | - subsystem_vendor_id); - - for (i = 0; i < ARRAY_SIZE(products); i++) - if (board_id == products[i].board_id) - break; - - prod_index = i; + prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); + if (prod_index < 0) + return -ENODEV; + h->product_name = products[prod_index].product_name; + h->access = *(products[prod_index].access); - if (prod_index == ARRAY_SIZE(products)) { - prod_index--; - if (subsystem_vendor_id != PCI_VENDOR_ID_HP || - !hpsa_allow_any) { - dev_warn(&h->pdev->dev, "unrecognized board ID:" - " 0x%08lx, ignoring.\n", - (unsigned long) board_id); - return -ENODEV; - } - } /* check to see if controller has been disabled * BEFORE trying to enable it */ @@ -3312,7 +3319,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) /* If the kernel supports MSI/MSI-X we will try to enable that, * else we use the IO-APIC interrupt assigned to us by system ROM. */ - hpsa_interrupt_mode(h, board_id); + hpsa_interrupt_mode(h, h->board_id); /* find the memory BAR */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { @@ -3364,7 +3371,6 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) cfg_base_addr_index)+cfg_offset+trans_offset, sizeof(*h->transtable)); - h->board_id = board_id; h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); @@ -3383,8 +3389,6 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) h->chainsize = 0; } - h->product_name = products[prod_index].product_name; - h->access = *(products[prod_index].access); /* Allow room for some ioctls */ h->nr_cmds = h->max_commands - 4; @@ -3410,7 +3414,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) * An ASIC bug may result in a prefetch beyond * physical memory. */ - if (board_id == 0x3225103C) { + if (h->board_id == 0x3225103C) { u32 dma_prefetch; dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG); dma_prefetch |= 0x8000; -- cgit v1.2.3-70-g09d2 From 85bdbabbd97ff797f91e6ec839ab053776bc72b4 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:12:57 -0500 Subject: [SCSI] hpsa: factor out hpsa_board_disabled Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b6c6e7f88fa..4233b932ef5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3278,9 +3278,16 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id) return ARRAY_SIZE(products) - 1; /* generic unknown smart array */ } +static inline bool hpsa_board_disabled(struct pci_dev *pdev) +{ + u16 command; + + (void) pci_read_config_word(pdev, PCI_COMMAND, &command); + return ((command & PCI_COMMAND_MEMORY) == 0); +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { - ushort command; u32 scratchpad = 0; u64 cfg_offset; u32 cfg_base_addr; @@ -3294,15 +3301,10 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) h->product_name = products[prod_index].product_name; h->access = *(products[prod_index].access); - /* check to see if controller has been disabled - * BEFORE trying to enable it - */ - (void)pci_read_config_word(h->pdev, PCI_COMMAND, &command); - if (!(command & 0x02)) { + if (hpsa_board_disabled(h->pdev)) { dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); return -ENODEV; } - err = pci_enable_device(h->pdev); if (err) { dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); -- cgit v1.2.3-70-g09d2 From 6b3f4c52b29eee17285a6cd57071c9ac7736d172 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:02 -0500 Subject: [SCSI] hpsa: remove redundant board_id parameter from hpsa_interrupt_mode and delete duplicated comment Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4233b932ef5..66b7dcfb727 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3209,7 +3209,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) * controllers that are capable. If not, we use IO-APIC mode. */ -static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, u32 board_id) +static void __devinit hpsa_interrupt_mode(struct ctlr_info *h) { #ifdef CONFIG_PCI_MSI int err; @@ -3218,9 +3218,8 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h, u32 board_id) }; /* Some boards advertise MSI but don't really support it */ - if ((board_id == 0x40700E11) || - (board_id == 0x40800E11) || - (board_id == 0x40820E11) || (board_id == 0x40830E11)) + if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) || + (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) goto default_int_mode; if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { dev_info(&h->pdev->dev, "MSIX\n"); @@ -3317,11 +3316,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) "cannot obtain PCI resources, aborting\n"); return err; } - - /* If the kernel supports MSI/MSI-X we will try to enable that, - * else we use the IO-APIC interrupt assigned to us by system ROM. - */ - hpsa_interrupt_mode(h, h->board_id); + hpsa_interrupt_mode(h); /* find the memory BAR */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { -- cgit v1.2.3-70-g09d2 From 3a7774ceb89f02f78e269b5c900096b066b66c3c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:07 -0500 Subject: [SCSI] hpsa: factor out hpsa_find_memory_BAR Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 66b7dcfb727..0582f2fc11f 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3285,6 +3285,23 @@ static inline bool hpsa_board_disabled(struct pci_dev *pdev) return ((command & PCI_COMMAND_MEMORY) == 0); } +static int __devinit hpsa_pci_find_memory_BAR(struct ctlr_info *h, + unsigned long *memory_bar) +{ + int i; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + if (pci_resource_flags(h->pdev, i) & IORESOURCE_MEM) { + /* addressing mode bits already removed */ + *memory_bar = pci_resource_start(h->pdev, i); + dev_dbg(&h->pdev->dev, "memory BAR = %lx\n", + *memory_bar); + return 0; + } + dev_warn(&h->pdev->dev, "no memory BAR found\n"); + return -ENODEV; +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { u32 scratchpad = 0; @@ -3317,22 +3334,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) return err; } hpsa_interrupt_mode(h); - - /* find the memory BAR */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(h->pdev, i) & IORESOURCE_MEM) - break; - } - if (i == DEVICE_COUNT_RESOURCE) { - dev_warn(&h->pdev->dev, "no memory BAR found\n"); - err = -ENODEV; + err = hpsa_pci_find_memory_BAR(h, &h->paddr); + if (err) goto err_out_free_res; - } - - h->paddr = pci_resource_start(h->pdev, i); /* addressing mode bits - * already removed - */ - h->vaddr = remap_pci_mem(h->paddr, 0x250); /* Wait for the board to become ready. */ -- cgit v1.2.3-70-g09d2 From 2c4c8c8b662286230a798c60408d217aeab55f7f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:12 -0500 Subject: [SCSI] hpsa: factor out hpsa_wait_for_board_ready Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 0582f2fc11f..66c4fc306f2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3302,9 +3302,23 @@ static int __devinit hpsa_pci_find_memory_BAR(struct ctlr_info *h, return -ENODEV; } +static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h) +{ + int i; + u32 scratchpad; + + for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) { + scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); + if (scratchpad == HPSA_FIRMWARE_READY) + return 0; + msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS); + } + dev_warn(&h->pdev->dev, "board not ready, timed out.\n"); + return -ENODEV; +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { - u32 scratchpad = 0; u64 cfg_offset; u32 cfg_base_addr; u64 cfg_base_addr_index; @@ -3339,18 +3353,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) goto err_out_free_res; h->vaddr = remap_pci_mem(h->paddr, 0x250); - /* Wait for the board to become ready. */ - for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) { - scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); - if (scratchpad == HPSA_FIRMWARE_READY) - break; - msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS); - } - if (scratchpad != HPSA_FIRMWARE_READY) { - dev_warn(&h->pdev->dev, "board not ready, timed out.\n"); - err = -ENODEV; + err = hpsa_wait_for_board_ready(h); + if (err) goto err_out_free_res; - } /* get the address index number */ cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET); -- cgit v1.2.3-70-g09d2 From 77c4495c17d7508bdef1cfd2c3c933ff5379908b Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:17 -0500 Subject: [SCSI] hpsa: factor out hpsa_find_cfgtables Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 66c4fc306f2..cb0cc0993b9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3317,12 +3317,39 @@ static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h) return -ENODEV; } -static int __devinit hpsa_pci_init(struct ctlr_info *h) +static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; u32 cfg_base_addr; u64 cfg_base_addr_index; u32 trans_offset; + + /* get the address index number */ + cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET); + cfg_base_addr &= (u32) 0x0000ffff; + cfg_base_addr_index = find_PCI_BAR_index(h->pdev, cfg_base_addr); + if (cfg_base_addr_index == -1) { + dev_warn(&h->pdev->dev, "cannot find cfg_base_addr_index\n"); + return -ENODEV; + } + cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET); + h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, + cfg_base_addr_index) + cfg_offset, + sizeof(h->cfgtable)); + if (!h->cfgtable) + return -ENOMEM; + /* Find performant mode table. */ + trans_offset = readl(&(h->cfgtable->TransMethodOffset)); + h->transtable = remap_pci_mem(pci_resource_start(h->pdev, + cfg_base_addr_index)+cfg_offset+trans_offset, + sizeof(*h->transtable)); + if (!h->transtable) + return -ENOMEM; + return 0; +} + +static int __devinit hpsa_pci_init(struct ctlr_info *h) +{ int i, prod_index, err; prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); @@ -3356,26 +3383,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) err = hpsa_wait_for_board_ready(h); if (err) goto err_out_free_res; - - /* get the address index number */ - cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET); - cfg_base_addr &= (u32) 0x0000ffff; - cfg_base_addr_index = find_PCI_BAR_index(h->pdev, cfg_base_addr); - if (cfg_base_addr_index == -1) { - dev_warn(&h->pdev->dev, "cannot find cfg_base_addr_index\n"); - err = -ENODEV; + err = hpsa_find_cfgtables(h); + if (err) goto err_out_free_res; - } - - cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET); - h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index) + cfg_offset, - sizeof(h->cfgtable)); - /* Find performant mode table. */ - trans_offset = readl(&(h->cfgtable->TransMethodOffset)); - h->transtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index)+cfg_offset+trans_offset, - sizeof(*h->transtable)); h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); -- cgit v1.2.3-70-g09d2 From 204892e9717790cd17689aaebf2790a477492734 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:22 -0500 Subject: [SCSI] hpsa: fix leak of ioremapped memory in hpsa_pci_init error path. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cb0cc0993b9..4983f3452dc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3379,7 +3379,10 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) if (err) goto err_out_free_res; h->vaddr = remap_pci_mem(h->paddr, 0x250); - + if (!h->vaddr) { + err = -ENOMEM; + goto err_out_free_res; + } err = hpsa_wait_for_board_ready(h); if (err) goto err_out_free_res; @@ -3466,6 +3469,12 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) return 0; err_out_free_res: + if (h->transtable) + iounmap(h->transtable); + if (h->cfgtable) + iounmap(h->cfgtable); + if (h->vaddr) + iounmap(h->vaddr); /* * Deliberately omit pci_disable_device(): it does something nasty to * Smart Array controllers that pci_enable_device does not undo @@ -3684,6 +3693,8 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev) hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ hpsa_shutdown(pdev); iounmap(h->vaddr); + iounmap(h->transtable); + iounmap(h->cfgtable); hpsa_free_sg_chain_blocks(h); pci_free_consistent(h->pdev, h->nr_cmds * sizeof(struct CommandList), -- cgit v1.2.3-70-g09d2 From b93d7536eaa1206ad4a00ad8ea700ff0bd75a0da Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:27 -0500 Subject: [SCSI] hpsa: hpsa factor out hpsa_find_board_params Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4983f3452dc..dcbe54b1dfb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3348,6 +3348,30 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) return 0; } +/* Interrogate the hardware for some limits: + * max commands, max SG elements without chaining, and with chaining, + * SG chain block size, etc. + */ +static void __devinit hpsa_find_board_params(struct ctlr_info *h) +{ + h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); + h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ + h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); + /* + * Limit in-command s/g elements to 32 save dma'able memory. + * Howvever spec says if 0, use 31 + */ + h->max_cmd_sg_entries = 31; + if (h->maxsgentries > 512) { + h->max_cmd_sg_entries = 32; + h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; + h->maxsgentries--; /* save one for chain pointer */ + } else { + h->maxsgentries = 31; /* default to traditional values */ + h->chainsize = 0; + } +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { int i, prod_index, err; @@ -3389,27 +3413,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) err = hpsa_find_cfgtables(h); if (err) goto err_out_free_res; - - h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); - h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); - - /* - * Limit in-command s/g elements to 32 save dma'able memory. - * Howvever spec says if 0, use 31 - */ - - h->max_cmd_sg_entries = 31; - if (h->maxsgentries > 512) { - h->max_cmd_sg_entries = 32; - h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; - h->maxsgentries--; /* save one for chain pointer */ - } else { - h->maxsgentries = 31; /* default to traditional values */ - h->chainsize = 0; - } - - /* Allow room for some ioctls */ - h->nr_cmds = h->max_commands - 4; + hpsa_find_board_params(h); if ((readb(&h->cfgtable->Signature[0]) != 'C') || (readb(&h->cfgtable->Signature[1]) != 'I') || -- cgit v1.2.3-70-g09d2 From 76c46e4970f7ee6d8c54220a767e93d67b74cd33 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:32 -0500 Subject: [SCSI] hpsa: factor out hpsa-CISS-signature-present Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index dcbe54b1dfb..f2a9af64dfa 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3372,6 +3372,18 @@ static void __devinit hpsa_find_board_params(struct ctlr_info *h) } } +static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) +{ + if ((readb(&h->cfgtable->Signature[0]) != 'C') || + (readb(&h->cfgtable->Signature[1]) != 'I') || + (readb(&h->cfgtable->Signature[2]) != 'S') || + (readb(&h->cfgtable->Signature[3]) != 'S')) { + dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); + return false; + } + return true; +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { int i, prod_index, err; @@ -3415,11 +3427,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) goto err_out_free_res; hpsa_find_board_params(h); - if ((readb(&h->cfgtable->Signature[0]) != 'C') || - (readb(&h->cfgtable->Signature[1]) != 'I') || - (readb(&h->cfgtable->Signature[2]) != 'S') || - (readb(&h->cfgtable->Signature[3]) != 'S')) { - dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); + if (!hpsa_CISS_signature_present(h)) { err = -ENODEV; goto err_out_free_res; } -- cgit v1.2.3-70-g09d2 From f7c391015ab64c835a9bb403626b38a51d6432cc Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:38 -0500 Subject: [SCSI] hpsa: factor out hpsa_enable_scsi_prefetch Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f2a9af64dfa..62f9784ecf8 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3384,6 +3384,18 @@ static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) return true; } +/* Need to enable prefetch in the SCSI core for 6400 in x86 */ +static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h) +{ +#ifdef CONFIG_X86 + u32 prefetch; + + prefetch = readl(&(h->cfgtable->SCSI_Prefetch)); + prefetch |= 0x100; + writel(prefetch, &(h->cfgtable->SCSI_Prefetch)); +#endif +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { int i, prod_index, err; @@ -3431,15 +3443,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) err = -ENODEV; goto err_out_free_res; } -#ifdef CONFIG_X86 - { - /* Need to enable prefetch in the SCSI core for 6400 in x86 */ - u32 prefetch; - prefetch = readl(&(h->cfgtable->SCSI_Prefetch)); - prefetch |= 0x100; - writel(prefetch, &(h->cfgtable->SCSI_Prefetch)); - } -#endif + hpsa_enable_scsi_prefetch(h); /* Disabling DMA prefetch for the P600 * An ASIC bug may result in a prefetch beyond -- cgit v1.2.3-70-g09d2 From 3d0eab67cf556db4430a42fbb45dc90ef690d30c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:43 -0500 Subject: [SCSI] hpsa: factor out hpsa_p600_dma_prefetch_quirk Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 62f9784ecf8..9e81e0bcf1e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3396,6 +3396,20 @@ static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h) #endif } +/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result + * in a prefetch beyond physical memory. + */ +static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) +{ + u32 dma_prefetch; + + if (h->board_id != 0x3225103C) + return; + dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG); + dma_prefetch |= 0x8000; + writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { int i, prod_index, err; @@ -3444,17 +3458,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) goto err_out_free_res; } hpsa_enable_scsi_prefetch(h); - - /* Disabling DMA prefetch for the P600 - * An ASIC bug may result in a prefetch beyond - * physical memory. - */ - if (h->board_id == 0x3225103C) { - u32 dma_prefetch; - dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG); - dma_prefetch |= 0x8000; - writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); - } + hpsa_p600_dma_prefetch_quirk(h); h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); /* Update the field, and then ring the doorbell */ -- cgit v1.2.3-70-g09d2 From eb6b2ae9058accd183fe8b31f1985312bf333624 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:48 -0500 Subject: [SCSI] hpsa: factor out hpsa_enter_simple_mode Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 62 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9e81e0bcf1e..4d4ecca399a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3410,9 +3410,41 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } +static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) +{ + int i; + + h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); + /* Update the field, and then ring the doorbell */ + writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + + /* under certain very rare conditions, this can take awhile. + * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right + * as we enter this code.) + */ + for (i = 0; i < MAX_CONFIG_WAIT; i++) { + if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + msleep(10); + } + +#ifdef HPSA_DEBUG + print_cfg_table(&h->pdev->dev, h->cfgtable); +#endif /* HPSA_DEBUG */ + + if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { + dev_warn(&h->pdev->dev, + "unable to get board into simple mode\n"); + return -ENODEV; + } + return 0; +} + static int __devinit hpsa_pci_init(struct ctlr_info *h) { - int i, prod_index, err; + int prod_index, err; prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); if (prod_index < 0) @@ -3459,33 +3491,9 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) } hpsa_enable_scsi_prefetch(h); hpsa_p600_dma_prefetch_quirk(h); - - h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); - /* Update the field, and then ring the doorbell */ - writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - - /* under certain very rare conditions, this can take awhile. - * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right - * as we enter this code.) - */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { - if (!(readl(h->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) - break; - /* delay and try again */ - msleep(10); - } - -#ifdef HPSA_DEBUG - print_cfg_table(&h->pdev->dev, h->cfgtable); -#endif /* HPSA_DEBUG */ - - if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { - dev_warn(&h->pdev->dev, - "unable to get board into simple mode\n"); - err = -ENODEV; + err = hpsa_enter_simple_mode(h); + if (err) goto err_out_free_res; - } return 0; err_out_free_res: -- cgit v1.2.3-70-g09d2 From cda7612d4b96d51324c6fc4d5e47d629da6cb500 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:53 -0500 Subject: [SCSI] hpsa: check that simple mode is supported before trying to enter simple mode transport method. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4d4ecca399a..57d038045ad 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3413,6 +3413,11 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) { int i; + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & SIMPLE_MODE)) + return -ENOTSUPP; h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); /* Update the field, and then ring the doorbell */ -- cgit v1.2.3-70-g09d2 From 58f8665cc369b9633af072afb741b8f0a01622fa Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:13:58 -0500 Subject: [SCSI] hpsa: clean up debug ifdefs Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 57d038045ad..7e602d282d5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3135,9 +3135,9 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev) * the io functions. * This is for debug only. */ -#ifdef HPSA_DEBUG static void print_cfg_table(struct device *dev, struct CfgTable *tb) { +#ifdef HPSA_DEBUG int i; char temp_name[17]; @@ -3167,8 +3167,8 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb) dev_info(dev, " Server Name = %s\n", temp_name); dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat))); -} #endif /* HPSA_DEBUG */ +} static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) { @@ -3434,11 +3434,7 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) /* delay and try again */ msleep(10); } - -#ifdef HPSA_DEBUG print_cfg_table(&h->pdev->dev, h->cfgtable); -#endif /* HPSA_DEBUG */ - if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); -- cgit v1.2.3-70-g09d2 From 7136f9a78eece43226dee1a46ec6fc144f561239 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:03 -0500 Subject: [SCSI] hpsa: mark hpsa_mark_hpsa_put_ctlr_into_performant_mode as __devinit Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 7e602d282d5..d495d8b19c9 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -158,7 +158,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h, /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int *bucket_map); -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); +static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h); static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); @@ -3803,7 +3803,7 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) +static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) { u32 trans_support; u64 trans_offset; -- cgit v1.2.3-70-g09d2 From 3f4336f33314e7d3687ff46af1fcaa970e3f4e00 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:08 -0500 Subject: [SCSI] hpsa: factor out hpsa_wait_for_mode_change_ack Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d495d8b19c9..e89c40aa2b3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3410,19 +3410,9 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); } -static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) +static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h) { int i; - u32 trans_support; - - trans_support = readl(&(h->cfgtable->TransportSupport)); - if (!(trans_support & SIMPLE_MODE)) - return -ENOTSUPP; - - h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); - /* Update the field, and then ring the doorbell */ - writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); /* under certain very rare conditions, this can take awhile. * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right @@ -3434,6 +3424,21 @@ static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) /* delay and try again */ msleep(10); } +} + +static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) +{ + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & SIMPLE_MODE)) + return -ENOTSUPP; + + h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); + /* Update the field, and then ring the doorbell */ + writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + hpsa_wait_for_mode_change_ack(h); print_cfg_table(&h->pdev->dev, h->cfgtable); if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { dev_warn(&h->pdev->dev, @@ -3814,7 +3819,6 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) */ int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */ int i = 0; - int l = 0; unsigned long register_value; trans_support = readl(&(h->cfgtable->TransportSupport)); @@ -3858,17 +3862,7 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) writel(CFGTBL_Trans_Performant, &(h->cfgtable->HostWrite.TransportRequest)); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - /* under certain very rare conditions, this can take awhile. - * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right - * as we enter this code.) */ - for (l = 0; l < MAX_CONFIG_WAIT; l++) { - register_value = readl(h->vaddr + SA5_DOORBELL); - if (!(register_value & CFGTBL_ChangeReq)) - break; - /* delay and try again */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(10); - } + hpsa_wait_for_mode_change_ack(h); register_value = readl(&(h->cfgtable->TransportActive)); if (!(register_value & CFGTBL_Trans_Performant)) { dev_warn(&h->pdev->dev, "unable to get board into" -- cgit v1.2.3-70-g09d2 From ec18d2abad04091c5125b0a37ad80a00099d8ac0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:13 -0500 Subject: [SCSI] hpsa: remove unused variable trans_offset Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e89c40aa2b3..ad70f3e29c2 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3811,7 +3811,6 @@ static void calc_bucket_map(int bucket[], int num_buckets, static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) { u32 trans_support; - u64 trans_offset; /* 5 = 1 s/g entry or 4k * 6 = 2 s/g entry or 8k * 8 = 4 s/g entry or 16k @@ -3846,7 +3845,6 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) memset(h->reply_pool, 0, h->reply_pool_size); h->reply_pool_head = h->reply_pool; - trans_offset = readl(&(h->cfgtable->TransMethodOffset)); bft[7] = h->max_sg_entries + 4; calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable); for (i = 0; i < 8; i++) -- cgit v1.2.3-70-g09d2 From 6c311b5725b9500bdd0f527cd97496b11999fbbd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:19 -0500 Subject: [SCSI] hpsa: factor out hpsa_enter_performant_mode Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 54 +++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ad70f3e29c2..3c51544db95 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3808,36 +3808,16 @@ static void calc_bucket_map(int bucket[], int num_buckets, } } -static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) +static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h) { - u32 trans_support; + int i; + unsigned long register_value; + int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */ /* 5 = 1 s/g entry or 4k * 6 = 2 s/g entry or 8k * 8 = 4 s/g entry or 16k * 10 = 6 s/g entry or 24k */ - int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */ - int i = 0; - unsigned long register_value; - - trans_support = readl(&(h->cfgtable->TransportSupport)); - if (!(trans_support & PERFORMANT_MODE)) - return; - - h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); - h->max_sg_entries = 32; - /* Performant mode ring buffer and supporting data structures */ - h->reply_pool_size = h->max_commands * sizeof(u64); - h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, - &(h->reply_pool_dhandle)); - - /* Need a block fetch table for performant mode */ - h->blockFetchTable = kmalloc(((h->max_sg_entries+1) * - sizeof(u32)), GFP_KERNEL); - - if ((h->reply_pool == NULL) - || (h->blockFetchTable == NULL)) - goto clean_up; h->reply_pool_wraparound = 1; /* spec: init to 1 */ @@ -3867,6 +3847,32 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) " performant mode\n"); return; } +} + +static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) +{ + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & PERFORMANT_MODE)) + return; + + h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); + h->max_sg_entries = 32; + /* Performant mode ring buffer and supporting data structures */ + h->reply_pool_size = h->max_commands * sizeof(u64); + h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, + &(h->reply_pool_dhandle)); + + /* Need a block fetch table for performant mode */ + h->blockFetchTable = kmalloc(((h->max_sg_entries+1) * + sizeof(u32)), GFP_KERNEL); + + if ((h->reply_pool == NULL) + || (h->blockFetchTable == NULL)) + goto clean_up; + + hpsa_enter_performant_mode(h); /* Change the access methods to the performant access methods */ h->access = SA5_performant_access; -- cgit v1.2.3-70-g09d2 From 873f339fc53750c1e715f5e1d2dfdb9869b7ea3f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:24 -0500 Subject: [SCSI] hpsa: remove unused firm_ver member of the per-hba structure Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 6 ------ drivers/scsi/hpsa.h | 1 - 2 files changed, 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3c51544db95..50fddf84e47 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1440,12 +1440,6 @@ static int hpsa_update_device_info(struct ctlr_info *h, goto bail_out; } - /* As a side effect, record the firmware version number - * if we happen to be talking to the RAID controller. - */ - if (is_hba_lunid(scsi3addr)) - memcpy(h->firm_ver, &inq_buff[32], 4); - this_device->devtype = (inq_buff[0] & 0x1f); memcpy(this_device->scsi3addr, scsi3addr, 8); memcpy(this_device->vendor, &inq_buff[8], diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 1bb5233b09a..a203ef65cb5 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -53,7 +53,6 @@ struct ctlr_info { int ctlr; char devname[8]; char *product_name; - char firm_ver[4]; /* Firmware version */ struct pci_dev *pdev; u32 board_id; void __iomem *vaddr; -- cgit v1.2.3-70-g09d2 From 992ebcf14f3cf029b8d0da4f479d752c19d8c726 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:29 -0500 Subject: [SCSI] hpsa: Add hpsa.txt to Documentation/scsi Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- Documentation/scsi/hpsa.txt | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/scsi/hpsa.txt diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt new file mode 100644 index 00000000000..4055657340a --- /dev/null +++ b/Documentation/scsi/hpsa.txt @@ -0,0 +1,100 @@ + +HPSA - Hewlett Packard Smart Array driver +----------------------------------------- + +This file describes the hpsa SCSI driver for HP Smart Array controllers. +The hpsa driver is intended to supplant the cciss driver for newer +Smart Array controllers. The hpsa driver is a SCSI driver, while the +cciss driver is a "block" driver. Actually cciss is both a block +driver (for logical drives) AND a SCSI driver (for tape drives). This +"split-brained" design of the cciss driver is a source of excess +complexity and eliminating that complexity is one of the reasons +for hpsa to exist. + +Supported devices: +------------------ + +Smart Array P212 +Smart Array P410 +Smart Array P410i +Smart Array P411 +Smart Array P812 +Smart Array P712m +Smart Array P711m +StorageWorks P1210m + +Additionally, older Smart Arrays may work with the hpsa driver if the kernel +boot parameter "hpsa_allow_any=1" is specified, however these are not tested +nor supported by HP with this driver. For older Smart Arrays, the cciss +driver should still be used. + +HPSA specific entries in /sys +----------------------------- + + In addition to the generic SCSI attributes available in /sys, hpsa supports + the following attributes: + + HPSA specific host attributes: + ------------------------------ + + /sys/class/scsi_host/host*/rescan + + the host "rescan" attribute is a write only attribute. Writing to this + attribute will cause the driver to scan for new, changed, or removed devices + (e.g. hot-plugged tape drives, or newly configured or deleted logical drives, + etc.) and notify the SCSI midlayer of any changes detected. Normally this is + triggered automatically by HP's Array Configuration Utility (either the GUI or + command line variety) so for logical drive changes, the user should not + normally have to use this. It may be useful when hot plugging devices like + tape drives, or entire storage boxes containing pre-configured logical drives. + + HPSA specific disk attributes: + ------------------------------ + + /sys/class/scsi_disk/c:b:t:l/device/unique_id + /sys/class/scsi_disk/c:b:t:l/device/raid_level + /sys/class/scsi_disk/c:b:t:l/device/lunid + + (where c:b:t:l are the controller, bus, target and lun of the device) + + For example: + + root@host:/sys/class/scsi_disk/4:0:0:0/device# cat unique_id + 600508B1001044395355323037570F77 + root@host:/sys/class/scsi_disk/4:0:0:0/device# cat lunid + 0x0000004000000000 + root@host:/sys/class/scsi_disk/4:0:0:0/device# cat raid_level + RAID 0 + +HPSA specific ioctls: +--------------------- + + For compatibility with applications written for the cciss driver, many, but + not all of the ioctls supported by the cciss driver are also supported by the + hpsa driver. The data structures used by these are described in + include/linux/cciss_ioctl.h + + CCISS_DEREGDISK + CCISS_REGNEWDISK + CCISS_REGNEWD + + The above three ioctls all do exactly the same thing, which is to cause the driver + to rescan for new devices. This does exactly the same thing as writing to the + hpsa specific host "rescan" attribute. + + CCISS_GETPCIINFO + + Returns PCI domain, bus, device and function and "board ID" (PCI subsystem ID). + + CCISS_GETDRIVVER + + Returns driver version in three bytes encoded as: + (major_version << 16) | (minor_version << 8) | (subminor_version) + + CCISS_PASSTHRU + CCISS_BIG_PASSTHRU + + Allows "BMIC" and "CISS" commands to be passed through to the Smart Array. + These are used extensively by the HP Array Configuration Utility, SNMP storage + agents, etc. See cciss_vol_status at http://cciss.sf.net for some examples. + -- cgit v1.2.3-70-g09d2 From d28ce020fb0ef9254fc9e0bd07f5898c69af9f7d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:34 -0500 Subject: [SCSI] hpsa: expose controller firmware revision via /sys. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- Documentation/scsi/hpsa.txt | 7 +++++++ drivers/scsi/hpsa.c | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Documentation/scsi/hpsa.txt b/Documentation/scsi/hpsa.txt index 4055657340a..dca658362cb 100644 --- a/Documentation/scsi/hpsa.txt +++ b/Documentation/scsi/hpsa.txt @@ -38,6 +38,7 @@ HPSA specific entries in /sys ------------------------------ /sys/class/scsi_host/host*/rescan + /sys/class/scsi_host/host*/firmware_revision the host "rescan" attribute is a write only attribute. Writing to this attribute will cause the driver to scan for new, changed, or removed devices @@ -48,6 +49,12 @@ HPSA specific entries in /sys normally have to use this. It may be useful when hot plugging devices like tape drives, or entire storage boxes containing pre-configured logical drives. + The "firmware_revision" attribute contains the firmware version of the Smart Array. + For example: + + root@host:/sys/class/scsi_host/host4# cat firmware_revision + 7.14 + HPSA specific disk attributes: ------------------------------ diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 50fddf84e47..410910762fc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -148,6 +148,8 @@ static ssize_t lunid_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr, char *buf); +static ssize_t host_show_firmware_revision(struct device *dev, + struct device_attribute *attr, char *buf); static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); static ssize_t host_store_rescan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); @@ -165,6 +167,8 @@ static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL); static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static DEVICE_ATTR(firmware_revision, S_IRUGO, + host_show_firmware_revision, NULL); static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_raid_level, @@ -175,6 +179,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = { static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_rescan, + &dev_attr_firmware_revision, NULL, }; @@ -260,6 +265,21 @@ static ssize_t host_store_rescan(struct device *dev, return count; } +static ssize_t host_show_firmware_revision(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct Scsi_Host *shost = class_to_shost(dev); + unsigned char *fwrev; + + h = shost_to_hba(shost); + if (!h->hba_inquiry_data) + return 0; + fwrev = &h->hba_inquiry_data[32]; + return snprintf(buf, 20, "%c%c%c%c\n", + fwrev[0], fwrev[1], fwrev[2], fwrev[3]); +} + /* Enqueuing and dequeuing functions for cmdlists. */ static inline void addQ(struct hlist_head *list, struct CommandList *c) { -- cgit v1.2.3-70-g09d2 From def342bd745d88ed73541b9c07cefb13d8c576fd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:39 -0500 Subject: [SCSI] hpsa: fix block fetch table problem. We have 32 (MAXSGENTRIES) scatter gather elements embedded in the command. With all these, the total command size is about 576 bytes. However, the last entry in the block fetch table is 35. (the block fetch table contains the number of 16-byte chunks the firmware needs to fetch for a given number of scatter gather elements.) 35 * 16 = 560 bytes, which isn't enough. It needs to be 36. (36 * 16 == 576) or, MAXSGENTRIES + 4. (plus 4 because there's a bunch of stuff at the front of the command before the first scatter gather element that takes up 4 * 16 bytes.) Without this fix, the controller may have to perform two DMA operations to fetch the command since the first one may not get the whole thing. Signed-off-by: Don Brace Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 410910762fc..1133b5fda0e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3826,7 +3826,26 @@ static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h) { int i; unsigned long register_value; - int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */ + + /* This is a bit complicated. There are 8 registers on + * the controller which we write to to tell it 8 different + * sizes of commands which there may be. It's a way of + * reducing the DMA done to fetch each command. Encoded into + * each command's tag are 3 bits which communicate to the controller + * which of the eight sizes that command fits within. The size of + * each command depends on how many scatter gather entries there are. + * Each SG entry requires 16 bytes. The eight registers are programmed + * with the number of 16-byte blocks a command of that size requires. + * The smallest command possible requires 5 such 16 byte blocks. + * the largest command possible requires MAXSGENTRIES + 4 16-byte + * blocks. Note, this only extends to the SG entries contained + * within the command block, and does not extend to chained blocks + * of SG elements. bft[] contains the eight values we write to + * the registers. They are not evenly distributed, but have more + * sizes for small commands, and fewer sizes for larger commands. + */ + int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4}; + BUILD_BUG_ON(28 > MAXSGENTRIES + 4); /* 5 = 1 s/g entry or 4k * 6 = 2 s/g entry or 8k * 8 = 4 s/g entry or 16k -- cgit v1.2.3-70-g09d2 From 9257aa4963873dcc3b339e2e3c0aba081c83695f Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Thu, 27 May 2010 15:14:44 -0500 Subject: [SCSI] hpsa: add entry to MAINTAINERS Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6d119c98b89..a1129bfd32c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2609,6 +2609,14 @@ S: Maintained F: Documentation/blockdev/cpqarray.txt F: drivers/block/cpqarray.* +HEWLETT-PACKARD SMART ARRAY RAID DRIVER (hpsa) +M: Stephen M. Cameron +L: iss_storagedev@hp.com +S: Supported +F: Documentation/scsi/hpsa.txt +F: drivers/scsi/hpsa*.[ch] +F: include/linux/cciss*.h + HEWLETT-PACKARD SMART CISS RAID DRIVER (cciss) M: Mike Miller L: iss_storagedev@hp.com -- cgit v1.2.3-70-g09d2 From b963752f47c54a29c11acee99e6c99b3c6bb35c5 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:15 -0700 Subject: [SCSI] qla2xxx: Clear drive active CRB register when not in use. The CRB drive active register is cleared when driver is unloaded or when driver enters failed state. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 1 - drivers/scsi/qla2xxx/qla_init.c | 2 ++ drivers/scsi/qla2xxx/qla_iocb.c | 4 ++-- drivers/scsi/qla2xxx/qla_nx.c | 4 ++++ drivers/scsi/qla2xxx/qla_nx.h | 3 +-- drivers/scsi/qla2xxx/qla_os.c | 4 ++++ 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 8217c3bcbc2..2247ef8702e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -513,7 +513,6 @@ extern int qla82xx_nvram_config(struct scsi_qla_host *); extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); extern int qla82xx_load_firmware(scsi_qla_host_t *); extern int qla82xx_reset_hw(scsi_qla_host_t *); -extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *); extern void qla82xx_watchdog(scsi_qla_host_t *); /* Firmware and flash related functions */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ab2cc71994c..f1db11a0d69 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1454,6 +1454,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = ha->isp_ops->load_risc(vha, &srisc_address); if (rval == QLA_SUCCESS) goto enable_82xx_npiv; + else + goto failed; } if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8ef94536541..5d0e99c2b52 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1683,7 +1683,7 @@ qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) struct srb_iocb *lio = ctx->u.iocb_cmd; uint16_t opts; - mbx->entry_type = MBX_IOCB_TYPE;; + mbx->entry_type = MBX_IOCB_TYPE; SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; @@ -1718,7 +1718,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) { struct qla_hw_data *ha = sp->fcport->vha->hw; - mbx->entry_type = MBX_IOCB_TYPE;; + mbx->entry_type = MBX_IOCB_TYPE; SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); mbx->mb1 = HAS_EXTENDED_IDS(ha) ? diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index ff562de0e8e..eb12bf260a1 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3279,6 +3279,10 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha) /* Disable the board */ qla_printk(KERN_INFO, ha, "Disabling the board\n"); + qla82xx_idc_lock(ha); + qla82xx_clear_drv_active(ha); + qla82xx_idc_unlock(ha); + /* Set DEV_FAILED flag to disable timer */ vha->device_flags |= DFLG_DEV_FAILED; qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index f8f99a5ea53..aa95d3816d6 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -538,11 +538,10 @@ /* Driver Coexistence Defines */ #define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138)) #define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140)) -#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) -#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174)) #define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144)) #define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148)) #define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) +#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174)) /* Every driver should use these Device State */ #define QLA82XX_DEV_COLD 1 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index be1a8fcbb1f..c345ba71672 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2402,6 +2402,10 @@ qla2x00_remove_one(struct pci_dev *pdev) scsi_host_put(base_vha->host); if (IS_QLA82XX(ha)) { + qla82xx_idc_lock(ha); + qla82xx_clear_drv_active(ha); + qla82xx_idc_unlock(ha); + iounmap((device_reg_t __iomem *)ha->nx_pcibase); if (!ql2xdbwr) iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); -- cgit v1.2.3-70-g09d2 From d3fa9e7d270e3d9b3fda325cdcb2ea77a00ed876 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 28 May 2010 15:08:16 -0700 Subject: [SCSI] qla2xxx: Add portid to async-request messages. This helps to correlate submission/completion messages during triaging. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 6 ++++-- drivers/scsi/qla2xxx/qla_isr.c | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f1db11a0d69..4bf97348381 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -131,8 +131,10 @@ qla2x00_async_iocb_timeout(srb_t *sp) struct srb_ctx *ctx = sp->ctx; DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s timeout.\n", - fcport->vha->host_no, sp->handle, ctx->name)); + "scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n", + fcport->vha->host_no, sp->handle, + ctx->name, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa)); fcport->flags &= ~FCF_ASYNC_SENT; if (ctx->type == SRB_LOGIN_CMD) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index be3d8bed2ec..bc82ba99f25 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -918,12 +918,15 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, QLA_LOGIO_LOGIN_RETRIED : 0; if (mbx->entry_status) { DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s error entry - entry-status=%x " - "status=%x state-flag=%x status-flags=%x.\n", + "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x " + "entry-status=%x status=%x state-flag=%x " + "status-flags=%x.\n", fcport->vha->host_no, sp->handle, type, - mbx->entry_status, le16_to_cpu(mbx->status), - le16_to_cpu(mbx->state_flags), + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, mbx->entry_status, + le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags), le16_to_cpu(mbx->status_flags))); + DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx))); goto logio_done; @@ -935,9 +938,11 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, status = 0; if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { DEBUG2(printk(KERN_DEBUG - "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n", + "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x " + "mbx1=%x.\n", fcport->vha->host_no, sp->handle, type, - le16_to_cpu(mbx->mb1))); + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1))); data[0] = MBS_COMMAND_COMPLETE; if (ctx->type == SRB_LOGIN_CMD) { @@ -963,9 +968,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, } DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x " - "mb6=%x mb7=%x.\n", - fcport->vha->host_no, sp->handle, type, status, + "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x " + "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", + fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), le16_to_cpu(mbx->mb7))); @@ -1096,9 +1102,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, QLA_LOGIO_LOGIN_RETRIED : 0; if (logio->entry_status) { DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", + "scsi(%ld:%x): Async-%s error entry - " + "portid=%02x%02x%02x entry-status=%x.\n", fcport->vha->host_no, sp->handle, type, - logio->entry_status)); + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, logio->entry_status)); DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio))); goto logio_done; @@ -1106,8 +1114,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { DEBUG2(printk(KERN_DEBUG - "scsi(%ld:%x): Async-%s complete - iop0=%x.\n", + "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x " + "iop0=%x.\n", fcport->vha->host_no, sp->handle, type, + fcport->d_id.b.domain, fcport->d_id.b.area, + fcport->d_id.b.al_pa, le32_to_cpu(logio->io_parameter[0]))); data[0] = MBS_COMMAND_COMPLETE; @@ -1152,8 +1163,10 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, } DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n", - fcport->vha->host_no, sp->handle, type, + "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x " + "iop0=%x iop1=%x.\n", + fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain, + fcport->d_id.b.area, fcport->d_id.b.al_pa, le16_to_cpu(logio->comp_status), le32_to_cpu(logio->io_parameter[0]), le32_to_cpu(logio->io_parameter[1]))); -- cgit v1.2.3-70-g09d2 From 7e2b895b93db603ac3462175baa846ebf1be44da Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:17 -0700 Subject: [SCSI] qla2xxx: Fix cpu-affinity usage for non-capable ISPs. The TMFs used for pre-24xx ISPs incorrectly assumed 'cpu' tag data could be valid. These chips have no multi-q/cpu-affinity support. This corrects an oops seen on ISP23xx parts. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mbx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index f3650d0434c..043f808ba3f 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -866,8 +866,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) l = l; vha = fcport->vha; - req = vha->hw->req_q_map[tag]; - rsp = vha->hw->rsp_q_map[tag]; + req = vha->hw->req_q_map[0]; + rsp = req->rsp; mcp->mb[0] = MBC_ABORT_TARGET; mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) { @@ -915,8 +915,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag) DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no)); vha = fcport->vha; - req = vha->hw->req_q_map[tag]; - rsp = vha->hw->rsp_q_map[tag]; + req = vha->hw->req_q_map[0]; + rsp = req->rsp; mcp->mb[0] = MBC_LUN_RESET; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) -- cgit v1.2.3-70-g09d2 From 083a469db4ecf3b286a96b5b722c37fc1affe0be Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:18 -0700 Subject: [SCSI] qla2xxx: Correct use-after-free oops seen during EH-abort. Hold a reference to the srb (sp) while aborting an I/O -- as the I/O can/will complete from within the interrupt-context. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_os.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 83961090901..f8239bff092 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -202,6 +202,7 @@ struct sd_dif_tuple { * SCSI Request Block */ typedef struct srb { + atomic_t ref_count; struct fc_port *fcport; uint32_t handle; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c345ba71672..9e656296b75 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -517,6 +517,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, if (!sp) return sp; + atomic_set(&sp->ref_count, 1); sp->fcport = fcport; sp->cmd = cmd; sp->flags = 0; @@ -797,6 +798,12 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) return (return_status); } +static void +sp_get(struct srb *sp) +{ + atomic_inc(&sp->ref_count); +} + /************************************************************************** * qla2xxx_eh_abort * @@ -825,6 +832,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) struct qla_hw_data *ha = vha->hw; struct req_que *req = vha->req; srb_t *spt; + int got_ref = 0; fc_block_scsi_eh(cmd); @@ -856,6 +864,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC." " pid=%ld.\n", __func__, vha->host_no, sp, serial)); + /* Get a reference to the sp and drop the lock.*/ + sp_get(sp); + got_ref++; + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops->abort_command(sp)) { DEBUG2(printk("%s(%ld): abort_command " @@ -881,6 +893,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } } + if (got_ref) + qla2x00_sp_compl(ha, sp); + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n", vha->host_no, id, lun, wait, serial, ret); @@ -3468,7 +3483,7 @@ qla2x00_sp_free_dma(srb_t *sp) } void -qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) +qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; @@ -3489,6 +3504,20 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) cmd->scsi_done(cmd); } +void +qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp) +{ + if (atomic_read(&sp->ref_count) == 0) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "SP reference-count to ZERO -- sp=%p\n", sp)); + DEBUG2(BUG()); + return; + } + if (!atomic_dec_and_test(&sp->ref_count)) + return; + qla2x00_sp_final_compl(ha, sp); +} + /************************************************************************** * qla2x00_timer * -- cgit v1.2.3-70-g09d2 From 6ac5260850841eb4055811a68ff47d658ebe9a59 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 28 May 2010 15:08:19 -0700 Subject: [SCSI] qla2xxx: Correct async-srb issues. * hold the hardware_lock throughout the duration of ctx-sp timeout handling -- could result in use-after-free oops. * retry a timed-out login-request. * done() routines are called with the hardware-lock held, issue qla2x00_mark_device_lost() with proper 'defer' flag. * FCP2 capabilities are only relevant to target devices. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 20 ++++++++++++++------ drivers/scsi/qla2xxx/qla_isr.c | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4bf97348381..cc735254508 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -60,9 +60,8 @@ qla2x00_ctx_sp_timeout(unsigned long __data) ctx = sp->ctx; iocb = ctx->u.iocb_cmd; iocb->timeout(sp); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - iocb->free(sp); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } void @@ -137,8 +136,16 @@ qla2x00_async_iocb_timeout(srb_t *sp) fcport->d_id.b.area, fcport->d_id.b.al_pa)); fcport->flags &= ~FCF_ASYNC_SENT; - if (ctx->type == SRB_LOGIN_CMD) + if (ctx->type == SRB_LOGIN_CMD) { + struct srb_iocb *lio = ctx->u.iocb_cmd; qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); + /* Retry as needed. */ + lio->u.logio.data[0] = MBS_COMMAND_ERROR; + lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED : 0; + qla2x00_post_async_login_done_work(fcport->vha, fcport, + lio->u.logio.data); + } } static void @@ -420,10 +427,11 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 0); + qla2x00_mark_device_lost(vha, fcport, 1, 1); break; case MBS_PORT_ID_USED: fcport->loop_id = data[1]; + qla2x00_post_async_logout_work(vha, fcport, NULL); qla2x00_post_async_login_work(vha, fcport, NULL); break; case MBS_LOOP_ID_USED: @@ -431,7 +439,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, rval = qla2x00_find_new_loop_id(vha, fcport); if (rval != QLA_SUCCESS) { fcport->flags &= ~FCF_ASYNC_SENT; - qla2x00_mark_device_lost(vha, fcport, 1, 0); + qla2x00_mark_device_lost(vha, fcport, 1, 1); break; } qla2x00_post_async_login_work(vha, fcport, NULL); @@ -463,7 +471,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, if (data[1] & QLA_LOGIO_LOGIN_RETRIED) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); else - qla2x00_mark_device_lost(vha, fcport, 1, 0); + qla2x00_mark_device_lost(vha, fcport, 1, 1); return; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index bc82ba99f25..912befdceb1 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -949,7 +949,7 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, fcport->port_type = FCT_TARGET; if (le16_to_cpu(mbx->mb1) & BIT_0) fcport->port_type = FCT_INITIATOR; - if (le16_to_cpu(mbx->mb1) & BIT_1) + else if (le16_to_cpu(mbx->mb1) & BIT_1) fcport->flags |= FCF_FCP2_DEVICE; } goto logio_done; -- cgit v1.2.3-70-g09d2 From 3a6478df74c271cb3be5895b39fddf75e9cef89c Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:20 -0700 Subject: [SCSI] qla2xxx: Limit rport-flaps during link-disruptions. Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cc735254508..9d969b596b1 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2651,7 +2651,8 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); if (test_bit(RSCN_UPDATE, &save_flags)) { set_bit(RSCN_UPDATE, &vha->dpc_flags); - vha->flags.rscn_queue_overflow = 1; + if (!IS_ALOGIO_CAPABLE(ha)) + vha->flags.rscn_queue_overflow = 1; } } @@ -3209,8 +3210,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, if (qla2x00_is_reserved_id(vha, loop_id)) continue; - if (atomic_read(&vha->loop_down_timer) || - LOOP_TRANSITION(vha)) { + if (ha->current_topology == ISP_CFG_FL && + (atomic_read(&vha->loop_down_timer) || + LOOP_TRANSITION(vha))) { atomic_set(&vha->loop_down_timer, 0); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); -- cgit v1.2.3-70-g09d2 From 23f2ebd17a13835c5b34994d2c2e5faacc127947 Mon Sep 17 00:00:00 2001 From: Sarang Radke Date: Fri, 28 May 2010 15:08:21 -0700 Subject: [SCSI] qla2xxx: Add internal loopback support for ISP81xx. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 196 +++++++++++++++++++++++++++++++++++++---- drivers/scsi/qla2xxx/qla_bsg.h | 7 ++ drivers/scsi/qla2xxx/qla_def.h | 4 + drivers/scsi/qla2xxx/qla_gbl.h | 5 ++ drivers/scsi/qla2xxx/qla_isr.c | 7 +- drivers/scsi/qla2xxx/qla_mbx.c | 66 ++++++++++++++ drivers/scsi/qla2xxx/qla_os.c | 1 + 7 files changed, 269 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index b905dfe5ea6..3a024838850 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -483,6 +483,98 @@ done: return rval; } +/* Set the port configuration to enable the + * internal loopback on ISP81XX + */ +static inline int +qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, + uint16_t *new_config) +{ + int ret = 0; + int rval = 0; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha)) + goto done_set_internal; + + new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); + memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; + + ha->notify_dcbx_comp = 1; + ret = qla81xx_set_port_config(vha, new_config); + if (ret != QLA_SUCCESS) { + DEBUG2(printk(KERN_ERR + "%s(%lu): Set port config failed\n", + __func__, vha->host_no)); + ha->notify_dcbx_comp = 0; + rval = -EINVAL; + goto done_set_internal; + } + + /* Wait for DCBX complete event */ + if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "State change notificaition not received.\n")); + } else + DEBUG2(qla_printk(KERN_INFO, ha, + "State change RECEIVED\n")); + + ha->notify_dcbx_comp = 0; + +done_set_internal: + return rval; +} + +/* Set the port configuration to disable the + * internal loopback on ISP81XX + */ +static inline int +qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, + int wait) +{ + int ret = 0; + int rval = 0; + uint16_t new_config[4]; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha)) + goto done_reset_internal; + + memset(new_config, 0 , sizeof(new_config)); + if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == + ENABLE_INTERNAL_LOOPBACK) { + new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; + memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; + + ha->notify_dcbx_comp = wait; + ret = qla81xx_set_port_config(vha, new_config); + if (ret != QLA_SUCCESS) { + DEBUG2(printk(KERN_ERR + "%s(%lu): Set port config failed\n", + __func__, vha->host_no)); + ha->notify_dcbx_comp = 0; + rval = -EINVAL; + goto done_reset_internal; + } + + /* Wait for DCBX complete event */ + if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, + (20 * HZ))) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "State change notificaition not received.\n")); + ha->notify_dcbx_comp = 0; + rval = -EINVAL; + goto done_reset_internal; + } else + DEBUG2(qla_printk(KERN_INFO, ha, + "State change RECEIVED\n")); + + ha->notify_dcbx_comp = 0; + } +done_reset_internal: + return rval; +} + static int qla2x00_process_loopback(struct fc_bsg_job *bsg_job) { @@ -494,6 +586,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) char *type; struct msg_echo_lb elreq; uint16_t response[MAILBOX_REGISTER_COUNT]; + uint16_t config[4], new_config[4]; uint8_t *fw_sts_ptr; uint8_t *req_data = NULL; dma_addr_t req_data_dma; @@ -568,29 +661,102 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - if (ha->current_topology != ISP_CFG_F) { - type = "FC_BSG_HST_VENDOR_LOOPBACK"; + if ((ha->current_topology == ISP_CFG_F || + (IS_QLA81XX(ha) && + le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE + && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && + elreq.options == EXTERNAL_LOOPBACK) { + type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; DEBUG2(qla_printk(KERN_INFO, ha, - "scsi(%ld) bsg rqst type: %s\n", - vha->host_no, type)); - - command_sent = INT_DEF_LB_LOOPBACK_CMD; - rval = qla2x00_loopback_test(vha, &elreq, response); + "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type)); + command_sent = INT_DEF_LB_ECHO_CMD; + rval = qla2x00_echo_test(vha, &elreq, response); + } else { if (IS_QLA81XX(ha)) { + memset(config, 0, sizeof(config)); + memset(new_config, 0, sizeof(new_config)); + if (qla81xx_get_port_config(vha, config)) { + DEBUG2(printk(KERN_ERR + "%s(%lu): Get port config failed\n", + __func__, vha->host_no)); + bsg_job->reply->reply_payload_rcv_len = 0; + bsg_job->reply->result = (DID_ERROR << 16); + rval = -EPERM; + goto done_free_dma_req; + } + + if (elreq.options != EXTERNAL_LOOPBACK) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Internal: current port config = %x\n", + config[0])); + if (qla81xx_set_internal_loopback(vha, config, + new_config)) { + bsg_job->reply->reply_payload_rcv_len = + 0; + bsg_job->reply->result = + (DID_ERROR << 16); + rval = -EPERM; + goto done_free_dma_req; + } + } else { + /* For external loopback to work + * ensure internal loopback is disabled + */ + if (qla81xx_reset_internal_loopback(vha, + config, 1)) { + bsg_job->reply->reply_payload_rcv_len = + 0; + bsg_job->reply->result = + (DID_ERROR << 16); + rval = -EPERM; + goto done_free_dma_req; + } + } + + type = "FC_BSG_HST_VENDOR_LOOPBACK"; + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s\n", + vha->host_no, type)); + + command_sent = INT_DEF_LB_LOOPBACK_CMD; + rval = qla2x00_loopback_test(vha, &elreq, response); + + if (new_config[1]) { + /* Revert back to original port config + * Also clear internal loopback + */ + qla81xx_reset_internal_loopback(vha, + new_config, 0); + } + if (response[0] == MBS_COMMAND_ERROR && - response[1] == MBS_LB_RESET) { + response[1] == MBS_LB_RESET) { DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing " - "ISP\n", __func__, vha->host_no)); + "ISP\n", __func__, vha->host_no)); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); + qla2x00_wait_for_chip_reset(vha); + /* Also reset the MPI */ + if (qla81xx_restart_mpi_firmware(vha) != + QLA_SUCCESS) { + qla_printk(KERN_INFO, ha, + "MPI reset failed for host%ld.\n", + vha->host_no); + } + + bsg_job->reply->reply_payload_rcv_len = 0; + bsg_job->reply->result = (DID_ERROR << 16); + rval = -EIO; + goto done_free_dma_req; } + } else { + type = "FC_BSG_HST_VENDOR_LOOPBACK"; + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld) bsg rqst type: %s\n", + vha->host_no, type)); + command_sent = INT_DEF_LB_LOOPBACK_CMD; + rval = qla2x00_loopback_test(vha, &elreq, response); } - } else { - type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; - DEBUG2(qla_printk(KERN_INFO, ha, - "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type)); - command_sent = INT_DEF_LB_ECHO_CMD; - rval = qla2x00_echo_test(vha, &elreq, response); } if (rval) { diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 76ed92dd2ef..1f096dabc01 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -19,6 +19,13 @@ #define INT_DEF_LB_LOOPBACK_CMD 0 #define INT_DEF_LB_ECHO_CMD 1 +/* Loopback related definations */ +#define EXTERNAL_LOOPBACK 0xF2 +#define ENABLE_INTERNAL_LOOPBACK 0x02 +#define INTERNAL_LOOPBACK_MASK 0x000E +#define MAX_ELS_FRAME_PAYLOAD 252 +#define ELS_OPCODE_BYTE 0x10 + /* BSG Vendor specific definations */ #define A84_ISSUE_WRITE_TYPE_CMD 0 #define A84_ISSUE_READ_TYPE_CMD 1 diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index f8239bff092..2895855adc9 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -714,6 +714,8 @@ typedef struct { #define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */ #define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ #define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ +#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */ +#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */ /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -2631,6 +2633,8 @@ struct qla_hw_data { struct mutex vport_lock; /* Virtual port synchronization */ struct completion mbx_cmd_comp; /* Serialize mbx access */ struct completion mbx_intr_comp; /* Used for completion notification */ + struct completion dcbx_comp; /* For set port config notification */ + int notify_dcbx_comp; /* Basic firmware related information. */ uint16_t fw_major_version; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 2247ef8702e..7ae2ee42564 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -357,6 +357,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_get_data_rate(scsi_qla_host_t *); extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); +extern int +qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *); + +extern int +qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *); /* * Global Function Prototypes in qla_isr.c source file. diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 912befdceb1..e51fc5f9fcd 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -545,10 +545,13 @@ skip_rio: if (IS_QLA2100(ha)) break; - if (IS_QLA8XXX_TYPE(ha)) + if (IS_QLA8XXX_TYPE(ha)) { DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x " "%04x\n", vha->host_no, mb[1], mb[2], mb[3])); - else + if (ha->notify_dcbx_comp) + complete(&ha->dcbx_comp); + + } else DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE " "received.\n", vha->host_no)); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 043f808ba3f..10f4815aec7 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -3949,6 +3949,72 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) return rval; } +int +qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + + DEBUG11(printk(KERN_INFO + "%s(%ld): entered.\n", __func__, vha->host_no)); + + if (!IS_QLA81XX(ha)) + return QLA_FUNCTION_FAILED; + mcp->mb[0] = MBC_GET_PORT_CONFIG; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk(KERN_WARNING + "%s(%ld): failed=%x (%x).\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else { + /* Copy all bits to preserve original value */ + memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4); + + DEBUG11(printk(KERN_INFO + "%s(%ld): done.\n", __func__, vha->host_no)); + } + return rval; +} + +int +qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + DEBUG11(printk(KERN_INFO + "%s(%ld): entered.\n", __func__, vha->host_no)); + + mcp->mb[0] = MBC_SET_PORT_CONFIG; + /* Copy all bits to preserve original setting */ + memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4); + mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk(KERN_WARNING + "%s(%ld): failed=%x (%x).\n", __func__, + vha->host_no, rval, mcp->mb[0])); + } else + DEBUG11(printk(KERN_INFO + "%s(%ld): done.\n", __func__, vha->host_no)); + + return rval; +} + + int qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, uint16_t *mb) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9e656296b75..fa59181bcb0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2128,6 +2128,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) init_completion(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp); init_completion(&ha->mbx_intr_comp); + init_completion(&ha->dcbx_comp); set_bit(0, (unsigned long *) ha->vp_idx_map); -- cgit v1.2.3-70-g09d2 From b0cd579cde8ee0c7ed52239531ba09bcbc5b54c2 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 28 May 2010 15:08:22 -0700 Subject: [SCSI] qla2xxx: Make the FC port capability mutual exclusive. In case of both target and initiator capabilities reported by fc port, the fc port port capability is made mutualy exclusive with priority given for target capabilities. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e51fc5f9fcd..8a608725eb7 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1133,9 +1133,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, fcport->port_type = FCT_TARGET; if (iop[0] & BIT_8) fcport->flags |= FCF_FCP2_DEVICE; - } - if (iop[0] & BIT_5) + } else if (iop[0] & BIT_5) fcport->port_type = FCT_INITIATOR; + if (logio->io_parameter[7] || logio->io_parameter[8]) fcport->supported_classes |= FC_COS_CLASS2; if (logio->io_parameter[9] || logio->io_parameter[10]) -- cgit v1.2.3-70-g09d2 From 9c2b297572bf3cc36d26520cd8f7e7ef4cb857f8 Mon Sep 17 00:00:00 2001 From: Harish Zunjarrao Date: Fri, 28 May 2010 15:08:23 -0700 Subject: [SCSI] qla2xxx: Support for loading Unified ROM Image (URI) format firmware file. Used bootloder address from FLT while loading FW from flash as well. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 3 + drivers/scsi/qla2xxx/qla_nx.c | 184 +++++++++++++++++++++++++++++++++++++++-- drivers/scsi/qla2xxx/qla_nx.h | 35 ++++++++ 3 files changed, 215 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2895855adc9..f0e792a82dd 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2788,6 +2788,9 @@ struct qla_hw_data { uint16_t gbl_dsd_avail; struct list_head gbl_dsd_list; #define NUM_DSD_CHAIN 4096 + + uint8_t fw_type; + __le32 file_prd_off; /* File firmware product offset */ }; /* diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index eb12bf260a1..1a9a7343dff 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1407,7 +1407,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha) { int i; long size = 0; - long flashaddr = BOOTLD_START, memaddr = BOOTLD_START; + long flashaddr = ha->flt_region_bootload << 2; + long memaddr = BOOTLD_START; u64 data; u32 high, low; size = (IMAGE_START - BOOTLD_START) / 8; @@ -1677,6 +1678,94 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, return ret; } +static struct qla82xx_uri_table_desc * +qla82xx_get_table_desc(const u8 *unirom, int section) +{ + uint32_t i; + struct qla82xx_uri_table_desc *directory = + (struct qla82xx_uri_table_desc *)&unirom[0]; + __le32 offset; + __le32 tab_type; + __le32 entries = cpu_to_le32(directory->num_entries); + + for (i = 0; i < entries; i++) { + offset = cpu_to_le32(directory->findex) + + (i * cpu_to_le32(directory->entry_size)); + tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8)); + + if (tab_type == section) + return (struct qla82xx_uri_table_desc *)&unirom[offset]; + } + + return NULL; +} + +static struct qla82xx_uri_data_desc * +qla82xx_get_data_desc(struct qla_hw_data *ha, + u32 section, u32 idx_offset) +{ + const u8 *unirom = ha->hablob->fw->data; + int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset)); + struct qla82xx_uri_table_desc *tab_desc = NULL; + __le32 offset; + + tab_desc = qla82xx_get_table_desc(unirom, section); + if (!tab_desc) + return NULL; + + offset = cpu_to_le32(tab_desc->findex) + + (cpu_to_le32(tab_desc->entry_size) * idx); + + return (struct qla82xx_uri_data_desc *)&unirom[offset]; +} + +static u8 * +qla82xx_get_bootld_offset(struct qla_hw_data *ha) +{ + u32 offset = BOOTLD_START; + struct qla82xx_uri_data_desc *uri_desc = NULL; + + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, + QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF); + if (uri_desc) + offset = cpu_to_le32(uri_desc->findex); + } + + return (u8 *)&ha->hablob->fw->data[offset]; +} + +static __le32 +qla82xx_get_fw_size(struct qla_hw_data *ha) +{ + struct qla82xx_uri_data_desc *uri_desc = NULL; + + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, + QLA82XX_URI_FIRMWARE_IDX_OFF); + if (uri_desc) + return cpu_to_le32(uri_desc->size); + } + + return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]); +} + +static u8 * +qla82xx_get_fw_offs(struct qla_hw_data *ha) +{ + u32 offset = IMAGE_START; + struct qla82xx_uri_data_desc *uri_desc = NULL; + + if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, + QLA82XX_URI_FIRMWARE_IDX_OFF); + if (uri_desc) + offset = cpu_to_le32(uri_desc->findex); + } + + return (u8 *)&ha->hablob->fw->data[offset]; +} + /* PCI related functions */ char * qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str) @@ -1878,19 +1967,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) size = (IMAGE_START - BOOTLD_START) / 8; - ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START]; + ptr64 = (u64 *)qla82xx_get_bootld_offset(ha); flashaddr = BOOTLD_START; for (i = 0; i < size; i++) { data = cpu_to_le64(ptr64[i]); - qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8); + if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) + return -EIO; flashaddr += 8; } - size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]; - size = (__force u32)cpu_to_le32(size) / 8; - ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START]; flashaddr = FLASH_ADDR_START; + size = (__force u32)qla82xx_get_fw_size(ha) / 8; + ptr64 = (u64 *)qla82xx_get_fw_offs(ha); for (i = 0; i < size; i++) { data = cpu_to_le64(ptr64[i]); @@ -1899,19 +1988,88 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) return -EIO; flashaddr += 8; } + udelay(100); /* Write a magic value to CAMRAM register * at a specified offset to indicate * that all data is written and * ready for firmware to initialize. */ - qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678); + qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC); + read_lock(&ha->hw_lock); if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); } else qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); + read_unlock(&ha->hw_lock); + return 0; +} + +static int +qla82xx_set_product_offset(struct qla_hw_data *ha) +{ + struct qla82xx_uri_table_desc *ptab_desc = NULL; + const uint8_t *unirom = ha->hablob->fw->data; + uint32_t i; + __le32 entries; + __le32 flags, file_chiprev, offset; + uint8_t chiprev = ha->chip_revision; + /* Hardcoding mn_present flag for P3P */ + int mn_present = 0; + uint32_t flagbit; + + ptab_desc = qla82xx_get_table_desc(unirom, + QLA82XX_URI_DIR_SECT_PRODUCT_TBL); + if (!ptab_desc) + return -1; + + entries = cpu_to_le32(ptab_desc->num_entries); + + for (i = 0; i < entries; i++) { + offset = cpu_to_le32(ptab_desc->findex) + + (i * cpu_to_le32(ptab_desc->entry_size)); + flags = cpu_to_le32(*((int *)&unirom[offset] + + QLA82XX_URI_FLAGS_OFF)); + file_chiprev = cpu_to_le32(*((int *)&unirom[offset] + + QLA82XX_URI_CHIP_REV_OFF)); + + flagbit = mn_present ? 1 : 2; + + if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) { + ha->file_prd_off = offset; + return 0; + } + } + return -1; +} + +int +qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type) +{ + __le32 val; + uint32_t min_size; + struct qla_hw_data *ha = vha->hw; + const struct firmware *fw = ha->hablob->fw; + + ha->fw_type = fw_type; + + if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) { + if (qla82xx_set_product_offset(ha)) + return -EINVAL; + + min_size = QLA82XX_URI_FW_MIN_SIZE; + } else { + val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]); + if ((__force u32)val != QLA82XX_BDINFO_MAGIC) + return -EINVAL; + + min_size = QLA82XX_FW_MIN_SIZE; + } + + if (fw->size < min_size) + return -EINVAL; return 0; } @@ -2470,6 +2628,18 @@ try_blob_fw: goto fw_load_failed; } + /* Validating firmware blob */ + if (qla82xx_validate_firmware_blob(vha, + QLA82XX_FLASH_ROMIMAGE)) { + /* Fallback to URI format */ + if (qla82xx_validate_firmware_blob(vha, + QLA82XX_UNIFIED_ROMIMAGE)) { + qla_printk(KERN_ERR, ha, + "No valid firmware image found!!!"); + return QLA_FUNCTION_FAILED; + } + } + if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "%s: Firmware loaded successfully " diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index aa95d3816d6..9a9127efada 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -773,13 +773,48 @@ struct qla82xx_legacy_intr_set { .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ } +#define BRDCFG_START 0x4000 #define BOOTLD_START 0x10000 #define IMAGE_START 0x100000 #define FLASH_ADDR_START 0x43000 /* Magic number to let user know flash is programmed */ #define QLA82XX_BDINFO_MAGIC 0x12345678 +#define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128) #define FW_SIZE_OFFSET (0x3e840c) +#define QLA82XX_FW_MIN_SIZE 0x3fffff + +/* UNIFIED ROMIMAGE START */ +#define QLA82XX_URI_FW_MIN_SIZE 0xc8000 +#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0 +#define QLA82XX_URI_DIR_SECT_BOOTLD 0x6 +#define QLA82XX_URI_DIR_SECT_FW 0x7 + +/* Offsets */ +#define QLA82XX_URI_CHIP_REV_OFF 10 +#define QLA82XX_URI_FLAGS_OFF 11 +#define QLA82XX_URI_BIOS_VERSION_OFF 12 +#define QLA82XX_URI_BOOTLD_IDX_OFF 27 +#define QLA82XX_URI_FIRMWARE_IDX_OFF 29 + +struct qla82xx_uri_table_desc{ + uint32_t findex; + uint32_t num_entries; + uint32_t entry_size; + uint32_t reserved[5]; +}; + +struct qla82xx_uri_data_desc{ + uint32_t findex; + uint32_t size; + uint32_t reserved[5]; +}; + +/* UNIFIED ROMIMAGE END */ + +#define QLA82XX_UNIFIED_ROMIMAGE 3 +#define QLA82XX_FLASH_ROMIMAGE 4 +#define QLA82XX_UNKNOWN_ROMIMAGE 0xff #define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50) #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) -- cgit v1.2.3-70-g09d2 From 3f3b6f98cb33043cba04f45a2f2c43b8303c120c Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 28 May 2010 15:08:24 -0700 Subject: [SCSI] qla2xxx: Do not enable VP in non fabric topology. After topology change ISP is reset and VPs are re-enabled. If the topology is not fabric, VPs could falsely get enabled. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8220e7b9799..d1618b4a5e5 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -136,7 +136,8 @@ qla24xx_enable_vp(scsi_qla_host_t *vha) /* Check if physical ha port is Up */ if (atomic_read(&base_vha->loop_state) == LOOP_DOWN || - atomic_read(&base_vha->loop_state) == LOOP_DEAD) { + atomic_read(&base_vha->loop_state) == LOOP_DEAD || + !(ha->current_topology & ISP_CFG_F)) { vha->vp_err_state = VP_ERR_PORTDWN; fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN); goto enable_failed; -- cgit v1.2.3-70-g09d2 From cdbb0a4f31c486e4f6fb6e673a892f4f5205f91c Mon Sep 17 00:00:00 2001 From: Santosh Vernekar Date: Fri, 28 May 2010 15:08:25 -0700 Subject: [SCSI] qla2xxx: Handle outstanding mbx cmds on hung f/w scenarios. Outstanding mailbox commands, have no way to recover on f/w hung, and we timeout on waiting for mbx response. This in turn affects the recovery process as follows: - We might already be in dpc while waiting for mbx to complete, so recovery for that pci function will never get invoked. Reset Timeout (10 sec) is far less than mbx timeout (30 sec). - Other mbx cmds will get stuck due to serial mbx access. Solution is to identify fw-hung scenario and handle outstanding mbx commands to have an early-exit instead of waiting for response. Other mbx commands waiting for access will also do an early-exit if fw-hung is still applicable. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 3 +- drivers/scsi/qla2xxx/qla_mbx.c | 78 +++++++++++++++++++++++++++++------------ drivers/scsi/qla2xxx/qla_nx.c | 20 ++++++++++- 4 files changed, 78 insertions(+), 24 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index f0e792a82dd..2bb187e23db 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2413,6 +2413,7 @@ struct qla_hw_data { uint32_t cpu_affinity_enabled :1; uint32_t disable_msix_handshake :1; uint32_t fcp_prio_enabled :1; + uint32_t fw_hung :1; } flags; /* This spinlock is used to protect "io transactions", you must diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9d969b596b1..4c6caccc6ad 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1972,7 +1972,8 @@ qla2x00_fw_ready(scsi_qla_host_t *vha) } } else { /* Mailbox cmd failed. Timeout on min_wait. */ - if (time_after_eq(jiffies, mtime)) + if (time_after_eq(jiffies, mtime) || + (IS_QLA82XX(ha) && ha->flags.fw_hung)) break; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 10f4815aec7..2f39e309393 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -37,7 +37,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) device_reg_t __iomem *reg; uint8_t abort_active; uint8_t io_lock_on; - uint16_t command; + uint16_t command = 0; uint16_t *iptr; uint16_t __iomem *optr; uint32_t cnt; @@ -83,6 +83,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) return QLA_FUNCTION_TIMEOUT; } + if (IS_QLA82XX(ha) && ha->flags.fw_hung) { + /* Setting Link-Down error */ + mcp->mb[0] = MBS_LINK_DOWN_ERROR; + rval = QLA_FUNCTION_FAILED; + goto premature_exit; + } + ha->flags.mbox_busy = 1; /* Save mailbox command for debug */ ha->mcp = mcp; @@ -151,7 +158,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) DEBUG2_3_11(printk(KERN_INFO "%s(%ld): Pending Mailbox timeout. " "Exiting.\n", __func__, base_vha->host_no)); - return QLA_FUNCTION_TIMEOUT; + rval = QLA_FUNCTION_TIMEOUT; + goto premature_exit; } WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); } else if (IS_FWI2_CAPABLE(ha)) @@ -176,7 +184,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) DEBUG2_3_11(printk(KERN_INFO "%s(%ld): Pending Mailbox timeout. " "Exiting.\n", __func__, base_vha->host_no)); - return QLA_FUNCTION_TIMEOUT; + rval = QLA_FUNCTION_TIMEOUT; + goto premature_exit; } WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); } else if (IS_FWI2_CAPABLE(ha)) @@ -214,6 +223,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ha->flags.mbox_int = 0; clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); + if (IS_QLA82XX(ha) && ha->flags.fw_hung) { + ha->flags.mbox_busy = 0; + /* Setting Link-Down error */ + mcp->mb[0] = MBS_LINK_DOWN_ERROR; + ha->mcp = NULL; + rval = QLA_FUNCTION_FAILED; + goto premature_exit; + } + if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) rval = QLA_FUNCTION_FAILED; @@ -279,35 +297,51 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) DEBUG2_3_11(printk("%s(%ld): timeout schedule " "isp_abort_needed.\n", __func__, base_vha->host_no)); - qla_printk(KERN_WARNING, ha, - "Mailbox command timeout occurred. Scheduling ISP " - "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy); - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); - qla2xxx_wake_dpc(vha); + + if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && + !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && + !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { + + qla_printk(KERN_WARNING, ha, + "Mailbox command timeout occured. " + "Scheduling ISP " "abort. eeh_busy: 0x%x\n", + ha->flags.eeh_busy); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } } else if (!abort_active) { /* call abort directly since we are in the DPC thread */ DEBUG(printk("%s(%ld): timeout calling abort_isp\n", __func__, base_vha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout calling " "abort_isp\n", __func__, base_vha->host_no)); - qla_printk(KERN_WARNING, ha, - "Mailbox command timeout occurred. Issuing ISP " - "abort.\n"); - - set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); - if (ha->isp_ops->abort_isp(base_vha)) { - /* Failed. retry later. */ - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); + + if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && + !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && + !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { + + qla_printk(KERN_WARNING, ha, + "Mailbox command timeout occured. " + "Issuing ISP abort.\n"); + + set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); + clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + if (ha->isp_ops->abort_isp(vha)) { + /* Failed. retry later. */ + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + } + clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); + DEBUG(printk("%s(%ld): finished abort_isp\n", + __func__, vha->host_no)); + DEBUG2_3_11(printk( + "%s(%ld): finished abort_isp\n", + __func__, vha->host_no)); } - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - DEBUG(printk("%s(%ld): finished abort_isp\n", __func__, - base_vha->host_no)); - DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n", - __func__, base_vha->host_no)); } } +premature_exit: /* Allow next mbx cmd to come in. */ complete(&ha->mbx_cmd_comp); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 1a9a7343dff..512ba8a4ac5 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3543,6 +3543,14 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); } qla2xxx_wake_dpc(vha); + if (ha->flags.mbox_busy) { + ha->flags.fw_hung = 1; + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Due to fw hung, doing premature " + "completion of mbx command\n")); + complete(&ha->mbx_intr_comp); + } } } vha->fw_heartbeat_counter = fw_heartbeat_counter; @@ -3646,6 +3654,14 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) "%s(): Adapter reset needed!\n", __func__); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); + if (ha->flags.mbox_busy) { + ha->flags.fw_hung = 1; + ha->flags.mbox_int = 1; + DEBUG2(qla_printk(KERN_ERR, ha, + "Need reset, doing premature " + "completion of mbx command\n")); + complete(&ha->mbx_intr_comp); + } } else { qla82xx_check_fw_alive(vha); } @@ -3701,8 +3717,10 @@ qla82xx_abort_isp(scsi_qla_host_t *vha) qla82xx_clear_rst_ready(ha); qla82xx_idc_unlock(ha); - if (rval == QLA_SUCCESS) + if (rval == QLA_SUCCESS) { + ha->flags.fw_hung = 0; qla82xx_restart_isp(vha); + } if (rval) { vha->flags.online = 1; -- cgit v1.2.3-70-g09d2 From 0547fb37ca1f8da18e65b7452f99e9784f026be2 Mon Sep 17 00:00:00 2001 From: Lalit Chandivade Date: Fri, 28 May 2010 15:08:26 -0700 Subject: [SCSI] qla2xxx: Fix flash write failure on ISP82xx. Driver was not unprotecting correctly, use correct bits to unprotect the flash on ISP 82xx. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 512ba8a4ac5..ee575b4efbe 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -19,6 +19,7 @@ #define QLA82XX_PCI_OCM0_2M (0xc0000) #define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) #define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) +#define BLOCK_PROTECT_BITS 0x0F /* CRB window related */ #define CRB_BLK(off) ((off >> 20) & 0x3f) @@ -3147,10 +3148,10 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha) if (ret < 0) goto done_unprotect; - val &= ~(0x7 << 2); + val &= ~(BLOCK_PROTECT_BITS << 2); ret = qla82xx_write_status_reg(ha, val); if (ret < 0) { - val |= (0x7 << 2); + val |= (BLOCK_PROTECT_BITS << 2); qla82xx_write_status_reg(ha, val); } @@ -3178,7 +3179,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha) if (ret < 0) goto done_protect; - val |= (0x7 << 2); + val |= (BLOCK_PROTECT_BITS << 2); /* LOCK all sectors */ ret = qla82xx_write_status_reg(ha, val); if (ret < 0) -- cgit v1.2.3-70-g09d2 From ba77ef53547883b6be06c0657d5dc1642ad43d0c Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Fri, 28 May 2010 15:08:27 -0700 Subject: [SCSI] qla2xxx: T10 DIF enablement for 81XX Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 1e4cafabba1..2b499c7601e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1732,7 +1732,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); } - if (IS_QLA25XX(ha) && ql2xenabledif) { + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { vha->flags.difdix_supported = 1; DEBUG18(qla_printk(KERN_INFO, ha, diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fa59181bcb0..bc35ecfbc28 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1677,7 +1677,7 @@ static struct isp_operations qla81xx_isp_ops = { .read_optrom = qla25xx_read_optrom_data, .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_start_scsi, + .start_scsi = qla24xx_dif_start_scsi, .abort_isp = qla2x00_abort_isp, }; @@ -2274,7 +2274,7 @@ skip_dpc: DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", base_vha->host_no, ha)); - if (IS_QLA25XX(ha) && ql2xenabledif) { + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) { if (ha->fw_attributes & BIT_4) { base_vha->flags.difdix_supported = 1; DEBUG18(qla_printk(KERN_INFO, ha, -- cgit v1.2.3-70-g09d2 From 6907869d726c04362122afd92717f86915a69f96 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:28 -0700 Subject: [SCSI] qla2xxx: Enable CRB based doorbell posting for request queue as default for ISP 82xx. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 13 +++++++++---- drivers/scsi/qla2xxx/qla_os.c | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index ee575b4efbe..e3e3ebdfe5d 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3372,11 +3372,16 @@ qla82xx_start_iocbs(srb_t *sp) dbval = 0x04 | (ha->portnum << 5); dbval = dbval | (req->id << 8) | (req->ring_index << 16); - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); - wmb(); - while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); + if (ql2xdbwr) + qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); + else { + WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); wmb(); + while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { + WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, + dbval); + wmb(); + } } } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index bc35ecfbc28..5be8db74896 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -140,7 +140,7 @@ MODULE_PARM_DESC(ql2xetsenable, "Enables firmware ETS burst." "Default is 0 - skip ETS enablement."); -int ql2xdbwr; +int ql2xdbwr = 1; module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xdbwr, "Option to specify scheme for request queue posting\n" -- cgit v1.2.3-70-g09d2 From 6c7ccf7bb96a0ae16d2bcc6155e1d1fc3e728b39 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:29 -0700 Subject: [SCSI] qla2xxx: Removed redundant check for ISP 84xx. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 2b499c7601e..fd6f7b10054 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1208,7 +1208,7 @@ qla24xx_84xx_fw_version_show(struct device *dev, if (!IS_QLA84XX(ha)) return snprintf(buf, PAGE_SIZE, "\n"); - if (ha->cs84xx && ha->cs84xx->op_fw_version == 0) + if (ha->cs84xx->op_fw_version == 0) rval = qla84xx_verify_chip(vha, status); if ((rval == QLA_SUCCESS) && (status[0] == 0)) -- cgit v1.2.3-70-g09d2 From 5b91490e457a88080b4dbc68f4bc2eadd65e30ea Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 28 May 2010 15:08:30 -0700 Subject: [SCSI] qla2xxx: For ISP 23xx, select user specified login timeout value if greater than minuimum value(4 secs). Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4c6caccc6ad..d0b993c8a18 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -121,7 +121,23 @@ done: /* Asynchronous Login/Logout Routines -------------------------------------- */ -#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2) +static inline unsigned long +qla2x00_get_async_timeout(struct scsi_qla_host *vha) +{ + unsigned long tmo; + struct qla_hw_data *ha = vha->hw; + + /* Firmware should use switch negotiated r_a_tov for timeout. */ + tmo = ha->r_a_tov / 10 * 2; + if (!IS_FWI2_CAPABLE(ha)) { + /* + * Except for earlier ISPs where the timeout is seeded from the + * initialization control block. + */ + tmo = ha->login_timeout; + } + return tmo; +} static void qla2x00_async_iocb_timeout(srb_t *sp) @@ -163,7 +179,6 @@ int qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { - struct qla_hw_data *ha = vha->hw; srb_t *sp; struct srb_ctx *ctx; struct srb_iocb *lio; @@ -171,7 +186,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, rval = QLA_FUNCTION_FAILED; sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), - ELS_TMO_2_RATOV(ha) + 2); + qla2x00_get_async_timeout(vha) + 2); if (!sp) goto done; @@ -215,7 +230,6 @@ qla2x00_async_logout_ctx_done(srb_t *sp) int qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) { - struct qla_hw_data *ha = vha->hw; srb_t *sp; struct srb_ctx *ctx; struct srb_iocb *lio; @@ -223,7 +237,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) rval = QLA_FUNCTION_FAILED; sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), - ELS_TMO_2_RATOV(ha) + 2); + qla2x00_get_async_timeout(vha) + 2); if (!sp) goto done; @@ -264,7 +278,6 @@ int qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { - struct qla_hw_data *ha = vha->hw; srb_t *sp; struct srb_ctx *ctx; struct srb_iocb *lio; @@ -272,7 +285,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, rval = QLA_FUNCTION_FAILED; sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), - ELS_TMO_2_RATOV(ha) + 2); + qla2x00_get_async_timeout(vha) + 2); if (!sp) goto done; @@ -316,7 +329,6 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, uint32_t tag) { struct scsi_qla_host *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; srb_t *sp; struct srb_ctx *ctx; struct srb_iocb *tcf; @@ -324,7 +336,7 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, rval = QLA_FUNCTION_FAILED; sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), - ELS_TMO_2_RATOV(ha) + 2); + qla2x00_get_async_timeout(vha) + 2); if (!sp) goto done; @@ -2409,7 +2421,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) ha->retry_count = nv->retry_count; /* Set minimum login_timeout to 4 seconds. */ - if (nv->login_timeout < ql2xlogintimeout) + if (nv->login_timeout != ql2xlogintimeout) nv->login_timeout = ql2xlogintimeout; if (nv->login_timeout < 4) nv->login_timeout = 4; -- cgit v1.2.3-70-g09d2 From c0ff2775a1dcbaf2cbe3fb571ae5ea11b63ea590 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 28 May 2010 15:08:31 -0700 Subject: [SCSI] qla2xxx: Updated version number to 8.03.03-k0. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 109068df933..9b49b086274 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.02-k2" +#define QLA2XXX_VERSION "8.03.03-k0" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 -#define QLA_DRIVER_PATCH_VER 2 -#define QLA_DRIVER_BETA_VER 2 +#define QLA_DRIVER_PATCH_VER 3 +#define QLA_DRIVER_BETA_VER 0 -- cgit v1.2.3-70-g09d2 From da2907ffd08a2d708c829ec171f05fe3ceab1315 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 30 May 2010 15:49:22 +0200 Subject: [SCSI] dpt_i2o: Use GFP_ATOMIC when a lock is held The function adpt_i2o_post_wait is called from several places, in some of which, such as adpt_abort, a lock may be held. The functions adpt_i2o_reparse_lct and adpt_i2o_lct_get are called from several places, including adpt_rescan where a lock may be held. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @gfp exists@ identifier fn; position p; @@ fn(...) { ... when != spin_unlock_irqrestore when any GFP_KERNEL@p ... when any } @locked@ identifier gfp.fn; @@ spin_lock_irqsave(...) ... when != spin_unlock_irqrestore fn(...) @depends on locked@ position gfp.p; @@ - GFP_KERNEL@p + GFP_ATOMIC // Signed-off-by: Julia Lawall Signed-off-by: James Bottomley --- drivers/scsi/dpt_i2o.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index b0c576f84b2..f2d4df14c31 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1290,7 +1290,7 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout) ulong flags = 0; struct adpt_i2o_post_wait_data *p1, *p2; struct adpt_i2o_post_wait_data *wait_data = - kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL); + kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC); DECLARE_WAITQUEUE(wait, current); if (!wait_data) @@ -2651,7 +2651,8 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) pDev = pDev->next_lun; } if(!pDev ) { // Something new add it - d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL); + d = kmalloc(sizeof(struct i2o_device), + GFP_ATOMIC); if(d==NULL) { printk(KERN_CRIT "Out of memory for I2O device data.\n"); @@ -2673,7 +2674,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) } pDev = pHba->channel[bus_no].device[scsi_id]; if( pDev == NULL){ - pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = + kzalloc(sizeof(struct adpt_device), + GFP_ATOMIC); if(pDev == NULL) { return -ENOMEM; } @@ -2682,7 +2685,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) while (pDev->next_lun) { pDev = pDev->next_lun; } - pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = pDev->next_lun = + kzalloc(sizeof(struct adpt_device), + GFP_ATOMIC); if(pDev == NULL) { return -ENOMEM; } @@ -3127,7 +3132,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba) if (pHba->lct == NULL) { pHba->lct = dma_alloc_coherent(&pHba->pDev->dev, pHba->lct_size, &pHba->lct_pa, - GFP_KERNEL); + GFP_ATOMIC); if(pHba->lct == NULL) { printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", pHba->name); -- cgit v1.2.3-70-g09d2 From 8701f18504751a5b89be3203e28c5ec04c147167 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Fri, 4 Jun 2010 10:26:50 -0700 Subject: [SCSI] ipr: add endian swap enablement for 64 bit adapters A change in the hardware design of the chip for the new adapters changes the default endianness of MMIO operations. This patch adds a register definition which when written to with a predefined value will change the endianness back to what the driver expects. This patch also fixes two problems found during testing. First, the first reserved field in the ipr_hostrcb64_fabirc_desc structure only reserved one byte. The correct amount to reserve is 2 bytes. Second, the reserved field of the ipr_hostrcb64_error structure only reserved 2 bytes. The correct amount to reserve is 16 bytes. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 19 +++++++++++++++++-- drivers/scsi/ipr.h | 9 +++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f820cffb7f0..62bbe31dd47 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -167,7 +167,8 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { .clr_uproc_interrupt_reg32 = 0x0002C, .init_feedback_reg = 0x0005C, .dump_addr_reg = 0x00064, - .dump_data_reg = 0x00068 + .dump_data_reg = 0x00068, + .endian_swap_reg = 0x00084 } }, }; @@ -7208,6 +7209,12 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) ipr_init_ioa_mem(ioa_cfg); ioa_cfg->allow_interrupts = 1; + if (ioa_cfg->sis64) { + /* Set the adapter to the correct endian mode. */ + writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg); + int_reg = readl(ioa_cfg->regs.endian_swap_reg); + } + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { @@ -7365,6 +7372,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + volatile u32 int_reg; int rc; ENTER; @@ -7383,6 +7391,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) ipr_fail_all_ops(ioa_cfg); + if (ioa_cfg->sis64) { + /* Set the adapter to the correct endian mode. */ + writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg); + int_reg = readl(ioa_cfg->regs.endian_swap_reg); + } + if (ioa_cfg->ioa_unit_checked) { ioa_cfg->ioa_unit_checked = 0; ipr_get_unit_check_buffer(ioa_cfg); @@ -7547,7 +7561,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) } /** - * ipr_reset_alert_part2 - Alert the adapter of a pending reset + * ipr_reset_alert - Alert the adapter of a pending reset * @ipr_cmd: ipr command struct * * Description: This function alerts the adapter that it will be reset. @@ -8318,6 +8332,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, t->init_feedback_reg = base + p->init_feedback_reg; t->dump_addr_reg = base + p->dump_addr_reg; t->dump_data_reg = base + p->dump_data_reg; + t->endian_swap_reg = base + p->endian_swap_reg; } } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index b965f3587c9..ea391ffc871 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -996,7 +996,7 @@ struct ipr_hostrcb64_fabric_desc { __be16 length; u8 descriptor_id; - u8 reserved; + u8 reserved[2]; u8 path_state; u8 reserved2[2]; @@ -1054,7 +1054,7 @@ struct ipr_hostrcb64_error { __be64 fd_lun; u8 fd_res_path[8]; __be64 time_stamp; - u8 reserved[2]; + u8 reserved[16]; union { struct ipr_hostrcb_type_ff_error type_ff_error; struct ipr_hostrcb_type_12_error type_12_error; @@ -1254,6 +1254,9 @@ struct ipr_interrupt_offsets { unsigned long dump_addr_reg; unsigned long dump_data_reg; + +#define IPR_ENDIAN_SWAP_KEY 0x000C0C00 + unsigned long endian_swap_reg; }; struct ipr_interrupts { @@ -1279,6 +1282,8 @@ struct ipr_interrupts { void __iomem *dump_addr_reg; void __iomem *dump_data_reg; + + void __iomem *endian_swap_reg; }; struct ipr_chip_cfg_t { -- cgit v1.2.3-70-g09d2 From ffc954936b134cc6d2eba1282cc71084929c3704 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:23:17 -0400 Subject: [SCSI] lpfc 8.3.13: FC Discovery Fixes and enhancements. - Retry PLOGI up to 48 times when LS_RJT reason is "Unable to supply requested data." - When dev loss timeout occures do not change state if there is an outstanding REG_LOGIN. - Add logic to ignore REG_LOGIN completion if discovery is restarted while waiting for REG_LOGIN. - Only change state on REG_LOGIN completion if still in state waiting for REG_LOGIN completion. - Only send ADISCs to FCP-2 Targets (not Initiators). Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_disc.h | 2 ++ drivers/scsi/lpfc/lpfc_els.c | 9 +++++++++ drivers/scsi/lpfc/lpfc_hbadisc.c | 35 ++++++++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_nportdisc.c | 7 ++++++- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index fbc9baeb604..6b404e510a3 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -41,6 +41,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, LPFC_MBOXQ_t *, uint32_t); +void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 36257a68550..7cae69de36f 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -114,6 +114,8 @@ struct lpfc_nodelist { }; /* Defines for nlp_flag (uint32) */ +#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */ +#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */ #define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ #define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ #define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c4c7f0ad746..6b1850c9fdf 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2740,6 +2740,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; break; } + if (stat.un.b.lsRjtRsnCodeExp == + LSEXP_CANT_GIVE_DATA) { + if (cmd == ELS_CMD_PLOGI) { + delay = 1000; + maxretry = 48; + } + retry = 1; + break; + } if (cmd == ELS_CMD_PLOGI) { delay = 1000; maxretry = lpfc_max_els_tries + 1; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 1f87b4fb8b5..8082d69ea73 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -275,7 +275,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && + (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); lpfc_unregister_unused_fcf(phba); @@ -2715,11 +2716,35 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); pmb->context1 = NULL; - /* Good status, call state machine */ - lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN); + if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) + ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; + + if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL || + ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { + /* We rcvd a rscn after issuing this + * mbox reg login, we may have cycled + * back through the state and be + * back at reg login state so this + * mbox needs to be ignored becase + * there is another reg login in + * proccess. + */ + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; + spin_unlock_irq(shost->host_lock); + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli4_free_rpi(phba, + pmb->u.mb.un.varRegLogin.rpi); + + } else + /* Good status, call state machine */ + lpfc_disc_state_machine(vport, ndlp, pmb, + NLP_EVT_CMPL_REG_LOGIN); + lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); @@ -3842,6 +3867,9 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) kfree(mp); } list_del(&mb->list); + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_sli4_free_rpi(phba, + mb->u.mb.un.varRegLogin.rpi); mempool_free(mb, phba->mbox_mem_pool); /* We shall not invoke the lpfc_nlp_put to decrement * the ndlp reference count as we are in the process @@ -3883,6 +3911,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(vport, ndlp); if ((ndlp->nlp_flag & NLP_DEFER_RM) && + !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && !(ndlp->nlp_flag & NLP_RPI_VALID)) { /* For this case we need to cleanup the default rpi * allocated by the firmware. diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index b90820a699f..9810b3d3cc5 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -626,7 +626,8 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!(vport->fc_flag & FC_PT2PT)) { /* Check config parameter use-adisc or FCP-2 */ if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || - ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { + ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && + (ndlp->nlp_type & NLP_FCP_TARGET))) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(shost->host_lock); @@ -962,6 +963,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login; break; default: + ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } mbox->context2 = lpfc_nlp_get(ndlp); @@ -972,6 +974,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, NLP_STE_REG_LOGIN_ISSUE); return ndlp->nlp_state; } + if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) + ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; /* decrement node reference count to the failed mbox * command */ @@ -1458,6 +1462,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_IGNR_REG_CMPL; ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(shost->host_lock); lpfc_disc_set_adisc(vport, ndlp); -- cgit v1.2.3-70-g09d2 From 6e7288d9a4b6691bf13fb07e3593d70d725d0737 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:23:35 -0400 Subject: [SCSI] lpfc 8.3.13: Initialization code clean up and fixes. - Add poll or wait flag parameter to hba_init_link and hba_down_link. - (From Linux Community) Make return with ENXIO negative. - Remove unused INB code from driver. - Prevent block_magmt_io from returning until mailbox is inactive. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 8 ++------ drivers/scsi/lpfc/lpfc_attr.c | 4 ++-- drivers/scsi/lpfc/lpfc_hw.h | 8 -------- drivers/scsi/lpfc/lpfc_init.c | 40 +++++++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_mbox.c | 1 - drivers/scsi/lpfc/lpfc_sli.c | 22 ++++------------------ 6 files changed, 43 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e35a4c71eb9..4cb78483bf7 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -510,9 +510,9 @@ struct lpfc_hba { void (*lpfc_stop_port) (struct lpfc_hba *); int (*lpfc_hba_init_link) - (struct lpfc_hba *); + (struct lpfc_hba *, uint32_t); int (*lpfc_hba_down_link) - (struct lpfc_hba *); + (struct lpfc_hba *, uint32_t); /* SLI4 specific HBA data structure */ struct lpfc_sli4_hba sli4_hba; @@ -525,7 +525,6 @@ struct lpfc_hba { #define LPFC_SLI3_NPIV_ENABLED 0x02 #define LPFC_SLI3_VPORT_TEARDOWN 0x04 #define LPFC_SLI3_CRP_ENABLED 0x08 -#define LPFC_SLI3_INB_ENABLED 0x10 #define LPFC_SLI3_BG_ENABLED 0x20 #define LPFC_SLI3_DSS_ENABLED 0x40 uint32_t iocb_cmd_size; @@ -557,9 +556,6 @@ struct lpfc_hba { MAILBOX_t *mbox; uint32_t *mbox_ext; - uint32_t *inb_ha_copy; - uint32_t *inb_counter; - uint32_t inb_last_counter; uint32_t ha_copy; struct _PCB *pcb; struct _IOCB *IOCBs; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index bf33b315f93..b17fe5149e3 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -506,10 +506,10 @@ lpfc_link_state_store(struct device *dev, struct device_attribute *attr, if ((strncmp(buf, "up", sizeof("up") - 1) == 0) && (phba->link_state == LPFC_LINK_DOWN)) - status = phba->lpfc_hba_init_link(phba); + status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) && (phba->link_state >= LPFC_LINK_UP)) - status = phba->lpfc_hba_down_link(phba); + status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT); if (status == 0) return strlen(buf); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index e654d01dad2..bc813fd99d5 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3014,18 +3014,10 @@ struct sli3_pgp { uint32_t hbq_get[16]; }; -struct sli3_inb_pgp { - uint32_t ha_copy; - uint32_t counter; - struct lpfc_pgp port[MAX_RINGS]; - uint32_t hbq_get[16]; -}; - union sli_var { struct sli2_desc s2; struct sli3_desc s3; struct sli3_pgp s3_pgp; - struct sli3_inb_pgp s3_inb_pgp; }; typedef struct { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index cd9697edf86..8da8fc69227 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -621,6 +621,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) /** * lpfc_hba_init_link - Initialize the FC link * @phba: pointer to lpfc hba data structure. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -632,7 +633,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) * Any other value - error **/ int -lpfc_hba_init_link(struct lpfc_hba *phba) +lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) { struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *pmb; @@ -651,7 +652,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba) phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + rc = lpfc_sli_issue_mbox(phba, pmb, flag); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0498 Adapter failed to init, mbxCmd x%x " @@ -664,17 +665,21 @@ lpfc_hba_init_link(struct lpfc_hba *phba) writel(0xffffffff, phba->HAregaddr); readl(phba->HAregaddr); /* flush */ phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY) + if (rc != MBX_BUSY || flag == MBX_POLL) mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK; + if (flag == MBX_POLL) + mempool_free(pmb, phba->mbox_mem_pool); return 0; } /** * lpfc_hba_down_link - this routine downs the FC link + * @phba: pointer to lpfc hba data structure. + * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the DOWN_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data @@ -685,7 +690,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba) * Any other value - error **/ int -lpfc_hba_down_link(struct lpfc_hba *phba) +lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) { LPFC_MBOXQ_t *pmb; int rc; @@ -701,7 +706,7 @@ lpfc_hba_down_link(struct lpfc_hba *phba) "0491 Adapter Link is disabled.\n"); lpfc_down_link(phba, pmb); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + rc = lpfc_sli_issue_mbox(phba, pmb, flag); if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -711,6 +716,9 @@ lpfc_hba_down_link(struct lpfc_hba *phba) mempool_free(pmb, phba->mbox_mem_pool); return -EIO; } + if (flag == MBX_POLL) + mempool_free(pmb, phba->mbox_mem_pool); + return 0; } @@ -2279,10 +2287,32 @@ static void lpfc_block_mgmt_io(struct lpfc_hba * phba) { unsigned long iflag; + uint8_t actcmd = MBX_HEARTBEAT; + unsigned long timeout; + spin_lock_irqsave(&phba->hbalock, iflag); phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO; + if (phba->sli.mbox_active) + actcmd = phba->sli.mbox_active->u.mb.mbxCommand; spin_unlock_irqrestore(&phba->hbalock, iflag); + /* Determine how long we might wait for the active mailbox + * command to be gracefully completed by firmware. + */ + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) + + jiffies; + /* Wait for the outstnading mailbox command to complete */ + while (phba->sli.mbox_active) { + /* Check active mailbox complete status every 2ms */ + msleep(2); + if (time_after(jiffies, timeout)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2813 Mgmt IO is Blocked %x " + "- mbox cmd %x still active\n", + phba->sli.sli_flag, actcmd); + break; + } + } } /** diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index e84dc33ca20..196371fae24 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1199,7 +1199,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mb->un.varCfgPort.cdss = 1; /* Configure Security */ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ - mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */ mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); if (phba->max_vpi && phba->cfg_enable_npiv && phba->vpd.sli3Feat.cmv) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 7a61455140b..87ae175a083 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3794,7 +3794,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) phba->link_state = LPFC_HBA_ERROR; mempool_free(pmb, phba->mbox_mem_pool); - return ENXIO; + return -ENXIO; } } phba->hbq_count = hbq_count; @@ -3885,7 +3885,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED | LPFC_SLI3_CRP_ENABLED | - LPFC_SLI3_INB_ENABLED | LPFC_SLI3_BG_ENABLED); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -3927,20 +3926,9 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; if (pmb->u.mb.un.varCfgPort.gcrp) phba->sli3_options |= LPFC_SLI3_CRP_ENABLED; - if (pmb->u.mb.un.varCfgPort.ginb) { - phba->sli3_options |= LPFC_SLI3_INB_ENABLED; - phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get; - phba->port_gp = phba->mbox->us.s3_inb_pgp.port; - phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy; - phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter; - phba->inb_last_counter = - phba->mbox->us.s3_inb_pgp.counter; - } else { - phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; - phba->port_gp = phba->mbox->us.s3_pgp.port; - phba->inb_ha_copy = NULL; - phba->inb_counter = NULL; - } + + phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; + phba->port_gp = phba->mbox->us.s3_pgp.port; if (phba->cfg_enable_bg) { if (pmb->u.mb.un.varCfgPort.gbg) @@ -3953,8 +3941,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) } else { phba->hbq_get = NULL; phba->port_gp = phba->mbox->us.s2.port; - phba->inb_ha_copy = NULL; - phba->inb_counter = NULL; phba->max_vpi = 0; } do_prep_failed: -- cgit v1.2.3-70-g09d2 From b92938b41ee84b83347b62baa6daa0d06a742e94 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:24:12 -0400 Subject: [SCSI] lpfc 8.3.13: SCSI specific changes - Fix hba_queue_depth to reflect actual available XRIs - Add support for new SLER specific firmware status codes. - Free SCSI buffer when iotag allocation fails. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hw.h | 8 ++++++++ drivers/scsi/lpfc/lpfc_init.c | 7 +++++-- drivers/scsi/lpfc/lpfc_scsi.c | 5 ++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index bc813fd99d5..8887fd831a2 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3124,6 +3124,14 @@ typedef struct { #define IOERR_BUFFER_SHORTAGE 0x28 #define IOERR_DEFAULT 0x29 #define IOERR_CNT 0x2A +#define IOERR_SLER_FAILURE 0x46 +#define IOERR_SLER_CMD_RCV_FAILURE 0x47 +#define IOERR_SLER_REC_RJT_ERR 0x48 +#define IOERR_SLER_REC_SRR_RETRY_ERR 0x49 +#define IOERR_SLER_SRR_RJT_ERR 0x4A +#define IOERR_SLER_RRQ_RJT_ERR 0x4C +#define IOERR_SLER_RRQ_RETRY_ERR 0x4D +#define IOERR_SLER_ABTS_ERR 0x4E #define IOERR_DRVR_MASK 0x100 #define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 8da8fc69227..62585870f08 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5563,9 +5563,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) mempool_free(pmb, phba->mbox_mem_pool); /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri)) + if (phba->cfg_hba_queue_depth > + (phba->sli4_hba.max_cfg_param.max_xri - + lpfc_sli4_get_els_iocb_cnt(phba))) phba->cfg_hba_queue_depth = - phba->sli4_hba.max_cfg_param.max_xri; + phba->sli4_hba.max_cfg_param.max_xri - + lpfc_sli4_get_els_iocb_cnt(phba); return rc; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f4a3b2e79ee..f7a92653467 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -774,6 +774,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) /* Allocate iotag for psb->cur_iocbq. */ iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); if (iotag == 0) { + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, + psb->data, psb->dma_handle); kfree(psb); break; } @@ -2363,7 +2365,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, case IOSTAT_LOCAL_REJECT: if (lpfc_cmd->result == IOERR_INVALID_RPI || lpfc_cmd->result == IOERR_NO_RESOURCES || - lpfc_cmd->result == IOERR_ABORT_REQUESTED) { + lpfc_cmd->result == IOERR_ABORT_REQUESTED || + lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { cmd->result = ScsiResult(DID_REQUEUE, 0); break; } -- cgit v1.2.3-70-g09d2 From 98fc5dd952ecfd3abff7c06e7a55a5eab4dd95b7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:24:29 -0400 Subject: [SCSI] lpfc 8.3.13: Misc fixes - Change the Max receive size on CIN FCFs to 0x800 - (From linux community) Check boundary before checking for NULL. - Update last completion time for completed I/O to prevent heartbeat. - Add Balius PCI Device IDs Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hw.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 6 ++++++ drivers/scsi/lpfc/lpfc_sli.c | 4 ++++ drivers/scsi/lpfc/lpfc_sli4.h | 2 +- drivers/scsi/lpfc/lpfc_vport.c | 2 +- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 8887fd831a2..f5dbf2be3ea 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1170,6 +1170,7 @@ typedef struct { #define PCI_DEVICE_ID_TIGERSHARK 0x0704 #define PCI_DEVICE_ID_TOMCAT 0x0714 #define PCI_DEVICE_ID_FALCON 0xf180 +#define PCI_DEVICE_ID_BALIUS 0xe131 #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 62585870f08..7dc55989b8f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1826,6 +1826,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", "EmulexSecure Fibre"}; break; + case PCI_DEVICE_ID_BALIUS: + m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", + "Fibre Channel Adapter"}; + break; default: m = (typeof(m)){"Unknown", "", ""}; break; @@ -8835,6 +8839,8 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 87ae175a083..103a5aa4ae8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9194,6 +9194,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, { struct lpfc_wcqe_release wcqe; bool workposted = false; + unsigned long iflag; /* Copy the work queue CQE and convert endian order if needed */ lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); @@ -9202,6 +9203,9 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { case CQE_CODE_COMPL_WQE: /* Process the WQ complete event */ + spin_lock_irqsave(&phba->hbalock, iflag); + phba->last_completion_time = jiffies; + spin_unlock_irqrestore(&phba->hbalock, iflag); lpfc_sli4_fp_handle_fcp_wcqe(phba, (struct lpfc_wcqe_complete *)&wcqe); break; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 58bb4c81b54..1f8ec72c5dc 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -58,7 +58,7 @@ #define LPFC_FCOE_FCF_MAP0 0x0E #define LPFC_FCOE_FCF_MAP1 0xFC #define LPFC_FCOE_FCF_MAP2 0x00 -#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC +#define LPFC_FCOE_MAX_RCV_SIZE 0x800 #define LPFC_FCOE_FKA_ADV_PER 0 #define LPFC_FCOE_FIP_PRIORITY 0x80 diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index ab91359bde2..1655507a682 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -782,7 +782,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) int i; if (vports == NULL) return; - for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) scsi_host_put(lpfc_shost_from_vport(vports[i])); kfree(vports); } -- cgit v1.2.3-70-g09d2 From 2a9bf3d011303d8da64cd5e0e7fdd95f0c143984 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:24:45 -0400 Subject: [SCSI] lpfc 8.3.13: Add TX Queue Support for SLI4 ELS commands. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 5 +- drivers/scsi/lpfc/lpfc_attr.c | 58 +++++++++++ drivers/scsi/lpfc/lpfc_bsg.c | 9 ++ drivers/scsi/lpfc/lpfc_crtn.h | 9 ++ drivers/scsi/lpfc/lpfc_els.c | 36 +++++-- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 + drivers/scsi/lpfc/lpfc_init.c | 8 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 24 ++++- drivers/scsi/lpfc/lpfc_scsi.c | 4 +- drivers/scsi/lpfc/lpfc_sli.c | 194 ++++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_sli.h | 2 + 11 files changed, 310 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 4cb78483bf7..fcfc495d1e0 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -20,7 +20,6 @@ *******************************************************************/ #include - struct lpfc_sli2_slim; #define LPFC_PCI_DEV_LP 0x1 @@ -376,6 +375,7 @@ struct lpfc_vport { #define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */ #define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */ #define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */ +#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */ struct timer_list fc_fdmitmo; struct timer_list els_tmofunc; @@ -624,6 +624,7 @@ struct lpfc_hba { uint32_t cfg_hostmem_hgp; uint32_t cfg_log_verbose; uint32_t cfg_aer_support; + uint32_t cfg_iocb_cnt; uint32_t cfg_suppress_link_up; #define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ #define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ @@ -812,6 +813,8 @@ struct lpfc_hba { uint8_t menlo_flag; /* menlo generic flags */ #define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */ + uint32_t iocb_cnt; + uint32_t iocb_max; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b17fe5149e3..39b0760c438 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1949,6 +1949,59 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK, LPFC_DELAY_INIT_LINK_INDEFINITELY, "Suppress Link Up at initialization"); +/* +# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS +# 1 - (1024) +# 2 - (2048) +# 3 - (3072) +# 4 - (4096) +# 5 - (5120) +*/ +static ssize_t +lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max); +} + +static DEVICE_ATTR(iocb_hw, S_IRUGO, + lpfc_iocb_hw_show, NULL); +static ssize_t +lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", + phba->sli.ring[LPFC_ELS_RING].txq_max); +} + +static DEVICE_ATTR(txq_hw, S_IRUGO, + lpfc_txq_hw_show, NULL); +static ssize_t +lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; + + return snprintf(buf, PAGE_SIZE, "%d\n", + phba->sli.ring[LPFC_ELS_RING].txcmplq_max); +} + +static DEVICE_ATTR(txcmplq_hw, S_IRUGO, + lpfc_txcmplq_hw_show, NULL); + +int lpfc_iocb_cnt = 2; +module_param(lpfc_iocb_cnt, int, 1); +MODULE_PARM_DESC(lpfc_iocb_cnt, + "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs"); +lpfc_param_show(iocb_cnt); +lpfc_param_init(iocb_cnt, 2, 1, 5); +static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO, + lpfc_iocb_cnt_show, NULL); /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear @@ -3334,6 +3387,10 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_aer_support, &dev_attr_lpfc_aer_state_cleanup, &dev_attr_lpfc_suppress_link_up, + &dev_attr_lpfc_iocb_cnt, + &dev_attr_iocb_hw, + &dev_attr_txq_hw, + &dev_attr_txcmplq_hw, NULL, }; @@ -4521,6 +4578,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_aer_support_init(phba, lpfc_aer_support); lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); + lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); return; } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index dcf088262b2..55f984166db 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -377,6 +377,11 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) if (rc == IOCB_SUCCESS) return 0; /* done for now */ + else if (rc == IOCB_BUSY) + rc = EAGAIN; + else + rc = EIO; + /* iocb failed so cleanup */ pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, @@ -625,6 +630,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) lpfc_nlp_put(ndlp); if (rc == IOCB_SUCCESS) return 0; /* done for now */ + else if (rc == IOCB_BUSY) + rc = EAGAIN; + else + rc = EIO; pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 6b404e510a3..361f4e7e23e 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -403,3 +403,12 @@ int lpfc_bsg_request(struct fc_bsg_job *); int lpfc_bsg_timeout(struct fc_bsg_job *); int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); +void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_iocbq *); +struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *, + struct lpfc_sli_ring *); +int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, + struct lpfc_iocbq *, uint32_t); +uint32_t lpfc_drain_txq(struct lpfc_hba *); + + diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 6b1850c9fdf..f936f8c7efe 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1472,8 +1472,12 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } goto out; } - /* PLOGI failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + /* PLOGI failed Don't print the vport to vport rjts */ + if (irsp->ulpStatus != IOSTAT_LS_RJT || + (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && + ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || + (phba)->pport->cfg_log_verbose & LOG_ELS) + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "2753 PLOGI failure DID:%06X Status:x%x/x%x\n", ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4]); @@ -5144,6 +5148,7 @@ lpfc_els_timeout(unsigned long ptr) return; } + /** * lpfc_els_timeout_handler - Process an els timeout event * @vport: pointer to a virtual N_Port data structure. @@ -5164,13 +5169,19 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) uint32_t els_command = 0; uint32_t timeout; uint32_t remote_ID = 0xffffffff; + LIST_HEAD(txcmplq_completions); + LIST_HEAD(abort_list); + - spin_lock_irq(&phba->hbalock); timeout = (uint32_t)(phba->fc_ratov << 1); pring = &phba->sli.ring[LPFC_ELS_RING]; - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { + spin_lock_irq(&phba->hbalock); + list_splice_init(&pring->txcmplq, &txcmplq_completions); + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) { cmd = &piocb->iocb; if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || @@ -5207,13 +5218,22 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) if (ndlp && NLP_CHK_NODE_ACT(ndlp)) remote_ID = ndlp->nlp_DID; } + list_add_tail(&piocb->dlist, &abort_list); + } + spin_lock_irq(&phba->hbalock); + list_splice(&txcmplq_completions, &pring->txcmplq); + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0127 ELS timeout Data: x%x x%x x%x " - "x%x\n", els_command, - remote_ID, cmd->ulpCommand, cmd->ulpIoTag); + "0127 ELS timeout Data: x%x x%x x%x " + "x%x\n", els_command, + remote_ID, cmd->ulpCommand, cmd->ulpIoTag); + spin_lock_irq(&phba->hbalock); + list_del_init(&piocb->dlist); lpfc_sli_issue_abort_iotag(phba, pring, piocb); + spin_unlock_irq(&phba->hbalock); } - spin_unlock_irq(&phba->hbalock); if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 8082d69ea73..d1c5c52b1c2 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -587,6 +587,8 @@ lpfc_work_done(struct lpfc_hba *phba) (status & HA_RXMASK)); } + if (phba->pport->work_port_events & WORKER_SERVICE_TXQ) + lpfc_drain_txq(phba); /* * Turn on Ring interrupts */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7dc55989b8f..184e45f286d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8147,8 +8147,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) } /* Initialize and populate the iocb list per host */ - error = lpfc_init_iocb_list(phba, - phba->sli4_hba.max_cfg_param.max_xri); + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2821 initialize iocb list %d.\n", + phba->cfg_iocb_cnt*1024); + error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024); + if (error) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1413 Failed to initialize iocb list.\n"); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 9810b3d3cc5..bccc9c66fa3 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -190,6 +190,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } + /* * Free resources / clean up outstanding I/Os * associated with a LPFC_NODELIST entry. This @@ -199,13 +200,15 @@ int lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); + LIST_HEAD(txcmplq_completions); + LIST_HEAD(abort_list); struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; struct lpfc_iocbq *iocb, *next_iocb; /* Abort outstanding I/O on NPort */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY, - "0205 Abort outstanding I/O on NPort x%x " + "2819 Abort outstanding I/O on NPort x%x " "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -224,14 +227,25 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } /* Next check the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { + list_splice_init(&pring->txcmplq, &txcmplq_completions); + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) { /* Check to see if iocb matches the nport we are looking for */ - if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } + if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) + list_add_tail(&iocb->dlist, &abort_list); } + spin_lock_irq(&phba->hbalock); + list_splice(&txcmplq_completions, &pring->txcmplq); spin_unlock_irq(&phba->hbalock); + list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { + spin_lock_irq(&phba->hbalock); + list_del_init(&iocb->dlist); + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + spin_unlock_irq(&phba->hbalock); + } + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f7a92653467..c6bdf63925d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3228,7 +3228,9 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, iocbqrsp->iocb.un.ulpWord[4]); - } else + } else if (status == IOCB_BUSY) + ret = FAILED; + else ret = SUCCESS; lpfc_sli_release_iocbq(phba, iocbqrsp); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 103a5aa4ae8..ae3cb0ab0ae 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -455,6 +455,11 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba) struct lpfc_iocbq * iocbq = NULL; list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list); + + if (iocbq) + phba->iocb_cnt++; + if (phba->iocb_cnt > phba->iocb_max) + phba->iocb_max = phba->iocb_cnt; return iocbq; } @@ -575,7 +580,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { struct lpfc_sglq *sglq; size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - unsigned long iflag; + unsigned long iflag = 0; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; if (iocbq->sli4_xritag == NO_XRI) sglq = NULL; @@ -593,6 +599,17 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) } else { sglq->state = SGL_FREED; list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list); + + /* Check if TXQ queue needs to be serviced */ + if (pring->txq_cnt) { + spin_lock_irqsave( + &phba->pport->work_port_lock, iflag); + phba->pport->work_port_events |= + WORKER_SERVICE_TXQ; + lpfc_worker_wake_up(phba); + spin_unlock_irqrestore( + &phba->pport->work_port_lock, iflag); + } } } @@ -605,6 +622,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); } + /** * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool * @phba: Pointer to HBA context object. @@ -642,6 +660,7 @@ static void __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { phba->__lpfc_sli_release_iocbq(phba, iocbq); + phba->iocb_cnt--; } /** @@ -872,7 +891,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { list_add_tail(&piocb->list, &pring->txcmplq); + piocb->iocb_flag |= LPFC_IO_ON_Q; pring->txcmplq_cnt++; + if (pring->txcmplq_cnt > pring->txcmplq_max) + pring->txcmplq_max = pring->txcmplq_cnt; + if ((unlikely(pring->ringno == LPFC_ELS_RING)) && (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { @@ -897,7 +920,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * the txq, the function returns first iocb in the list after * removing the iocb from the list, else it returns NULL. **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { struct lpfc_iocbq *cmd_iocb; @@ -2150,7 +2173,10 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; list_del_init(&cmd_iocb->list); - pring->txcmplq_cnt--; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { + pring->txcmplq_cnt--; + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + } return cmd_iocb; } @@ -2183,7 +2209,10 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; list_del_init(&cmd_iocb->list); - pring->txcmplq_cnt--; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + pring->txcmplq_cnt--; + } return cmd_iocb; } @@ -5578,7 +5607,7 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) * iocb to the txq when SLI layer cannot submit the command iocb * to the ring. **/ -static void +void __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { @@ -6195,7 +6224,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { struct lpfc_sglq *sglq; - uint16_t xritag; union lpfc_wqe wqe; struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; @@ -6204,10 +6232,26 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) sglq = NULL; else { + if (pring->txq_cnt) { + if (!(flag & SLI_IOCB_RET_IOCB)) { + __lpfc_sli_ringtx_put(phba, + pring, piocb); + return IOCB_SUCCESS; + } else { + return IOCB_BUSY; + } + } else { sglq = __lpfc_sli_get_sglq(phba); - if (!sglq) - return IOCB_ERROR; - piocb->sli4_xritag = sglq->sli4_xritag; + if (!sglq) { + if (!(flag & SLI_IOCB_RET_IOCB)) { + __lpfc_sli_ringtx_put(phba, + pring, + piocb); + return IOCB_SUCCESS; + } else + return IOCB_BUSY; + } + } } } else if (piocb->iocb_flag & LPFC_IO_FCP) { sglq = NULL; /* These IO's already have an XRI and @@ -6223,8 +6267,9 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, } if (sglq) { - xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq); - if (xritag != sglq->sli4_xritag) + piocb->sli4_xritag = sglq->sli4_xritag; + + if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq)) return IOCB_ERROR; } @@ -6264,7 +6309,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, * IOCB_SUCCESS - Success * IOCB_BUSY - Busy **/ -static inline int +int __lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { @@ -7081,13 +7126,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ abort_iocb = phba->sli.iocbq_lookup[abort_context]; - lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI, - "0327 Cannot abort els iocb %p " - "with tag %x context %x, abort status %x, " - "abort code %x\n", - abort_iocb, abort_iotag, abort_context, - irsp->ulpStatus, irsp->un.ulpWord[4]); - /* * If the iocb is not found in Firmware queue the iocb * might have completed already. Do not free it again. @@ -7106,6 +7144,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4) abort_context = abort_iocb->iocb.ulpContext; } + + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, + "0327 Cannot abort els iocb %p " + "with tag %x context %x, abort status %x, " + "abort code %x\n", + abort_iocb, abort_iotag, abort_context, + irsp->ulpStatus, irsp->un.ulpWord[4]); /* * make sure we have the right iocbq before taking it * off the txcmplq and try to call completion routine. @@ -7123,7 +7168,10 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * following abort XRI from the HBA. */ list_del_init(&abort_iocb->list); - pring->txcmplq_cnt--; + if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) { + abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + pring->txcmplq_cnt--; + } /* Firmware could still be in progress of DMAing * payload, so don't free data buffer till after @@ -7255,8 +7303,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0339 Abort xri x%x, original iotag x%x, " "abort cmd iotag x%x\n", + iabt->un.acxri.abortIoTag, iabt->un.acxri.abortContextTag, - iabt->un.acxri.abortIoTag, abtsiocbp->iotag); + abtsiocbp->iotag); retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0); if (retval) @@ -7586,7 +7635,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, long timeleft, timeout_req = 0; int retval = IOCB_SUCCESS; uint32_t creg_val; - + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; /* * If the caller has provided a response iocbq buffer, then context2 * is NULL or its an error. @@ -7608,7 +7657,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, readl(phba->HCregaddr); /* flush */ } - retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0); + retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, + SLI_IOCB_RET_IOCB); if (retval == IOCB_SUCCESS) { timeout_req = timeout * HZ; timeleft = wait_event_timeout(done_q, @@ -7630,6 +7680,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, timeout, (timeleft / jiffies)); retval = IOCB_TIMEDOUT; } + } else if (retval == IOCB_BUSY) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n", + phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt); + return retval; } else { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "0332 IOCB wait issue failed, Data x%x\n", @@ -8775,12 +8830,17 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, { struct lpfc_iocbq *irspiocbq; unsigned long iflags; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; /* Get an irspiocbq for later ELS response processing use */ irspiocbq = lpfc_sli_get_iocbq(phba); if (!irspiocbq) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0387 Failed to allocate an iocbq\n"); + "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " + "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n", + pring->txq_cnt, phba->iocb_cnt, + phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt, + phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt); return false; } @@ -12695,3 +12755,89 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) spin_unlock_irq(&phba->hbalock); } +/** + * lpfc_drain_txq - Drain the txq + * @phba: Pointer to HBA context object. + * + * This function attempt to submit IOCBs on the txq + * to the adapter. For SLI4 adapters, the txq contains + * ELS IOCBs that have been deferred because the there + * are no SGLs. This congestion can occur with large + * vport counts during node discovery. + **/ + +uint32_t +lpfc_drain_txq(struct lpfc_hba *phba) +{ + LIST_HEAD(completions); + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct lpfc_iocbq *piocbq = 0; + unsigned long iflags = 0; + char *fail_msg = NULL; + struct lpfc_sglq *sglq; + union lpfc_wqe wqe; + + spin_lock_irqsave(&phba->hbalock, iflags); + if (pring->txq_cnt > pring->txq_max) + pring->txq_max = pring->txq_cnt; + + spin_unlock_irqrestore(&phba->hbalock, iflags); + + while (pring->txq_cnt) { + spin_lock_irqsave(&phba->hbalock, iflags); + + sglq = __lpfc_sli_get_sglq(phba); + if (!sglq) { + spin_unlock_irqrestore(&phba->hbalock, iflags); + break; + } else { + piocbq = lpfc_sli_ringtx_get(phba, pring); + if (!piocbq) { + /* The txq_cnt out of sync. This should + * never happen + */ + sglq = __lpfc_clear_active_sglq(phba, + sglq->sli4_xritag); + spin_unlock_irqrestore(&phba->hbalock, iflags); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2823 txq empty and txq_cnt is %d\n ", + pring->txq_cnt); + break; + } + } + + /* The xri and iocb resources secured, + * attempt to issue request + */ + piocbq->sli4_xritag = sglq->sli4_xritag; + if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) + fail_msg = "to convert bpl to sgl"; + else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) + fail_msg = "to convert iocb to wqe"; + else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) + fail_msg = " - Wq is full"; + else + lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); + + if (fail_msg) { + /* Failed means we can't issue and need to cancel */ + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2822 IOCB failed %s iotag 0x%x " + "xri 0x%x\n", + fail_msg, + piocbq->iotag, piocbq->sli4_xritag); + list_add_tail(&piocbq->list, &completions); + } + spin_unlock_irqrestore(&phba->hbalock, iflags); + } + + spin_lock_irqsave(&phba->pport->work_port_lock, iflags); + phba->pport->work_port_events &= ~WORKER_SERVICE_TXQ; + spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); + + /* Cancel all the IOCBs that cannot be issued */ + lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, + IOERR_SLI_ABORTED); + + return pring->txq_cnt; +} diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index e3792151ca0..cd56d6cce6c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -48,6 +48,7 @@ struct lpfc_iocbq { /* lpfc_iocbqs are used in double linked lists */ struct list_head list; struct list_head clist; + struct list_head dlist; uint16_t iotag; /* pre-assigned IO tag */ uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ struct lpfc_cq_event cq_event; @@ -64,6 +65,7 @@ struct lpfc_iocbq { #define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ #define DSS_SECURITY_OP 0x100 /* security IO */ +#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ #define LPFC_FIP_ELS_ID_SHIFT 14 -- cgit v1.2.3-70-g09d2 From 18cacc34887df274feb3f1ff420d7592e4ea246f Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 7 Jun 2010 15:24:54 -0400 Subject: [SCSI] lpfc 8.3.13: Update Driver Version to 8.3.13 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 5294c3a515a..e79090df228 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.12" +#define LPFC_DRIVER_VERSION "8.3.13" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v1.2.3-70-g09d2 From c20c426732a5a5d21e99b36286f79c2024115341 Mon Sep 17 00:00:00 2001 From: Anil Ravindranath Date: Tue, 8 Jun 2010 10:56:34 -0700 Subject: [SCSI] pmcraid: MSI-X support and other changes 1. MSI-X interrupt support 2. Driver changes to support new maxRAID controller FW version. The changes are mainly done to handle async notification changes done in newer controller FW version. 3. Added state change notifications to notify applications of controller states. Signed-off-by: Anil Ravindranath Signed-off-by: James Bottomley --- drivers/scsi/pmcraid.c | 886 ++++++++++++++++++++++++++++++++++++------------- drivers/scsi/pmcraid.h | 305 ++++++++++------- 2 files changed, 843 insertions(+), 348 deletions(-) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index c44e4ab4e93..9ebcea3643b 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -113,6 +113,7 @@ static struct pmcraid_chip_details pmcraid_chip_cfg[] = { .global_intr_mask = 0x00034, .ioa_host_intr = 0x0009C, .ioa_host_intr_clr = 0x000A0, + .ioa_host_msix_intr = 0x7FC40, .ioa_host_mask = 0x7FC28, .ioa_host_mask_clr = 0x7FC28, .host_ioa_intr = 0x00020, @@ -154,8 +155,12 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) u8 target, bus, lun; unsigned long lock_flags; int rc = -ENXIO; + u16 fw_version; + pinstance = shost_priv(scsi_dev->host); + fw_version = be16_to_cpu(pinstance->inq_data->fw_version); + /* Driver exposes VSET and GSCSI resources only; all other device types * are not exposed. Resource list is synchronized using resource lock * so any traversal or modifications to the list should be done inside @@ -166,7 +171,11 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */ if (RES_IS_VSET(temp->cfg_entry)) { - target = temp->cfg_entry.unique_flags1; + if (fw_version <= PMCRAID_FW_VERSION_1) + target = temp->cfg_entry.unique_flags1; + else + target = temp->cfg_entry.array_id & 0xFF; + if (target > PMCRAID_MAX_VSET_TARGETS) continue; bus = PMCRAID_VSET_BUS_ID; @@ -283,7 +292,7 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) * @reason: calling context * * Return value - * actual depth set + * actual depth set */ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, int reason) @@ -305,7 +314,7 @@ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, * @tag: type of tags to use * * Return value: - * actual queue type set + * actual queue type set */ static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag) { @@ -357,6 +366,7 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) * processed by IOA */ memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); + ioarcb->hrrq_id = 0; ioarcb->request_flags0 = 0; ioarcb->request_flags1 = 0; ioarcb->cmd_timeout = 0; @@ -368,13 +378,15 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) ioarcb->add_cmd_param_offset = 0; cmd->ioa_cb->ioasa.ioasc = 0; cmd->ioa_cb->ioasa.residual_data_length = 0; - cmd->u.time_left = 0; + cmd->time_left = 0; } cmd->cmd_done = NULL; cmd->scsi_cmd = NULL; cmd->release = 0; cmd->completion_req = 0; + cmd->sense_buffer = 0; + cmd->sense_buffer_dma = 0; cmd->dma_handle = 0; init_timer(&cmd->timer); } @@ -449,7 +461,9 @@ void pmcraid_return_cmd(struct pmcraid_cmd *cmd) */ static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) { - return ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + return (pinstance->interrupt_mode) ? + ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) : + ioread32(pinstance->int_regs.ioa_host_interrupt_reg); } /** @@ -469,10 +483,15 @@ static void pmcraid_disable_interrupts( u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; - iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); - iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); + ioread32(pinstance->int_regs.global_interrupt_mask_reg); + + if (!pinstance->interrupt_mode) { + iowrite32(intrs, + pinstance->int_regs.ioa_host_interrupt_mask_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + } } /** @@ -493,14 +512,51 @@ static void pmcraid_enable_interrupts( u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); - iowrite32(~intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + + if (!pinstance->interrupt_mode) { + iowrite32(~intrs, + pinstance->int_regs.ioa_host_interrupt_mask_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + } pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", ioread32(pinstance->int_regs.global_interrupt_mask_reg), ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); } +/** + * pmcraid_clr_trans_op - clear trans to op interrupt + * + * @pinstance: pointer to per adapter instance structure + * + * Return Value + * None + */ +static void pmcraid_clr_trans_op( + struct pmcraid_instance *pinstance +) +{ + unsigned long lock_flags; + + if (!pinstance->interrupt_mode) { + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_mask_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg); + } + + if (pinstance->reset_cmd != NULL) { + del_timer(&pinstance->reset_cmd->timer); + spin_lock_irqsave( + pinstance->host->host_lock, lock_flags); + pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); + spin_unlock_irqrestore( + pinstance->host->host_lock, lock_flags); + } +} + /** * pmcraid_reset_type - Determine the required reset type * @pinstance: pointer to adapter instance structure @@ -536,7 +592,7 @@ static void pmcraid_reset_type(struct pmcraid_instance *pinstance) * pmcraid_bist_done - completion function for PCI BIST * @cmd: pointer to reset command * Return Value - * none + * none */ static void pmcraid_ioa_reset(struct pmcraid_cmd *); @@ -552,16 +608,16 @@ static void pmcraid_bist_done(struct pmcraid_cmd *cmd) /* If PCI config space can't be accessed wait for another two secs */ if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && - cmd->u.time_left > 0) { + cmd->time_left > 0) { pmcraid_info("BIST not complete, waiting another 2 secs\n"); - cmd->timer.expires = jiffies + cmd->u.time_left; - cmd->u.time_left = 0; + cmd->timer.expires = jiffies + cmd->time_left; + cmd->time_left = 0; cmd->timer.data = (unsigned long)cmd; cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; add_timer(&cmd->timer); } else { - cmd->u.time_left = 0; + cmd->time_left = 0; pmcraid_info("BIST is complete, proceeding with reset\n"); spin_lock_irqsave(pinstance->host->host_lock, lock_flags); pmcraid_ioa_reset(cmd); @@ -585,10 +641,10 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd) pinstance->int_regs.host_ioa_interrupt_reg); doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); - pmcraid_info("doorbells after start bist: %x intrs: %x \n", + pmcraid_info("doorbells after start bist: %x intrs: %x\n", doorbells, intrs); - cmd->u.time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); + cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); cmd->timer.data = (unsigned long)cmd; cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; @@ -612,7 +668,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) * some more time to wait, restart the timer */ if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || - cmd->u.time_left <= 0) { + cmd->time_left <= 0) { pmcraid_info("critical op is reset proceeding with reset\n"); spin_lock_irqsave(pinstance->host->host_lock, lock_flags); pmcraid_ioa_reset(cmd); @@ -620,7 +676,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) } else { pmcraid_info("critical op is not yet reset waiting again\n"); /* restart timer if some more time is available to wait */ - cmd->u.time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; + cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; cmd->timer.data = (unsigned long)cmd; cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; cmd->timer.function = @@ -638,6 +694,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) * successfully written to IOA. Returns non-zero in case pci_config_space * is not accessible */ +static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) { struct pmcraid_instance *pinstance = cmd->drv_inst; @@ -658,7 +715,7 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) * OPERATION bit is reset. A timer is started to wait for this * bit to be reset. */ - cmd->u.time_left = PMCRAID_RESET_TIMEOUT; + cmd->time_left = PMCRAID_RESET_TIMEOUT; cmd->timer.data = (unsigned long)cmd; cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; cmd->timer.function = @@ -693,7 +750,8 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) unsigned long lock_flags; dev_info(&pinstance->pdev->dev, - "Adapter being reset due to command timeout.\n"); + "Adapter being reset due to cmd(CDB[0] = %x) timeout\n", + cmd->ioa_cb->ioarcb.cdb[0]); /* Command timeouts result in hard reset sequence. The command that got * timed out may be the one used as part of reset sequence. In this @@ -736,9 +794,14 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) */ if (cmd == pinstance->reset_cmd) cmd->cmd_done = pmcraid_ioa_reset; - } + /* Notify apps of important IOA bringup/bringdown sequences */ + if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START && + pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START) + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_RESET_START); + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; scsi_block_requests(pinstance->host); pmcraid_reset_alert(cmd); @@ -866,7 +929,7 @@ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) /* Add this command block to pending cmd pool. We do this prior to * writting IOARCB to ioarrin because IOA might complete the command * by the time we are about to add it to the list. Response handler - * (isr/tasklet) looks for cmb block in the pending pending list. + * (isr/tasklet) looks for cmd block in the pending pending list. */ spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); @@ -915,6 +978,23 @@ static void pmcraid_send_cmd( _pmcraid_fire_command(cmd); } +/** + * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command + * @cmd: pointer to the command block used for sending IOA shutdown command + * + * Return value + * None + */ +static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + unsigned long lock_flags; + + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + pmcraid_ioa_reset(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); +} + /** * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa * @@ -943,30 +1023,112 @@ static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) pmcraid_info("firing normal shutdown command (%d) to IOA\n", le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); - pmcraid_send_cmd(cmd, pmcraid_ioa_reset, + pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START); + + pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done, PMCRAID_SHUTDOWN_TIMEOUT, pmcraid_timeout_handler); } /** - * pmcraid_identify_hrrq - registers host rrq buffers with IOA - * @cmd: pointer to command block to be used for identify hrrq + * pmcraid_get_fwversion_done - completion function for get_fwversion + * + * @cmd: pointer to command block used to send INQUIRY command * * Return Value - * 0 in case of success, otherwise non-zero failure code + * none */ - static void pmcraid_querycfg(struct pmcraid_cmd *); +static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) +{ + struct pmcraid_instance *pinstance = cmd->drv_inst; + u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); + unsigned long lock_flags; + + /* configuration table entry size depends on firmware version. If fw + * version is not known, it is not possible to interpret IOA config + * table + */ + if (ioasc) { + pmcraid_err("IOA Inquiry failed with %x\n", ioasc); + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); + pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; + pmcraid_reset_alert(cmd); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + } else { + pmcraid_querycfg(cmd); + } +} + +/** + * pmcraid_get_fwversion - reads firmware version information + * + * @cmd: pointer to command block used to send INQUIRY command + * + * Return Value + * none + */ +static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) +{ + struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; + struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; + struct pmcraid_instance *pinstance = cmd->drv_inst; + u16 data_size = sizeof(struct pmcraid_inquiry_data); + + pmcraid_reinit_cmdblk(cmd); + ioarcb->request_type = REQ_TYPE_SCSI; + ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); + ioarcb->cdb[0] = INQUIRY; + ioarcb->cdb[1] = 1; + ioarcb->cdb[2] = 0xD0; + ioarcb->cdb[3] = (data_size >> 8) & 0xFF; + ioarcb->cdb[4] = data_size & 0xFF; + + /* Since entire inquiry data it can be part of IOARCB itself + */ + ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + + offsetof(struct pmcraid_ioarcb, + add_data.u.ioadl[0])); + ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); + ioarcb->ioarcb_bus_addr &= ~(0x1FULL); + + ioarcb->request_flags0 |= NO_LINK_DESCS; + ioarcb->data_transfer_length = cpu_to_le32(data_size); + ioadl = &(ioarcb->add_data.u.ioadl[0]); + ioadl->flags = IOADL_FLAGS_LAST_DESC; + ioadl->address = cpu_to_le64(pinstance->inq_data_baddr); + ioadl->data_len = cpu_to_le32(data_size); + + pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done, + PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); +} + +/** + * pmcraid_identify_hrrq - registers host rrq buffers with IOA + * @cmd: pointer to command block to be used for identify hrrq + * + * Return Value + * none + */ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) { struct pmcraid_instance *pinstance = cmd->drv_inst; struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - int index = 0; + int index = cmd->hrrq_index; __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); + void (*done_function)(struct pmcraid_cmd *); pmcraid_reinit_cmdblk(cmd); + cmd->hrrq_index = index + 1; + + if (cmd->hrrq_index < pinstance->num_hrrq) { + done_function = pmcraid_identify_hrrq; + } else { + cmd->hrrq_index = 0; + done_function = pmcraid_get_fwversion; + } /* Initialize ioarcb */ ioarcb->request_type = REQ_TYPE_IOACMD; @@ -980,8 +1142,8 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) /* IOA expects 64-bit pci address to be written in B.E format * (i.e cdb[2]=MSByte..cdb[9]=LSB. */ - pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb => %llx:%llx\n", - hrrq_addr, ioarcb->ioarcb_bus_addr); + pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n", + hrrq_addr, ioarcb->ioarcb_bus_addr, index); memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); @@ -990,7 +1152,7 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) * Note that this gets called even during reset from SCSI mid-layer * or tasklet */ - pmcraid_send_cmd(cmd, pmcraid_querycfg, + pmcraid_send_cmd(cmd, done_function, PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); } @@ -1047,7 +1209,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam } if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { - rcb_size = sizeof(struct pmcraid_hcam_ccn); + rcb_size = sizeof(struct pmcraid_hcam_ccn_ext); cmd_done = pmcraid_process_ccn; dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; hcam = &pinstance->ccn; @@ -1094,7 +1256,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam * This function will send a Host Controlled Async command to IOA. * * Return value: - * none + * none */ static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) { @@ -1202,18 +1364,25 @@ static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) /** * pmcraid_expose_resource - check if the resource can be exposed to OS * + * @fw_version: firmware version code * @cfgte: pointer to configuration table entry of the resource * * Return value: - * true if resource can be added to midlayer, false(0) otherwise + * true if resource can be added to midlayer, false(0) otherwise */ -static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte) +static int pmcraid_expose_resource(u16 fw_version, + struct pmcraid_config_table_entry *cfgte) { int retval = 0; - if (cfgte->resource_type == RES_TYPE_VSET) - retval = ((cfgte->unique_flags1 & 0x80) == 0); - else if (cfgte->resource_type == RES_TYPE_GSCSI) + if (cfgte->resource_type == RES_TYPE_VSET) { + if (fw_version <= PMCRAID_FW_VERSION_1) + retval = ((cfgte->unique_flags1 & 0x80) == 0); + else + retval = ((cfgte->unique_flags0 & 0x80) == 0 && + (cfgte->unique_flags1 & 0x80) == 0); + + } else if (cfgte->resource_type == RES_TYPE_GSCSI) retval = (RES_BUS(cfgte->resource_address) != PMCRAID_VIRTUAL_ENCL_BUS_ID); return retval; @@ -1246,8 +1415,8 @@ static struct genl_family pmcraid_event_family = { * pmcraid_netlink_init - registers pmcraid_event_family * * Return value: - * 0 if the pmcraid_event_family is successfully registered - * with netlink generic, non-zero otherwise + * 0 if the pmcraid_event_family is successfully registered + * with netlink generic, non-zero otherwise */ static int pmcraid_netlink_init(void) { @@ -1268,7 +1437,7 @@ static int pmcraid_netlink_init(void) * pmcraid_netlink_release - unregisters pmcraid_event_family * * Return value: - * none + * none */ static void pmcraid_netlink_release(void) { @@ -1283,31 +1452,30 @@ static void pmcraid_netlink_release(void) * Return value: * 0 if success, error value in case of any failure. */ -static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type) +static int pmcraid_notify_aen( + struct pmcraid_instance *pinstance, + struct pmcraid_aen_msg *aen_msg, + u32 data_size +) { struct sk_buff *skb; - struct pmcraid_aen_msg *aen_msg; void *msg_header; - int data_size, total_size; + u32 total_size, nla_genl_hdr_total_size; int result; - - if (type == PMCRAID_HCAM_CODE_LOG_DATA) { - aen_msg = pinstance->ldn.msg; - data_size = pinstance->ldn.hcam->data_len; - } else { - aen_msg = pinstance->ccn.msg; - data_size = pinstance->ccn.hcam->data_len; - } - - data_size += sizeof(struct pmcraid_hcam_hdr); aen_msg->hostno = (pinstance->host->unique_id << 16 | MINOR(pinstance->cdev.dev)); aen_msg->length = data_size; + data_size += sizeof(*aen_msg); total_size = nla_total_size(data_size); - skb = genlmsg_new(total_size, GFP_ATOMIC); + /* Add GENL_HDR to total_size */ + nla_genl_hdr_total_size = + (total_size + (GENL_HDRLEN + + ((struct genl_family *)&pmcraid_event_family)->hdrsize) + + NLMSG_HDRLEN); + skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); if (!skb) { @@ -1329,7 +1497,7 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type) result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); if (result) { - pmcraid_err("failed to copy AEN attribute data \n"); + pmcraid_err("failed to copy AEN attribute data\n"); nlmsg_free(skb); return -EINVAL; } @@ -1350,12 +1518,56 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type) * value. */ if (result) - pmcraid_info("failed to send %s event message %x!\n", - type == PMCRAID_HCAM_CODE_LOG_DATA ? "LDN" : "CCN", - result); + pmcraid_info("error (%x) sending aen event message\n", result); return result; } +/** + * pmcraid_notify_ccn - notifies about CCN event msg to user space + * @pinstance: pointer adapter instance structure + * + * Return value: + * 0 if success, error value in case of any failure + */ +static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) +{ + return pmcraid_notify_aen(pinstance, + pinstance->ccn.msg, + pinstance->ccn.hcam->data_len + + sizeof(struct pmcraid_hcam_hdr)); +} + +/** + * pmcraid_notify_ldn - notifies about CCN event msg to user space + * @pinstance: pointer adapter instance structure + * + * Return value: + * 0 if success, error value in case of any failure + */ +static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) +{ + return pmcraid_notify_aen(pinstance, + pinstance->ldn.msg, + pinstance->ldn.hcam->data_len + + sizeof(struct pmcraid_hcam_hdr)); +} + +/** + * pmcraid_notify_ioastate - sends IOA state event msg to user space + * @pinstance: pointer adapter instance structure + * @evt: controller state event to be sent + * + * Return value: + * 0 if success, error value in case of any failure + */ +static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) +{ + pinstance->scn.ioa_state = evt; + pmcraid_notify_aen(pinstance, + &pinstance->scn.msg, + sizeof(u32)); +} + /** * pmcraid_handle_config_change - Handle a config change from the adapter * @pinstance: pointer to per adapter instance structure @@ -1375,10 +1587,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) unsigned long host_lock_flags; u32 new_entry = 1; u32 hidden_entry = 0; + u16 fw_version; int rc; ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; cfg_entry = &ccn_hcam->cfg_entry; + fw_version = be16_to_cpu(pinstance->inq_data->fw_version); pmcraid_info ("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n", @@ -1391,7 +1605,10 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : RES_BUS(cfg_entry->resource_address)), - RES_IS_VSET(*cfg_entry) ? cfg_entry->unique_flags1 : + RES_IS_VSET(*cfg_entry) ? + (fw_version <= PMCRAID_FW_VERSION_1 ? + cfg_entry->unique_flags1 : + cfg_entry->array_id & 0xFF) : RES_TARGET(cfg_entry->resource_address), RES_LUN(cfg_entry->resource_address)); @@ -1415,11 +1632,16 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) */ if (pinstance->ccn.hcam->notification_type == NOTIFICATION_TYPE_ENTRY_CHANGED && - cfg_entry->resource_type == RES_TYPE_VSET && - cfg_entry->unique_flags1 & 0x80) { - hidden_entry = 1; - } else if (!pmcraid_expose_resource(cfg_entry)) + cfg_entry->resource_type == RES_TYPE_VSET) { + + if (fw_version <= PMCRAID_FW_VERSION_1) + hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; + else + hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; + + } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { goto out_notify_apps; + } spin_lock_irqsave(&pinstance->resource_lock, lock_flags); list_for_each_entry(res, &pinstance->used_res_q, queue) { @@ -1466,13 +1688,15 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) list_add_tail(&res->queue, &pinstance->used_res_q); } - memcpy(&res->cfg_entry, cfg_entry, - sizeof(struct pmcraid_config_table_entry)); + memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); if (pinstance->ccn.hcam->notification_type == NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { if (res->scsi_dev) { - res->cfg_entry.unique_flags1 &= 0x7F; + if (fw_version <= PMCRAID_FW_VERSION_1) + res->cfg_entry.unique_flags1 &= 0x7F; + else + res->cfg_entry.array_id &= 0xFF; res->change_detected = RES_CHANGE_DEL; res->cfg_entry.resource_handle = PMCRAID_INVALID_RES_HANDLE; @@ -1491,7 +1715,7 @@ out_notify_apps: /* Notify configuration changes to registered applications.*/ if (!pmcraid_disable_aen) - pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); + pmcraid_notify_ccn(pinstance); cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); if (cmd) @@ -1528,7 +1752,7 @@ void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) return; /* log the error string */ - pmcraid_err("cmd [%d] for resource %x failed with %x(%s)\n", + pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", cmd->ioa_cb->ioarcb.cdb[0], cmd->ioa_cb->ioarcb.resource_handle, le32_to_cpu(ioasc), error_info->error_string); @@ -1663,7 +1887,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) } /* send netlink message for HCAM notification if enabled */ if (!pmcraid_disable_aen) - pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); + pmcraid_notify_ldn(pinstance); cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); if (cmd) @@ -1701,10 +1925,13 @@ static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) atomic_set(&pinstance->ldn.ignore, 1); /* If adapter reset was forced as part of runtime reset sequence, - * start the reset sequence. + * start the reset sequence. Reset will be triggered even in case + * IOA unit_check. */ - if (pinstance->force_ioa_reset && !pinstance->ioa_bringdown) { + if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || + pinstance->ioa_unit_check) { pinstance->force_ioa_reset = 0; + pinstance->ioa_unit_check = 0; pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; pmcraid_reset_alert(cmd); return; @@ -1735,10 +1962,13 @@ static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_mask_reg); - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_clr_reg); + if (!pinstance->interrupt_mode) { + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs. + ioa_host_interrupt_mask_reg); + iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + } return 1; } else { return 0; @@ -1777,8 +2007,19 @@ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) doorbell = DOORBELL_RUNTIME_RESET | DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; + /* Since we do RESET_ALERT and Start BIST we have to again write + * MSIX Doorbell to indicate the interrupt mode + */ + if (pinstance->interrupt_mode) { + iowrite32(DOORBELL_INTR_MODE_MSIX, + pinstance->int_regs.host_ioa_interrupt_reg); + ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + } + iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); + ioread32(pinstance->int_regs.host_ioa_interrupt_reg), int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + pmcraid_info("Waiting for IOA to become operational %x:%x\n", ioread32(pinstance->int_regs.host_ioa_interrupt_reg), int_reg); @@ -1854,7 +2095,8 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) } else if (cmd->cmd_done == pmcraid_internal_done || cmd->cmd_done == pmcraid_erp_done) { cmd->cmd_done(cmd); - } else if (cmd->cmd_done != pmcraid_ioa_reset) { + } else if (cmd->cmd_done != pmcraid_ioa_reset && + cmd->cmd_done != pmcraid_ioa_shutdown_done) { pmcraid_return_cmd(cmd); } @@ -1964,6 +2206,13 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) pinstance->ioa_reset_attempts = 0; pmcraid_err("IOA didn't respond marking it as dead\n"); pinstance->ioa_state = IOA_STATE_DEAD; + + if (pinstance->ioa_bringdown) + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_SHUTDOWN_FAILED); + else + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_RESET_FAILED); reset_complete = 1; break; } @@ -1971,7 +2220,6 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) /* Once either bist or pci reset is done, restore PCI config * space. If this fails, proceed with hard reset again */ - if (pci_restore_state(pinstance->pdev)) { pmcraid_info("config-space error resetting again\n"); pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; @@ -2002,6 +2250,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) pinstance->ioa_shutdown_type = SHUTDOWN_NONE; pinstance->ioa_bringdown = 0; pinstance->ioa_state = IOA_STATE_UNKNOWN; + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); reset_complete = 1; } else { /* bring-up IOA, so proceed with soft reset @@ -2051,6 +2301,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) */ if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && pinstance->force_ioa_reset == 0) { + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_RESET_SUCCESS); reset_complete = 1; } else { if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) @@ -2116,6 +2368,8 @@ static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) pinstance->ioa_shutdown_type = SHUTDOWN_NONE; pinstance->reset_cmd = cmd; pinstance->force_ioa_reset = 1; + pmcraid_notify_ioastate(pinstance, + PMC_DEVICE_EVENT_RESET_START); pmcraid_ioa_reset(cmd); } } @@ -2191,7 +2445,7 @@ static int pmcraid_reset_reload( wait_event(pinstance->reset_wait_q, !pinstance->ioa_reset_in_progress); - pmcraid_info("reset_reload: reset is complete !! \n"); + pmcraid_info("reset_reload: reset is complete !!\n"); scsi_unblock_requests(pinstance->host); if (pinstance->ioa_state == target_state) reset = 0; @@ -2225,6 +2479,8 @@ static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) */ static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) { + pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); + return pmcraid_reset_reload(pinstance, SHUTDOWN_NONE, IOA_STATE_OPERATIONAL); @@ -2704,7 +2960,7 @@ static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) pmcraid_info("command (%d) CDB[0] = %x for %x\n", le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, - cmd->ioa_cb->ioarcb.cdb[0], + cancel_cmd->ioa_cb->ioarcb.cdb[0], le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); pmcraid_send_cmd(cancel_cmd, @@ -2729,8 +2985,8 @@ static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) u32 ioasc; wait_for_completion(&cancel_cmd->wait_for_completion); - res = cancel_cmd->u.res; - cancel_cmd->u.res = NULL; + res = cancel_cmd->res; + cancel_cmd->res = NULL; ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); /* If the abort task is not timed out we will get a Good completion @@ -2823,7 +3079,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) host_lock_flags); if (cancel_cmd) { - cancel_cmd->u.res = cmd->scsi_cmd->device->hostdata; + cancel_cmd->res = cmd->scsi_cmd->device->hostdata; rc = pmcraid_abort_complete(cancel_cmd); } @@ -2842,7 +3098,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) * takes care by locking/unlocking host_lock. * * Return value - * SUCCESS or FAILED + * SUCCESS or FAILED */ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) { @@ -2879,7 +3135,7 @@ static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) * Initiates adapter reset to bring it up to operational state * * Return value - * SUCCESS or FAILED + * SUCCESS or FAILED */ static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) { @@ -2991,7 +3247,7 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) * to firmware. This builds ioadl descriptors and sets up ioarcb fields. * * Return value: - * 0 on success or -1 on failure + * 0 on success or -1 on failure */ static int pmcraid_build_ioadl( struct pmcraid_instance *pinstance, @@ -3049,7 +3305,7 @@ static int pmcraid_build_ioadl( * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist * * Return value: - * none + * none */ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) { @@ -3070,7 +3326,7 @@ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) * list. * * Return value - * pointer to sglist / NULL on failure + * pointer to sglist / NULL on failure */ static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) { @@ -3224,11 +3480,12 @@ static int pmcraid_queuecommand( struct pmcraid_resource_entry *res; struct pmcraid_ioarcb *ioarcb; struct pmcraid_cmd *cmd; + u32 fw_version; int rc = 0; pinstance = (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; - + fw_version = be16_to_cpu(pinstance->inq_data->fw_version); scsi_cmd->scsi_done = done; res = scsi_cmd->device->hostdata; scsi_cmd->result = (DID_OK << 16); @@ -3247,6 +3504,15 @@ static int pmcraid_queuecommand( if (pinstance->ioa_reset_in_progress) return SCSI_MLQUEUE_HOST_BUSY; + /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete + * the command here itself with success return + */ + if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { + pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); + scsi_cmd->scsi_done(scsi_cmd); + return 0; + } + /* initialize the command and IOARCB to be sent to IOA */ cmd = pmcraid_get_free_cmd(pinstance); @@ -3261,6 +3527,13 @@ static int pmcraid_queuecommand( ioarcb->resource_handle = res->cfg_entry.resource_handle; ioarcb->request_type = REQ_TYPE_SCSI; + /* set hrrq number where the IOA should respond to. Note that all cmds + * generated internally uses hrrq_id 0, exception to this is the cmd + * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses + * hrrq_id assigned here in queuecommand + */ + ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % + pinstance->num_hrrq; cmd->cmd_done = pmcraid_io_done; if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { @@ -3287,7 +3560,9 @@ static int pmcraid_queuecommand( RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : PMCRAID_PHYS_BUS_ID, RES_IS_VSET(res->cfg_entry) ? - res->cfg_entry.unique_flags1 : + (fw_version <= PMCRAID_FW_VERSION_1 ? + res->cfg_entry.unique_flags1 : + res->cfg_entry.array_id & 0xFF) : RES_TARGET(res->cfg_entry.resource_address), RES_LUN(res->cfg_entry.resource_address)); @@ -3465,6 +3740,7 @@ static long pmcraid_ioctl_passthrough( unsigned long request_buffer; unsigned long request_offset; unsigned long lock_flags; + u32 ioasc; int request_size; int buffer_size; u8 access, direction; @@ -3566,6 +3842,14 @@ static long pmcraid_ioctl_passthrough( buffer->ioarcb.add_cmd_param_length); } + /* set hrrq number where the IOA should respond to. Note that all cmds + * generated internally uses hrrq_id 0, exception to this is the cmd + * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses + * hrrq_id assigned here in queuecommand + */ + ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % + pinstance->num_hrrq; + if (request_size) { rc = pmcraid_build_passthrough_ioadls(cmd, request_size, @@ -3606,6 +3890,14 @@ static long pmcraid_ioctl_passthrough( _pmcraid_fire_command(cmd); spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + /* NOTE ! Remove the below line once abort_task is implemented + * in firmware. This line disables ioctl command timeout handling logic + * similar to IO command timeout handling, making ioctl commands to wait + * until the command completion regardless of timeout value specified in + * ioarcb + */ + buffer->ioarcb.cmd_timeout = 0; + /* If command timeout is specified put caller to wait till that time, * otherwise it would be blocking wait. If command gets timed out, it * will be aborted. @@ -3620,25 +3912,47 @@ static long pmcraid_ioctl_passthrough( le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), cmd->ioa_cb->ioarcb.cdb[0]); - rc = -ETIMEDOUT; spin_lock_irqsave(pinstance->host->host_lock, lock_flags); cancel_cmd = pmcraid_abort_cmd(cmd); spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); if (cancel_cmd) { wait_for_completion(&cancel_cmd->wait_for_completion); + ioasc = cancel_cmd->ioa_cb->ioasa.ioasc; pmcraid_return_cmd(cancel_cmd); + + /* if abort task couldn't find the command i.e it got + * completed prior to aborting, return good completion. + * if command got aborted succesfully or there was IOA + * reset due to abort task itself getting timedout then + * return -ETIMEDOUT + */ + if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || + PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { + if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) + rc = -ETIMEDOUT; + goto out_handle_response; + } } - goto out_free_sglist; + /* no command block for abort task or abort task failed to abort + * the IOARCB, then wait for 150 more seconds and initiate reset + * sequence after timeout + */ + if (!wait_for_completion_timeout( + &cmd->wait_for_completion, + msecs_to_jiffies(150 * 1000))) { + pmcraid_reset_bringup(cmd->drv_inst); + rc = -ETIMEDOUT; + } } +out_handle_response: /* If the command failed for any reason, copy entire IOASA buffer and * return IOCTL success. If copying IOASA to user-buffer fails, return * EFAULT */ - if (le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)) { - + if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) { void *ioasa = (void *)(arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); @@ -3651,6 +3965,7 @@ static long pmcraid_ioctl_passthrough( rc = -EFAULT; } } + /* If the data transfer was from device, copy the data onto user * buffers */ @@ -3699,7 +4014,7 @@ static long pmcraid_ioctl_driver( int rc = -ENOSYS; if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { - pmcraid_err("ioctl_driver: access fault in request buffer \n"); + pmcraid_err("ioctl_driver: access fault in request buffer\n"); return -EFAULT; } @@ -4011,36 +4326,77 @@ static struct scsi_host_template pmcraid_host_template = { .proc_name = PMCRAID_DRIVER_NAME }; -/** - * pmcraid_isr_common - Common interrupt handler routine - * - * @pinstance: pointer to adapter instance - * @intrs: active interrupts (contents of ioa_host_interrupt register) - * @hrrq_id: Host RRQ index +/* + * pmcraid_isr_msix - implements MSI-X interrupt handling routine + * @irq: interrupt vector number + * @dev_id: pointer hrrq_vector * * Return Value - * none + * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored */ -static void pmcraid_isr_common( - struct pmcraid_instance *pinstance, - u32 intrs, - int hrrq_id -) + +static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) { - u32 intrs_clear = - (intrs & INTRS_CRITICAL_OP_IN_PROGRESS) ? intrs - : INTRS_HRRQ_VALID; - iowrite32(intrs_clear, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + struct pmcraid_isr_param *hrrq_vector; + struct pmcraid_instance *pinstance; + unsigned long lock_flags; + u32 intrs_val; + int hrrq_id; + + hrrq_vector = (struct pmcraid_isr_param *)dev_id; + hrrq_id = hrrq_vector->hrrq_id; + pinstance = hrrq_vector->drv_inst; + + if (!hrrq_id) { + /* Read the interrupt */ + intrs_val = pmcraid_read_interrupts(pinstance); + if (intrs_val && + ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) + & DOORBELL_INTR_MSIX_CLR) == 0)) { + /* Any error interrupts including unit_check, + * initiate IOA reset.In case of unit check indicate + * to reset_sequence that IOA unit checked and prepare + * for a dump during reset sequence + */ + if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { + if (intrs_val & INTRS_IOA_UNIT_CHECK) + pinstance->ioa_unit_check = 1; + + pmcraid_err("ISR: error interrupts: %x \ + initiating reset\n", intrs_val); + spin_lock_irqsave(pinstance->host->host_lock, + lock_flags); + pmcraid_initiate_reset(pinstance); + spin_unlock_irqrestore( + pinstance->host->host_lock, + lock_flags); + } + /* If interrupt was as part of the ioa initialization, + * clear it. Delete the timer and wakeup the + * reset engine to proceed with reset sequence + */ + if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) + pmcraid_clr_trans_op(pinstance); + + /* Clear the interrupt register by writing + * to host to ioa doorbell. Once done + * FW will clear the interrupt. + */ + iowrite32(DOORBELL_INTR_MSIX_CLR, + pinstance->int_regs.host_ioa_interrupt_reg); + ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + - /* hrrq valid bit was set, schedule tasklet to handle the response */ - if (intrs_clear == INTRS_HRRQ_VALID) - tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); + } + } + + tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); + + return IRQ_HANDLED; } /** - * pmcraid_isr - implements interrupt handling routine + * pmcraid_isr - implements legacy interrupt handling routine * * @irq: interrupt vector number * @dev_id: pointer hrrq_vector @@ -4052,8 +4408,9 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id) { struct pmcraid_isr_param *hrrq_vector; struct pmcraid_instance *pinstance; - unsigned long lock_flags; u32 intrs; + unsigned long lock_flags; + int hrrq_id = 0; /* In case of legacy interrupt mode where interrupts are shared across * isrs, it may be possible that the current interrupt is not from IOA @@ -4062,21 +4419,13 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id) printk(KERN_INFO "%s(): NULL host pointer\n", __func__); return IRQ_NONE; } - hrrq_vector = (struct pmcraid_isr_param *)dev_id; pinstance = hrrq_vector->drv_inst; - /* Acquire the lock (currently host_lock) while processing interrupts. - * This interval is small as most of the response processing is done by - * tasklet without the lock. - */ - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); intrs = pmcraid_read_interrupts(pinstance); - if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) { - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) return IRQ_NONE; - } /* Any error interrupts including unit_check, initiate IOA reset. * In case of unit check indicate to reset_sequence that IOA unit @@ -4091,13 +4440,28 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id) pinstance->int_regs.ioa_host_interrupt_clr_reg); pmcraid_err("ISR: error interrupts: %x initiating reset\n", intrs); - intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); + intrs = ioread32( + pinstance->int_regs.ioa_host_interrupt_clr_reg); + spin_lock_irqsave(pinstance->host->host_lock, lock_flags); pmcraid_initiate_reset(pinstance); + spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); } else { - pmcraid_isr_common(pinstance, intrs, hrrq_vector->hrrq_id); - } + /* If interrupt was as part of the ioa initialization, + * clear. Delete the timer and wakeup the + * reset engine to proceed with reset sequence + */ + if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { + pmcraid_clr_trans_op(pinstance); + } else { + iowrite32(intrs, + pinstance->int_regs.ioa_host_interrupt_clr_reg); + ioread32( + pinstance->int_regs.ioa_host_interrupt_clr_reg); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); + tasklet_schedule( + &(pinstance->isr_tasklet[hrrq_id])); + } + } return IRQ_HANDLED; } @@ -4120,6 +4484,7 @@ static void pmcraid_worker_function(struct work_struct *workp) struct scsi_device *sdev; unsigned long lock_flags; unsigned long host_lock_flags; + u16 fw_version; u8 bus, target, lun; pinstance = container_of(workp, struct pmcraid_instance, worker_q); @@ -4127,6 +4492,8 @@ static void pmcraid_worker_function(struct work_struct *workp) if (!atomic_read(&pinstance->expose_resources)) return; + fw_version = be16_to_cpu(pinstance->inq_data->fw_version); + spin_lock_irqsave(&pinstance->resource_lock, lock_flags); list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { @@ -4166,12 +4533,16 @@ static void pmcraid_worker_function(struct work_struct *workp) if (res->change_detected == RES_CHANGE_ADD) { - if (!pmcraid_expose_resource(&res->cfg_entry)) + if (!pmcraid_expose_resource(fw_version, + &res->cfg_entry)) continue; if (RES_IS_VSET(res->cfg_entry)) { bus = PMCRAID_VSET_BUS_ID; - target = res->cfg_entry.unique_flags1; + if (fw_version <= PMCRAID_FW_VERSION_1) + target = res->cfg_entry.unique_flags1; + else + target = res->cfg_entry.array_id & 0xFF; lun = PMCRAID_VSET_LUN_ID; } else { bus = PMCRAID_PHYS_BUS_ID; @@ -4201,7 +4572,7 @@ static void pmcraid_worker_function(struct work_struct *workp) * Return Value * None */ -void pmcraid_tasklet_function(unsigned long instance) +static void pmcraid_tasklet_function(unsigned long instance) { struct pmcraid_isr_param *hrrq_vector; struct pmcraid_instance *pinstance; @@ -4210,35 +4581,12 @@ void pmcraid_tasklet_function(unsigned long instance) unsigned long host_lock_flags; spinlock_t *lockp; /* hrrq buffer lock */ int id; - u32 intrs; __le32 resp; hrrq_vector = (struct pmcraid_isr_param *)instance; pinstance = hrrq_vector->drv_inst; id = hrrq_vector->hrrq_id; lockp = &(pinstance->hrrq_lock[id]); - intrs = pmcraid_read_interrupts(pinstance); - - /* If interrupts was as part of the ioa initialization, clear and mask - * it. Delete the timer and wakeup the reset engine to proceed with - * reset sequence - */ - if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_mask_reg); - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - - if (pinstance->reset_cmd != NULL) { - del_timer(&pinstance->reset_cmd->timer); - spin_lock_irqsave(pinstance->host->host_lock, - host_lock_flags); - pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - } - return; - } /* loop through each of the commands responded by IOA. Each HRRQ buf is * protected by its own lock. Traversals must be done within this lock @@ -4256,27 +4604,6 @@ void pmcraid_tasklet_function(unsigned long instance) int cmd_index = resp >> 2; struct pmcraid_cmd *cmd = NULL; - if (cmd_index < PMCRAID_MAX_CMD) { - cmd = pinstance->cmd_list[cmd_index]; - } else { - /* In case of invalid response handle, initiate IOA - * reset sequence. - */ - spin_unlock_irqrestore(lockp, hrrq_lock_flags); - - pmcraid_err("Invalid response %d initiating reset\n", - cmd_index); - - spin_lock_irqsave(pinstance->host->host_lock, - host_lock_flags); - pmcraid_initiate_reset(pinstance); - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - - spin_lock_irqsave(lockp, hrrq_lock_flags); - break; - } - if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { pinstance->hrrq_curr[id]++; } else { @@ -4284,6 +4611,14 @@ void pmcraid_tasklet_function(unsigned long instance) pinstance->host_toggle_bit[id] ^= 1u; } + if (cmd_index >= PMCRAID_MAX_CMD) { + /* In case of invalid response handle, log message */ + pmcraid_err("Invalid response handle %d\n", cmd_index); + resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); + continue; + } + + cmd = pinstance->cmd_list[cmd_index]; spin_unlock_irqrestore(lockp, hrrq_lock_flags); spin_lock_irqsave(&pinstance->pending_pool_lock, @@ -4324,7 +4659,16 @@ void pmcraid_tasklet_function(unsigned long instance) static void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) { - free_irq(pinstance->pdev->irq, &(pinstance->hrrq_vector[0])); + int i; + + for (i = 0; i < pinstance->num_hrrq; i++) + free_irq(pinstance->hrrq_vector[i].vector, + &(pinstance->hrrq_vector[i])); + + if (pinstance->interrupt_mode) { + pci_disable_msix(pinstance->pdev); + pinstance->interrupt_mode = 0; + } } /** @@ -4337,14 +4681,70 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) static int pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) { + int rc; struct pci_dev *pdev = pinstance->pdev; + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; + struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; + int i; + for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) + entries[i].entry = i; + + rc = pci_enable_msix(pdev, entries, num_hrrq); + if (rc < 0) + goto pmcraid_isr_legacy; + + /* Check how many MSIX vectors are allocated and register + * msi-x handlers for each of them giving appropriate buffer + */ + if (rc > 0) { + num_hrrq = rc; + if (pci_enable_msix(pdev, entries, num_hrrq)) + goto pmcraid_isr_legacy; + } + + for (i = 0; i < num_hrrq; i++) { + pinstance->hrrq_vector[i].hrrq_id = i; + pinstance->hrrq_vector[i].drv_inst = pinstance; + pinstance->hrrq_vector[i].vector = entries[i].vector; + rc = request_irq(pinstance->hrrq_vector[i].vector, + pmcraid_isr_msix, 0, + PMCRAID_DRIVER_NAME, + &(pinstance->hrrq_vector[i])); + + if (rc) { + int j; + for (j = 0; j < i; j++) + free_irq(entries[j].vector, + &(pinstance->hrrq_vector[j])); + pci_disable_msix(pdev); + goto pmcraid_isr_legacy; + } + } + + pinstance->num_hrrq = num_hrrq; + pinstance->interrupt_mode = 1; + iowrite32(DOORBELL_INTR_MODE_MSIX, + pinstance->int_regs.host_ioa_interrupt_reg); + ioread32(pinstance->int_regs.host_ioa_interrupt_reg); + goto pmcraid_isr_out; + } + +pmcraid_isr_legacy: + /* If MSI-X registration failed fallback to legacy mode, where + * only one hrrq entry will be used + */ pinstance->hrrq_vector[0].hrrq_id = 0; pinstance->hrrq_vector[0].drv_inst = pinstance; - pinstance->hrrq_vector[0].vector = 0; + pinstance->hrrq_vector[0].vector = pdev->irq; pinstance->num_hrrq = 1; - return request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, - PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); + rc = 0; + + rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, + PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); +pmcraid_isr_out: + return rc; } /** @@ -4516,12 +4916,11 @@ pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) static int __devinit pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) { - int i; - int buf_count = PMCRAID_MAX_CMD / pinstance->num_hrrq; + int i, buffer_size; - for (i = 0; i < pinstance->num_hrrq; i++) { - int buffer_size = HRRQ_ENTRY_SIZE * buf_count; + buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; + for (i = 0; i < pinstance->num_hrrq; i++) { pinstance->hrrq_start[i] = pci_alloc_consistent( pinstance->pdev, @@ -4529,7 +4928,8 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) &(pinstance->hrrq_start_bus_addr[i])); if (pinstance->hrrq_start[i] == 0) { - pmcraid_err("could not allocate host rrq: %d\n", i); + pmcraid_err("pci_alloc failed for hrrq vector : %d\n", + i); pmcraid_release_host_rrqs(pinstance, i); return -ENOMEM; } @@ -4537,7 +4937,7 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) memset(pinstance->hrrq_start[i], 0, buffer_size); pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; pinstance->hrrq_end[i] = - pinstance->hrrq_start[i] + buf_count - 1; + pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; pinstance->host_toggle_bit[i] = 1; spin_lock_init(&pinstance->hrrq_lock[i]); } @@ -4557,7 +4957,7 @@ static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) if (pinstance->ccn.msg != NULL) { pci_free_consistent(pinstance->pdev, PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ccn), + sizeof(struct pmcraid_hcam_ccn_ext), pinstance->ccn.msg, pinstance->ccn.baddr); @@ -4591,7 +4991,7 @@ static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) pinstance->ccn.msg = pci_alloc_consistent( pinstance->pdev, PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ccn), + sizeof(struct pmcraid_hcam_ccn_ext), &(pinstance->ccn.baddr)); pinstance->ldn.msg = pci_alloc_consistent( @@ -4723,6 +5123,32 @@ static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) tasklet_kill(&pinstance->isr_tasklet[i]); } +/** + * pmcraid_release_buffers - release per-adapter buffers allocated + * + * @pinstance: pointer to adapter soft state + * + * Return Value + * none + */ +static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) +{ + pmcraid_release_config_buffers(pinstance); + pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); + pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); + pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); + + if (pinstance->inq_data != NULL) { + pci_free_consistent(pinstance->pdev, + sizeof(struct pmcraid_inquiry_data), + pinstance->inq_data, + pinstance->inq_data_baddr); + + pinstance->inq_data = NULL; + pinstance->inq_data_baddr = 0; + } +} + /** * pmcraid_init_buffers - allocates memory and initializes various structures * @pinstance: pointer to per adapter instance structure @@ -4753,20 +5179,32 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) } if (pmcraid_allocate_cmd_blocks(pinstance)) { - pmcraid_err("couldn't allocate memory for cmd blocks \n"); + pmcraid_err("couldn't allocate memory for cmd blocks\n"); pmcraid_release_config_buffers(pinstance); pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); return -ENOMEM; } if (pmcraid_allocate_control_blocks(pinstance)) { - pmcraid_err("couldn't allocate memory control blocks \n"); + pmcraid_err("couldn't allocate memory control blocks\n"); pmcraid_release_config_buffers(pinstance); pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); return -ENOMEM; } + /* allocate DMAable memory for page D0 INQUIRY buffer */ + pinstance->inq_data = pci_alloc_consistent( + pinstance->pdev, + sizeof(struct pmcraid_inquiry_data), + &pinstance->inq_data_baddr); + + if (pinstance->inq_data == NULL) { + pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); + pmcraid_release_buffers(pinstance); + return -ENOMEM; + } + /* Initialize all the command blocks and add them to free pool. No * need to lock (free_pool_lock) as this is done in initialization * itself @@ -4785,7 +5223,7 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) * pmcraid_reinit_buffers - resets various buffer pointers * @pinstance: pointer to adapter instance * Return value - * none + * none */ static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) { @@ -4836,6 +5274,8 @@ static int __devinit pmcraid_init_instance( mapped_pci_addr + chip_cfg->ioa_host_intr; pint_regs->ioa_host_interrupt_clr_reg = mapped_pci_addr + chip_cfg->ioa_host_intr_clr; + pint_regs->ioa_host_msix_interrupt_reg = + mapped_pci_addr + chip_cfg->ioa_host_msix_intr; pint_regs->host_ioa_interrupt_reg = mapped_pci_addr + chip_cfg->host_ioa_intr; pint_regs->host_ioa_interrupt_clr_reg = @@ -4858,6 +5298,7 @@ static int __devinit pmcraid_init_instance( init_waitqueue_head(&pinstance->reset_wait_q); atomic_set(&pinstance->outstanding_cmds, 0); + atomic_set(&pinstance->last_message_id, 0); atomic_set(&pinstance->expose_resources, 0); INIT_LIST_HEAD(&pinstance->free_res_q); @@ -4882,23 +5323,6 @@ static int __devinit pmcraid_init_instance( return 0; } -/** - * pmcraid_release_buffers - release per-adapter buffers allocated - * - * @pinstance: pointer to adapter soft state - * - * Return Value - * none - */ -static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) -{ - pmcraid_release_config_buffers(pinstance); - pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); - pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); - pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); - -} - /** * pmcraid_shutdown - shutdown adapter controller. * @pdev: pci device struct @@ -4958,7 +5382,7 @@ static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) pmcraid_release_minor(minor); else device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), - NULL, "pmcsas%u", minor); + NULL, "%s%u", PMCRAID_DEVFILE, minor); return error; } @@ -5050,7 +5474,6 @@ static int pmcraid_resume(struct pci_dev *pdev) struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); struct Scsi_Host *host = pinstance->host; int rc; - int hrrqs; pci_set_power_state(pdev, PCI_D0); pci_enable_wake(pdev, PCI_D0, 0); @@ -5077,8 +5500,8 @@ static int pmcraid_resume(struct pci_dev *pdev) goto disable_device; } + pmcraid_disable_interrupts(pinstance, ~0); atomic_set(&pinstance->outstanding_cmds, 0); - hrrqs = pinstance->num_hrrq; rc = pmcraid_register_interrupt_handler(pinstance); if (rc) { @@ -5100,7 +5523,7 @@ static int pmcraid_resume(struct pci_dev *pdev) * state. */ if (pmcraid_reset_bringup(pinstance)) { - dev_err(&pdev->dev, "couldn't initialize IOA \n"); + dev_err(&pdev->dev, "couldn't initialize IOA\n"); rc = -ENODEV; goto release_tasklets; } @@ -5108,6 +5531,7 @@ static int pmcraid_resume(struct pci_dev *pdev) return 0; release_tasklets: + pmcraid_disable_interrupts(pinstance, ~0); pmcraid_kill_tasklets(pinstance); pmcraid_unregister_interrupt_handler(pinstance); @@ -5129,7 +5553,7 @@ disable_device: /** * pmcraid_complete_ioa_reset - Called by either timer or tasklet during - * completion of the ioa reset + * completion of the ioa reset * @cmd: pointer to reset command block */ static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) @@ -5204,11 +5628,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) struct pmcraid_config_table_entry *cfgte; unsigned long lock_flags; int found, rc, i; + u16 fw_version; LIST_HEAD(old_res); if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) pmcraid_err("IOA requires microcode download\n"); + fw_version = be16_to_cpu(pinstance->inq_data->fw_version); + /* resource list is protected by pinstance->resource_lock. * init_res_table can be called from probe (user-thread) or runtime * reset (timer/tasklet) @@ -5219,9 +5646,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) list_move_tail(&res->queue, &old_res); for (i = 0; i < pinstance->cfg_table->num_entries; i++) { - cfgte = &pinstance->cfg_table->entries[i]; + if (be16_to_cpu(pinstance->inq_data->fw_version) <= + PMCRAID_FW_VERSION_1) + cfgte = &pinstance->cfg_table->entries[i]; + else + cfgte = (struct pmcraid_config_table_entry *) + &pinstance->cfg_table->entries_ext[i]; - if (!pmcraid_expose_resource(cfgte)) + if (!pmcraid_expose_resource(fw_version, cfgte)) continue; found = 0; @@ -5263,10 +5695,12 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) */ if (found) { memcpy(&res->cfg_entry, cfgte, - sizeof(struct pmcraid_config_table_entry)); + pinstance->config_table_entry_size); pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", res->cfg_entry.resource_type, - res->cfg_entry.unique_flags1, + (fw_version <= PMCRAID_FW_VERSION_1 ? + res->cfg_entry.unique_flags1 : + res->cfg_entry.array_id & 0xFF), le32_to_cpu(res->cfg_entry.resource_address)); } } @@ -5306,6 +5740,14 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd) struct pmcraid_instance *pinstance = cmd->drv_inst; int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); + if (be16_to_cpu(pinstance->inq_data->fw_version) <= + PMCRAID_FW_VERSION_1) + pinstance->config_table_entry_size = + sizeof(struct pmcraid_config_table_entry); + else + pinstance->config_table_entry_size = + sizeof(struct pmcraid_config_table_entry_ext); + ioarcb->request_type = REQ_TYPE_IOACMD; ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); @@ -5338,7 +5780,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd) /** - * pmcraid_probe - PCI probe entry pointer for PMC MaxRaid controller driver + * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver * @pdev: pointer to pci device structure * @dev_id: pointer to device ids structure * @@ -5485,7 +5927,7 @@ static int __devinit pmcraid_probe( */ pmcraid_info("starting IOA initialization sequence\n"); if (pmcraid_reset_bringup(pinstance)) { - dev_err(&pdev->dev, "couldn't initialize IOA \n"); + dev_err(&pdev->dev, "couldn't initialize IOA\n"); rc = 1; goto out_release_bufs; } diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index b8ad07c3449..6cfa0145a1d 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -40,10 +40,12 @@ * Driver version: version string in major_version.minor_version.patch format * Driver date : date information in "Mon dd yyyy" format */ -#define PMCRAID_DRIVER_NAME "PMC MaxRAID" +#define PMCRAID_DRIVER_NAME "PMC MaxRAID" #define PMCRAID_DEVFILE "pmcsas" -#define PMCRAID_DRIVER_VERSION "1.0.2" -#define PMCRAID_DRIVER_DATE __DATE__ +#define PMCRAID_DRIVER_VERSION "2.0.2" +#define PMCRAID_DRIVER_DATE __DATE__ + +#define PMCRAID_FW_VERSION_1 0x002 /* Maximum number of adapters supported by current version of the driver */ #define PMCRAID_MAX_ADAPTERS 1024 @@ -85,17 +87,17 @@ #define PMCRAID_IOARCB_ALIGNMENT 32 #define PMCRAID_IOADL_ALIGNMENT 16 #define PMCRAID_IOASA_ALIGNMENT 4 -#define PMCRAID_NUM_MSIX_VECTORS 1 +#define PMCRAID_NUM_MSIX_VECTORS 16 /* various other limits */ -#define PMCRAID_VENDOR_ID_LEN 8 -#define PMCRAID_PRODUCT_ID_LEN 16 -#define PMCRAID_SERIAL_NUM_LEN 8 -#define PMCRAID_LUN_LEN 8 -#define PMCRAID_MAX_CDB_LEN 16 -#define PMCRAID_DEVICE_ID_LEN 8 -#define PMCRAID_SENSE_DATA_LEN 256 -#define PMCRAID_ADD_CMD_PARAM_LEN 48 +#define PMCRAID_VENDOR_ID_LEN 8 +#define PMCRAID_PRODUCT_ID_LEN 16 +#define PMCRAID_SERIAL_NUM_LEN 8 +#define PMCRAID_LUN_LEN 8 +#define PMCRAID_MAX_CDB_LEN 16 +#define PMCRAID_DEVICE_ID_LEN 8 +#define PMCRAID_SENSE_DATA_LEN 256 +#define PMCRAID_ADD_CMD_PARAM_LEN 48 #define PMCRAID_MAX_BUS_TO_SCAN 1 #define PMCRAID_MAX_NUM_TARGETS_PER_BUS 256 @@ -116,17 +118,10 @@ #define PMCRAID_VSET_MAX_SECTORS 512 #define PMCRAID_MAX_CMD_PER_LUN 254 -/* Number of configuration table entries (resources) */ -#define PMCRAID_MAX_NUM_OF_VSETS 240 - -/* Todo : Check max limit for Phase 1 */ -#define PMCRAID_MAX_NUM_OF_PHY_DEVS 256 - -/* MAX_NUM_OF_DEVS includes 1 FP, 1 Dummy Enclosure device */ -#define PMCRAID_MAX_NUM_OF_DEVS \ - (PMCRAID_MAX_NUM_OF_VSETS + PMCRAID_MAX_NUM_OF_PHY_DEVS + 2) - -#define PMCRAID_MAX_RESOURCES PMCRAID_MAX_NUM_OF_DEVS +/* Number of configuration table entries (resources), includes 1 FP, + * 1 Enclosure device + */ +#define PMCRAID_MAX_RESOURCES 256 /* Adapter Commands used by driver */ #define PMCRAID_QUERY_RESOURCE_STATE 0xC2 @@ -177,6 +172,7 @@ #define PMCRAID_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff) #define PMCRAID_IOASC_GOOD_COMPLETION 0x00000000 +#define PMCRAID_IOASC_GC_IOARCB_NOTFOUND 0x005A0000 #define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 #define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED 0x02048000 #define PMCRAID_IOASC_NR_SYNC_REQUIRED 0x023F0000 @@ -187,12 +183,12 @@ #define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED 0x04448600 #define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000 #define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000 -#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000 -#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000 +#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000 +#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000 /* Driver defined IOASCs */ -#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001 -#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002 +#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001 +#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002 /* Various timeout values (in milliseconds) used. If any of these are chip * specific, move them to pmcraid_chip_details structure. @@ -336,6 +332,13 @@ struct pmcraid_config_table_entry { __u8 lun[PMCRAID_LUN_LEN]; } __attribute__((packed, aligned(4))); +/* extended configuration table sizes are of 64 bytes in size */ +#define PMCRAID_CFGTE_EXT_SIZE 32 +struct pmcraid_config_table_entry_ext { + struct pmcraid_config_table_entry cfgte; + __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE]; +}; + /* resource types (config_table_entry.resource_type values) */ #define RES_TYPE_AF_DASD 0x00 #define RES_TYPE_GSCSI 0x01 @@ -376,7 +379,12 @@ struct pmcraid_config_table { __u8 reserved1; __u8 flags; __u8 reserved2[11]; - struct pmcraid_config_table_entry entries[PMCRAID_MAX_RESOURCES]; + union { + struct pmcraid_config_table_entry + entries[PMCRAID_MAX_RESOURCES]; + struct pmcraid_config_table_entry_ext + entries_ext[PMCRAID_MAX_RESOURCES]; + }; } __attribute__((packed, aligned(4))); /* config_table.flags value */ @@ -385,7 +393,7 @@ struct pmcraid_config_table { /* * HCAM format */ -#define PMCRAID_HOSTRCB_LDNSIZE 4056 +#define PMCRAID_HOSTRCB_LDNSIZE 4056 /* Error log notification format */ struct pmcraid_hostrcb_error { @@ -416,6 +424,15 @@ struct pmcraid_hcam_hdr { struct pmcraid_hcam_ccn { struct pmcraid_hcam_hdr header; struct pmcraid_config_table_entry cfg_entry; + struct pmcraid_config_table_entry cfg_entry_old; +} __attribute__((packed, aligned(4))); + +#define PMCRAID_CCN_EXT_SIZE 3944 +struct pmcraid_hcam_ccn_ext { + struct pmcraid_hcam_hdr header; + struct pmcraid_config_table_entry_ext cfg_entry; + struct pmcraid_config_table_entry_ext cfg_entry_old; + __u8 reserved[PMCRAID_CCN_EXT_SIZE]; } __attribute__((packed, aligned(4))); struct pmcraid_hcam_ldn { @@ -431,6 +448,8 @@ struct pmcraid_hcam_ldn { #define NOTIFICATION_TYPE_ENTRY_CHANGED 0x0 #define NOTIFICATION_TYPE_ENTRY_NEW 0x1 #define NOTIFICATION_TYPE_ENTRY_DELETED 0x2 +#define NOTIFICATION_TYPE_STATE_CHANGE 0x3 +#define NOTIFICATION_TYPE_ENTRY_STATECHANGED 0x4 #define NOTIFICATION_TYPE_ERROR_LOG 0x10 #define NOTIFICATION_TYPE_INFORMATION_LOG 0x11 @@ -460,6 +479,7 @@ struct pmcraid_chip_details { unsigned long mailbox; unsigned long global_intr_mask; unsigned long ioa_host_intr; + unsigned long ioa_host_msix_intr; unsigned long ioa_host_intr_clr; unsigned long ioa_host_mask; unsigned long ioa_host_mask_clr; @@ -482,6 +502,7 @@ struct pmcraid_chip_details { #define INTRS_IOA_PROCESSOR_ERROR PMC_BIT32(29) #define INTRS_HRRQ_VALID PMC_BIT32(30) #define INTRS_OPERATIONAL_STATUS PMC_BIT32(0) +#define INTRS_ALLOW_MSIX_VECTOR0 PMC_BIT32(31) /* Host to IOA Doorbells */ #define DOORBELL_RUNTIME_RESET PMC_BIT32(1) @@ -489,10 +510,12 @@ struct pmcraid_chip_details { #define DOORBELL_IOA_DEBUG_ALERT PMC_BIT32(9) #define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS PMC_BIT32(8) #define DOORBELL_IOA_START_BIST PMC_BIT32(23) +#define DOORBELL_INTR_MODE_MSIX PMC_BIT32(25) +#define DOORBELL_INTR_MSIX_CLR PMC_BIT32(26) #define DOORBELL_RESET_IOA PMC_BIT32(31) /* Global interrupt mask register value */ -#define GLOBAL_INTERRUPT_MASK 0x4ULL +#define GLOBAL_INTERRUPT_MASK 0x5ULL #define PMCRAID_ERROR_INTERRUPTS (INTRS_IOARCB_TRANSFER_FAILED | \ INTRS_IOA_UNIT_CHECK | \ @@ -503,8 +526,8 @@ struct pmcraid_chip_details { #define PMCRAID_PCI_INTERRUPTS (PMCRAID_ERROR_INTERRUPTS | \ INTRS_HRRQ_VALID | \ - INTRS_CRITICAL_OP_IN_PROGRESS |\ - INTRS_TRANSITION_TO_OPERATIONAL) + INTRS_TRANSITION_TO_OPERATIONAL |\ + INTRS_ALLOW_MSIX_VECTOR0) /* control_block, associated with each of the commands contains IOARCB, IOADLs * memory for IOASA. Additional 3 * 16 bytes are allocated in order to support @@ -526,17 +549,24 @@ struct pmcraid_sglist { struct scatterlist scatterlist[1]; }; +/* page D0 inquiry data of focal point resource */ +struct pmcraid_inquiry_data { + __u8 ph_dev_type; + __u8 page_code; + __u8 reserved1; + __u8 add_page_len; + __u8 length; + __u8 reserved2; + __le16 fw_version; + __u8 reserved3[16]; +}; + /* pmcraid_cmd - LLD representation of SCSI command */ struct pmcraid_cmd { /* Ptr and bus address of DMA.able control block for this command */ struct pmcraid_control_block *ioa_cb; dma_addr_t ioa_cb_bus_addr; - - /* sense buffer for REQUEST SENSE command if firmware is not sending - * auto sense data - */ - dma_addr_t sense_buffer_dma; dma_addr_t dma_handle; u8 *sense_buffer; @@ -556,11 +586,22 @@ struct pmcraid_cmd { struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */ - /* scratch used during reset sequence */ + /* scratch used */ union { + /* during reset sequence */ unsigned long time_left; struct pmcraid_resource_entry *res; - } u; + int hrrq_index; + + /* used during IO command error handling. Sense buffer + * for REQUEST SENSE command if firmware is not sending + * auto sense data + */ + struct { + u8 *sense_buffer; + dma_addr_t sense_buffer_dma; + }; + }; }; /* @@ -568,6 +609,7 @@ struct pmcraid_cmd { */ struct pmcraid_interrupts { void __iomem *ioa_host_interrupt_reg; + void __iomem *ioa_host_msix_interrupt_reg; void __iomem *ioa_host_interrupt_clr_reg; void __iomem *ioa_host_interrupt_mask_reg; void __iomem *ioa_host_interrupt_mask_clr_reg; @@ -578,11 +620,12 @@ struct pmcraid_interrupts { /* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */ struct pmcraid_isr_param { - u8 hrrq_id; /* hrrq entry index */ - u16 vector; /* allocated msi-x vector */ struct pmcraid_instance *drv_inst; + u16 vector; /* allocated msi-x vector */ + u8 hrrq_id; /* hrrq entry index */ }; + /* AEN message header sent as part of event data to applications */ struct pmcraid_aen_msg { u32 hostno; @@ -591,6 +634,19 @@ struct pmcraid_aen_msg { u8 data[0]; }; +/* Controller state event message type */ +struct pmcraid_state_msg { + struct pmcraid_aen_msg msg; + u32 ioa_state; +}; + +#define PMC_DEVICE_EVENT_RESET_START 0x11000000 +#define PMC_DEVICE_EVENT_RESET_SUCCESS 0x11000001 +#define PMC_DEVICE_EVENT_RESET_FAILED 0x11000002 +#define PMC_DEVICE_EVENT_SHUTDOWN_START 0x11000003 +#define PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS 0x11000004 +#define PMC_DEVICE_EVENT_SHUTDOWN_FAILED 0x11000005 + struct pmcraid_hostrcb { struct pmcraid_instance *drv_inst; struct pmcraid_aen_msg *msg; @@ -628,6 +684,7 @@ struct pmcraid_instance { /* HostRCBs needed for HCAM */ struct pmcraid_hostrcb ldn; struct pmcraid_hostrcb ccn; + struct pmcraid_state_msg scn; /* controller state change msg */ /* Bus address of start of HRRQ */ @@ -645,12 +702,15 @@ struct pmcraid_instance { /* Lock for HRRQ access */ spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS]; + struct pmcraid_inquiry_data *inq_data; + dma_addr_t inq_data_baddr; + + /* size of configuration table entry, varies based on the firmware */ + u32 config_table_entry_size; + /* Expected toggle bit at host */ u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS]; - /* No of Reset IOA retries . IOA marked dead if threshold exceeds */ - u8 ioa_reset_attempts; -#define PMCRAID_RESET_ATTEMPTS 3 /* Wait Q for threads to wait for Reset IOA completion */ wait_queue_head_t reset_wait_q; @@ -664,14 +724,22 @@ struct pmcraid_instance { struct Scsi_Host *host; /* mid layer interface structure handle */ struct pci_dev *pdev; /* PCI device structure handle */ + /* No of Reset IOA retries . IOA marked dead if threshold exceeds */ + u8 ioa_reset_attempts; +#define PMCRAID_RESET_ATTEMPTS 3 + u8 current_log_level; /* default level for logging IOASC errors */ u8 num_hrrq; /* Number of interrupt vectors allocated */ + u8 interrupt_mode; /* current interrupt mode legacy or msix */ dev_t dev; /* Major-Minor numbers for Char device */ /* Used as ISR handler argument */ struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS]; + /* Message id as filled in last fired IOARCB, used to identify HRRQ */ + atomic_t last_message_id; + /* configuration table */ struct pmcraid_config_table *cfg_table; dma_addr_t cfg_table_bus_addr; @@ -686,8 +754,14 @@ struct pmcraid_instance { struct list_head free_cmd_pool; struct list_head pending_cmd_pool; - spinlock_t free_pool_lock; /* free pool lock */ - spinlock_t pending_pool_lock; /* pending pool lock */ + spinlock_t free_pool_lock; /* free pool lock */ + spinlock_t pending_pool_lock; /* pending pool lock */ + + /* Tasklet to handle deferred processing */ + struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS]; + + /* Work-queue (Shared) for deferred reset processing */ + struct work_struct worker_q; /* No of IO commands pending with FW */ atomic_t outstanding_cmds; @@ -695,11 +769,6 @@ struct pmcraid_instance { /* should add/delete resources to mid-layer now ?*/ atomic_t expose_resources; - /* Tasklet to handle deferred processing */ - struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS]; - - /* Work-queue (Shared) for deferred reset processing */ - struct work_struct worker_q; u32 ioa_state:4; /* For IOA Reset sequence FSM */ @@ -728,7 +797,10 @@ struct pmcraid_instance { /* LLD maintained resource entry structure */ struct pmcraid_resource_entry { struct list_head queue; /* link to "to be exposed" resources */ - struct pmcraid_config_table_entry cfg_entry; + union { + struct pmcraid_config_table_entry cfg_entry; + struct pmcraid_config_table_entry_ext cfg_entry_ext; + }; struct scsi_device *scsi_dev; /* Link scsi_device structure */ atomic_t read_failures; /* count of failed READ commands */ atomic_t write_failures; /* count of failed WRITE commands */ @@ -771,73 +843,75 @@ struct pmcraid_ioasc_error { * statically. */ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { - {0x01180600, IOASC_LOG_LEVEL_MUST, + {0x01180600, IOASC_LOG_LEVEL_HARD, "Recovered Error, soft media error, sector reassignment suggested"}, - {0x015D0000, IOASC_LOG_LEVEL_MUST, - "Recovered Error, failure prediction threshold exceeded"}, - {0x015D9200, IOASC_LOG_LEVEL_MUST, - "Recovered Error, soft Cache Card Battery error threshold"}, - {0x015D9200, IOASC_LOG_LEVEL_MUST, - "Recovered Error, soft Cache Card Battery error threshold"}, - {0x02048000, IOASC_LOG_LEVEL_MUST, + {0x015D0000, IOASC_LOG_LEVEL_HARD, + "Recovered Error, failure prediction thresold exceeded"}, + {0x015D9200, IOASC_LOG_LEVEL_HARD, + "Recovered Error, soft Cache Card Battery error thresold"}, + {0x015D9200, IOASC_LOG_LEVEL_HARD, + "Recovered Error, soft Cache Card Battery error thresold"}, + {0x02048000, IOASC_LOG_LEVEL_HARD, "Not Ready, IOA Reset Required"}, - {0x02408500, IOASC_LOG_LEVEL_MUST, + {0x02408500, IOASC_LOG_LEVEL_HARD, "Not Ready, IOA microcode download required"}, - {0x03110B00, IOASC_LOG_LEVEL_MUST, + {0x03110B00, IOASC_LOG_LEVEL_HARD, "Medium Error, data unreadable, reassignment suggested"}, {0x03110C00, IOASC_LOG_LEVEL_MUST, "Medium Error, data unreadable do not reassign"}, - {0x03310000, IOASC_LOG_LEVEL_MUST, + {0x03310000, IOASC_LOG_LEVEL_HARD, "Medium Error, media corrupted"}, - {0x04050000, IOASC_LOG_LEVEL_MUST, + {0x04050000, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA can't communicate with device"}, {0x04080000, IOASC_LOG_LEVEL_MUST, "Hardware Error, device bus error"}, - {0x04080000, IOASC_LOG_LEVEL_MUST, + {0x04088000, IOASC_LOG_LEVEL_MUST, "Hardware Error, device bus is not functioning"}, - {0x04118000, IOASC_LOG_LEVEL_MUST, + {0x04118000, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA reserved area data check"}, - {0x04118100, IOASC_LOG_LEVEL_MUST, + {0x04118100, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA reserved area invalid data pattern"}, - {0x04118200, IOASC_LOG_LEVEL_MUST, + {0x04118200, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA reserved area LRC error"}, - {0x04320000, IOASC_LOG_LEVEL_MUST, + {0x04320000, IOASC_LOG_LEVEL_HARD, "Hardware Error, reassignment space exhausted"}, - {0x04330000, IOASC_LOG_LEVEL_MUST, + {0x04330000, IOASC_LOG_LEVEL_HARD, "Hardware Error, data transfer underlength error"}, - {0x04330000, IOASC_LOG_LEVEL_MUST, + {0x04330000, IOASC_LOG_LEVEL_HARD, "Hardware Error, data transfer overlength error"}, {0x04418000, IOASC_LOG_LEVEL_MUST, "Hardware Error, PCI bus error"}, - {0x04440000, IOASC_LOG_LEVEL_MUST, + {0x04440000, IOASC_LOG_LEVEL_HARD, "Hardware Error, device error"}, - {0x04448300, IOASC_LOG_LEVEL_MUST, + {0x04448200, IOASC_LOG_LEVEL_MUST, + "Hardware Error, IOA error"}, + {0x04448300, IOASC_LOG_LEVEL_HARD, "Hardware Error, undefined device response"}, - {0x04448400, IOASC_LOG_LEVEL_MUST, + {0x04448400, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA microcode error"}, - {0x04448600, IOASC_LOG_LEVEL_MUST, + {0x04448600, IOASC_LOG_LEVEL_HARD, "Hardware Error, IOA reset required"}, - {0x04449200, IOASC_LOG_LEVEL_MUST, + {0x04449200, IOASC_LOG_LEVEL_HARD, "Hardware Error, hard Cache Fearuee Card Battery error"}, - {0x0444A000, IOASC_LOG_LEVEL_MUST, + {0x0444A000, IOASC_LOG_LEVEL_HARD, "Hardware Error, failed device altered"}, - {0x0444A200, IOASC_LOG_LEVEL_MUST, + {0x0444A200, IOASC_LOG_LEVEL_HARD, "Hardware Error, data check after reassignment"}, - {0x0444A300, IOASC_LOG_LEVEL_MUST, + {0x0444A300, IOASC_LOG_LEVEL_HARD, "Hardware Error, LRC error after reassignment"}, - {0x044A0000, IOASC_LOG_LEVEL_MUST, + {0x044A0000, IOASC_LOG_LEVEL_HARD, "Hardware Error, device bus error (msg/cmd phase)"}, - {0x04670400, IOASC_LOG_LEVEL_MUST, + {0x04670400, IOASC_LOG_LEVEL_HARD, "Hardware Error, new device can't be used"}, - {0x04678000, IOASC_LOG_LEVEL_MUST, + {0x04678000, IOASC_LOG_LEVEL_HARD, "Hardware Error, invalid multiadapter configuration"}, - {0x04678100, IOASC_LOG_LEVEL_MUST, + {0x04678100, IOASC_LOG_LEVEL_HARD, "Hardware Error, incorrect connection between enclosures"}, - {0x04678200, IOASC_LOG_LEVEL_MUST, + {0x04678200, IOASC_LOG_LEVEL_HARD, "Hardware Error, connections exceed IOA design limits"}, - {0x04678300, IOASC_LOG_LEVEL_MUST, + {0x04678300, IOASC_LOG_LEVEL_HARD, "Hardware Error, incorrect multipath connection"}, - {0x04679000, IOASC_LOG_LEVEL_MUST, + {0x04679000, IOASC_LOG_LEVEL_HARD, "Hardware Error, command to LUN failed"}, {0x064C8000, IOASC_LOG_LEVEL_HARD, "Unit Attention, cache exists for missing/failed device"}, @@ -845,15 +919,15 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { "Unit Attention, incompatible exposed mode device"}, {0x06670600, IOASC_LOG_LEVEL_HARD, "Unit Attention, attachment of logical unit failed"}, - {0x06678000, IOASC_LOG_LEVEL_MUST, + {0x06678000, IOASC_LOG_LEVEL_HARD, "Unit Attention, cables exceed connective design limit"}, - {0x06678300, IOASC_LOG_LEVEL_MUST, + {0x06678300, IOASC_LOG_LEVEL_HARD, "Unit Attention, incomplete multipath connection between" \ "IOA and enclosure"}, - {0x06678400, IOASC_LOG_LEVEL_MUST, + {0x06678400, IOASC_LOG_LEVEL_HARD, "Unit Attention, incomplete multipath connection between" \ "device and enclosure"}, - {0x06678500, IOASC_LOG_LEVEL_MUST, + {0x06678500, IOASC_LOG_LEVEL_HARD, "Unit Attention, incomplete multipath connection between" \ "IOA and remote IOA"}, {0x06678600, IOASC_LOG_LEVEL_HARD, @@ -863,11 +937,11 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { "function"}, {0x06698200, IOASC_LOG_LEVEL_HARD, "Unit Attention, corrupt array parity detected on device"}, - {0x066B0200, IOASC_LOG_LEVEL_MUST, + {0x066B0200, IOASC_LOG_LEVEL_HARD, "Unit Attention, array exposed"}, {0x066B8200, IOASC_LOG_LEVEL_HARD, "Unit Attention, exposed array is still protected"}, - {0x066B9200, IOASC_LOG_LEVEL_MUST, + {0x066B9200, IOASC_LOG_LEVEL_HARD, "Unit Attention, Multipath redundancy level got worse"}, {0x07270000, IOASC_LOG_LEVEL_HARD, "Data Protect, device is read/write protected by IOA"}, @@ -875,37 +949,37 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { "Data Protect, IOA doesn't support device attribute"}, {0x07278100, IOASC_LOG_LEVEL_HARD, "Data Protect, NVRAM mirroring prohibited"}, - {0x07278400, IOASC_LOG_LEVEL_MUST, + {0x07278400, IOASC_LOG_LEVEL_HARD, "Data Protect, array is short 2 or more devices"}, - {0x07278600, IOASC_LOG_LEVEL_MUST, + {0x07278600, IOASC_LOG_LEVEL_HARD, "Data Protect, exposed array is short a required device"}, - {0x07278700, IOASC_LOG_LEVEL_MUST, + {0x07278700, IOASC_LOG_LEVEL_HARD, "Data Protect, array members not at required addresses"}, - {0x07278800, IOASC_LOG_LEVEL_MUST, + {0x07278800, IOASC_LOG_LEVEL_HARD, "Data Protect, exposed mode device resource address conflict"}, - {0x07278900, IOASC_LOG_LEVEL_MUST, + {0x07278900, IOASC_LOG_LEVEL_HARD, "Data Protect, incorrect resource address of exposed mode device"}, - {0x07278A00, IOASC_LOG_LEVEL_MUST, + {0x07278A00, IOASC_LOG_LEVEL_HARD, "Data Protect, Array is missing a device and parity is out of sync"}, - {0x07278B00, IOASC_LOG_LEVEL_MUST, + {0x07278B00, IOASC_LOG_LEVEL_HARD, "Data Protect, maximum number of arrays already exist"}, {0x07278C00, IOASC_LOG_LEVEL_HARD, "Data Protect, cannot locate cache data for device"}, {0x07278D00, IOASC_LOG_LEVEL_HARD, "Data Protect, cache data exits for a changed device"}, - {0x07279100, IOASC_LOG_LEVEL_MUST, + {0x07279100, IOASC_LOG_LEVEL_HARD, "Data Protect, detection of a device requiring format"}, - {0x07279200, IOASC_LOG_LEVEL_MUST, + {0x07279200, IOASC_LOG_LEVEL_HARD, "Data Protect, IOA exceeds maximum number of devices"}, - {0x07279600, IOASC_LOG_LEVEL_MUST, + {0x07279600, IOASC_LOG_LEVEL_HARD, "Data Protect, missing array, volume set is not functional"}, - {0x07279700, IOASC_LOG_LEVEL_MUST, + {0x07279700, IOASC_LOG_LEVEL_HARD, "Data Protect, single device for a volume set"}, - {0x07279800, IOASC_LOG_LEVEL_MUST, + {0x07279800, IOASC_LOG_LEVEL_HARD, "Data Protect, missing multiple devices for a volume set"}, {0x07279900, IOASC_LOG_LEVEL_HARD, "Data Protect, maximum number of volument sets already exists"}, - {0x07279A00, IOASC_LOG_LEVEL_MUST, + {0x07279A00, IOASC_LOG_LEVEL_HARD, "Data Protect, other volume set problem"}, }; @@ -952,27 +1026,6 @@ struct pmcraid_ioctl_header { #define PMCRAID_IOCTL_SIGNATURE "PMCRAID" - -/* - * pmcraid_event_details - defines AEN details that apps can retrieve from LLD - * - * .rcb_ccn - complete RCB of CCN - * .rcb_ldn - complete RCB of CCN - */ -struct pmcraid_event_details { - struct pmcraid_hcam_ccn rcb_ccn; - struct pmcraid_hcam_ldn rcb_ldn; -}; - -/* - * pmcraid_driver_ioctl_buffer - structure passed as argument to most of the - * PMC driver handled ioctls. - */ -struct pmcraid_driver_ioctl_buffer { - struct pmcraid_ioctl_header ioctl_header; - struct pmcraid_event_details event_details; -}; - /* * pmcraid_passthrough_ioctl_buffer - structure given as argument to * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires -- cgit v1.2.3-70-g09d2 From 75baf69657ea2107f2c202cd29dada206ae4b7c4 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 8 Jun 2010 18:31:21 -0400 Subject: [SCSI] lpfc 8.3.14: PCI fixes and enhancements - Allow enabling MSI-X intterupts with fewer vectors than requested by looking at the return value from pci_enable_msix. - Implemented driver PCI AER error handling routines for supporting AER error recovering on SLI4 devices. - Remove redundant SLI_ACTIVE checks Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 22 +---- drivers/scsi/lpfc/lpfc_init.c | 195 +++++++++++++++++++++++++++++++++++++++--- drivers/scsi/lpfc/lpfc_scsi.c | 10 ++- drivers/scsi/lpfc/lpfc_sli.c | 41 +++++++-- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 5 files changed, 228 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 39b0760c438..a7c6b739055 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -864,7 +864,6 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mrpi, uint32_t *arpi, uint32_t *mvpi, uint32_t *avpi) { - struct lpfc_sli *psli = &phba->sli; struct lpfc_mbx_read_config *rd_config; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; @@ -893,8 +892,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; - if ((phba->pport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) + if (phba->pport->fc_flag & FC_OFFLINE_MODE) rc = MBX_NOT_FINISHED; else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -2943,9 +2941,6 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; int val = 0, rc = -EINVAL; - /* AER not supported on OC devices yet */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) - return -EPERM; if (!isdigit(buf[0])) return -EINVAL; if (sscanf(buf, "%i", &val) != 1) @@ -3018,12 +3013,6 @@ lpfc_param_show(aer_support) static int lpfc_aer_support_init(struct lpfc_hba *phba, int val) { - /* AER not supported on OC devices yet */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { - phba->cfg_aer_support = 0; - return -EPERM; - } - if (val == 0 || val == 1) { phba->cfg_aer_support = val; return 0; @@ -3068,9 +3057,6 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, struct lpfc_hba *phba = vport->phba; int val, rc = -1; - /* AER not supported on OC devices yet */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) - return -EPERM; if (!isdigit(buf[0])) return -EINVAL; if (sscanf(buf, "%i", &val) != 1) @@ -4099,8 +4085,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->context1 = NULL; pmboxq->vport = vport; - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) + if (vport->fc_flag & FC_OFFLINE_MODE) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); @@ -4124,8 +4109,7 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->context1 = NULL; pmboxq->vport = vport; - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) + if (vport->fc_flag & FC_OFFLINE_MODE) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 184e45f286d..08db674ec58 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7030,22 +7030,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) static int lpfc_sli4_enable_msix(struct lpfc_hba *phba) { - int rc, index; + int vectors, rc, index; /* Set up MSI-X multi-message vectors */ for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) phba->sli4_hba.msix_entries[index].entry = index; /* Configure MSI-X capability structure */ + vectors = phba->sli4_hba.cfg_eqn; +enable_msix_vectors: rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, - phba->sli4_hba.cfg_eqn); - if (rc) { + vectors); + if (rc > 1) { + vectors = rc; + goto enable_msix_vectors; + } else if (rc) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0484 PCI enable MSI-X failed (%d)\n", rc); goto msi_fail_out; } + /* Log MSI-X vector assignment */ - for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) + for (index = 0; index < vectors; index++) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0489 MSI-X entry[%d]: vector=x%x " "message=%d\n", index, @@ -7067,7 +7073,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) } /* The rest of the vector(s) are associated to fast-path handler(s) */ - for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) { + for (index = 1; index < vectors; index++) { phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; rc = request_irq(phba->sli4_hba.msix_entries[index].vector, @@ -7081,6 +7087,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) goto cfg_fail_out; } } + phba->sli4_hba.msix_vec_nr = vectors; return rc; @@ -7114,9 +7121,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba) /* Free up MSI-X multi-message vectors */ free_irq(phba->sli4_hba.msix_entries[0].vector, phba); - for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) + for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++) free_irq(phba->sli4_hba.msix_entries[index].vector, &phba->sli4_hba.fcp_eq_hdl[index - 1]); + /* Disable MSI-X */ pci_disable_msix(phba->pcidev); @@ -7158,6 +7166,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) pci_disable_msi(phba->pcidev); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0490 MSI request_irq failed (%d)\n", rc); + return rc; } for (index = 0; index < phba->cfg_fcp_eq_count; index++) { @@ -7165,7 +7174,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) phba->sli4_hba.fcp_eq_hdl[index].phba = phba; } - return rc; + return 0; } /** @@ -7876,6 +7885,9 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2710 PCI channel disable preparing for reset\n"); + /* Block any management I/Os to the device */ + lpfc_block_mgmt_io(phba); + /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); @@ -7885,6 +7897,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) /* Disable interrupt and pci device */ lpfc_sli_disable_intr(phba); pci_disable_device(phba->pcidev); + /* Flush all driver's outstanding SCSI I/Os as we are to reset */ lpfc_sli_flush_fcp_rings(phba); } @@ -7898,7 +7911,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) * pending I/Os. **/ static void -lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba) +lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2711 PCI channel permanent disable for failure\n"); @@ -7947,7 +7960,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: /* Permanent failure, prepare for device down */ - lpfc_prep_dev_for_perm_failure(phba); + lpfc_sli_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; default: /* Unknown state, prepare and request slot reset */ @@ -8016,7 +8029,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev) } else phba->intr_mode = intr_mode; - /* Take device offline; this will perform cleanup */ + /* Take device offline, it will perform cleanup */ + lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); @@ -8201,6 +8215,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Default to single FCP EQ for non-MSI-X */ if (phba->intr_type != MSIX) phba->cfg_fcp_eq_count = 1; + else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count) + phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1; /* Set up SLI-4 HBA */ if (lpfc_sli4_hba_setup(phba)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8362,7 +8378,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0298 PCI device Power Management suspend.\n"); + "2843 PCI device Power Management suspend.\n"); /* Bring down the device */ lpfc_offline_prep(phba); @@ -8452,6 +8468,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) return 0; } +/** + * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot recover. It + * aborts all the outstanding SCSI I/Os to the pci device. + **/ +static void +lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2828 PCI channel I/O abort preparing for recovery\n"); + /* + * There may be errored I/Os through HBA, abort all I/Os on txcmplq + * and let the SCSI mid-layer to retry them to recover. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); +} + +/** + * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot reset. It + * disables the device interrupt and pci device, and aborts the internal FCP + * pending I/Os. + **/ +static void +lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2826 PCI channel disable preparing for reset\n"); + + /* Block any management I/Os to the device */ + lpfc_block_mgmt_io(phba); + + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + + /* Disable interrupt and pci device */ + lpfc_sli4_disable_intr(phba); + pci_disable_device(phba->pcidev); + + /* Flush all driver's outstanding SCSI I/Os as we are to reset */ + lpfc_sli_flush_fcp_rings(phba); +} + +/** + * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI4 device for PCI slot permanently + * disabling. It blocks the SCSI transport layer traffic and flushes the FCP + * pending I/Os. + **/ +static void +lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2827 PCI channel permanent disable for failure\n"); + + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + + /* stop all timers */ + lpfc_stop_hba_timers(phba); + + /* Clean up all driver's outstanding SCSI I/Os */ + lpfc_sli_flush_fcp_rings(phba); +} + /** * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device * @pdev: pointer to PCI device. @@ -8471,7 +8565,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev) static pci_ers_result_t lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) { - return PCI_ERS_RESULT_NEED_RESET; + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + switch (state) { + case pci_channel_io_normal: + /* Non-fatal error, prepare for recovery */ + lpfc_sli4_prep_dev_for_recover(phba); + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + /* Fatal error, prepare for slot reset */ + lpfc_sli4_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + /* Permanent failure, prepare for device down */ + lpfc_sli4_prep_dev_for_perm_failure(phba); + return PCI_ERS_RESULT_DISCONNECT; + default: + /* Unknown state, prepare and request slot reset */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2825 Unknown PCI error state: x%x\n", state); + lpfc_sli4_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; + } } /** @@ -8495,6 +8611,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) static pci_ers_result_t lpfc_io_slot_reset_s4(struct pci_dev *pdev) { + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + struct lpfc_sli *psli = &phba->sli; + uint32_t intr_mode; + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_mem(pdev)) { + printk(KERN_ERR "lpfc: Cannot re-enable " + "PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_restore_state(pdev); + if (pdev->is_busmaster) + pci_set_master(pdev); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + /* Configure and enable interrupt */ + intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); + if (intr_mode == LPFC_INTR_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2824 Cannot re-enable interrupt after " + "slot reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } else + phba->intr_mode = intr_mode; + + /* Log the current active interrupt mode */ + lpfc_log_intr_mode(phba, phba->intr_mode); + return PCI_ERS_RESULT_RECOVERED; } @@ -8511,7 +8660,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev) static void lpfc_io_resume_s4(struct pci_dev *pdev) { - return; + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + /* + * In case of slot reset, as function reset is performed through + * mailbox command which needs DMA to be enabled, this operation + * has to be moved to the io resume phase. Taking device offline + * will perform the necessary cleanup. + */ + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { + /* Perform device reset */ + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + /* Bring the device back online */ + lpfc_online(phba); + } + + /* Clean up Advanced Error Reporting (AER) if needed */ + if (phba->hba_flag & HBA_AER_ENABLED) + pci_cleanup_aer_uncorrect_error_status(pdev); } /** diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c6bdf63925d..f68753ea941 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2295,15 +2295,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_vport *vport = pIocbIn->vport; struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; - struct scsi_cmnd *cmd = lpfc_cmd->pCmd; + struct scsi_cmnd *cmd; int result; struct scsi_device *tmp_sdev; int depth; unsigned long flags; struct lpfc_fast_path_event *fast_path_evt; - struct Scsi_Host *shost = cmd->device->host; + struct Scsi_Host *shost; uint32_t queue_depth, scsi_id; + /* Sanity check on return of outstanding command */ + if (!(lpfc_cmd->pCmd)) + return; + cmd = lpfc_cmd->pCmd; + shost = cmd->device->host; + lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; /* pick up SLI4 exhange busy status from HBA */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ae3cb0ab0ae..9c609546b4e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3593,13 +3593,16 @@ static int lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; - + uint32_t hba_aer_enabled; /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "0296 Restart HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); + /* Take PCIe device Advanced Error Reporting (AER) state */ + hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; + lpfc_sli4_brdreset(phba); spin_lock_irq(&phba->hbalock); @@ -3611,6 +3614,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); psli->stats_start = get_seconds(); + /* Reset HBA AER if it was enabled, note hba_flag was reset above */ + if (hba_aer_enabled) + pci_disable_pcie_error_reporting(phba->pcidev); + lpfc_hba_down_post(phba); return 0; @@ -4554,6 +4561,24 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) /* Start error attention (ERATT) polling timer */ mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + /* Enable PCIe device Advanced Error Reporting (AER) if configured */ + if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { + rc = pci_enable_pcie_error_reporting(phba->pcidev); + if (!rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2829 This device supports " + "Advanced Error Reporting (AER)\n"); + spin_lock_irq(&phba->hbalock); + phba->hba_flag |= HBA_AER_ENABLED; + spin_unlock_irq(&phba->hbalock); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2830 This device does not support " + "Advanced Error Reporting (AER)\n"); + phba->cfg_aer_support = 0; + } + } + /* * The port is ready, set the host's link state to LINK_DOWN * in preparation for link interrupts. @@ -9089,9 +9114,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) } } if (unlikely(!cq)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0365 Slow-path CQ identifier (%d) does " - "not exist\n", cqid); + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0365 Slow-path CQ identifier " + "(%d) does not exist\n", cqid); return; } @@ -9321,9 +9347,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; if (unlikely(!cq)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0367 Fast-path completion queue does not " - "exist\n"); + if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0367 Fast-path completion queue " + "does not exist\n"); return; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 1f8ec72c5dc..ccdb95774e8 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -382,6 +382,7 @@ struct lpfc_sli4_hba { struct lpfc_pc_sli4_params pc_sli4_params; struct msix_entry *msix_entries; uint32_t cfg_eqn; + uint32_t msix_vec_nr; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ /* Pointers to the constructed SLI4 queues */ struct lpfc_queue **fp_eq; /* Fast-path event queue */ -- cgit v1.2.3-70-g09d2 From dbb6b3ab10464aa11df74c0d0a14e869a8c6fd1b Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 8 Jun 2010 18:31:37 -0400 Subject: [SCSI] lpfc 8.3.14: FCoE Discovery Fixes - Prevent unregistring of unused FCF when FLOGI is pending. - Prevent point to point discovery on a FCoE HBA. - Fixed FCF discovery failure after swapping FCoE port by switching over to fast failover method when no FCF matches in-use FCF. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 38 +++++++++- drivers/scsi/lpfc/lpfc_hbadisc.c | 151 ++++++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_sli.c | 3 +- drivers/scsi/lpfc/lpfc_sli4.h | 3 + 4 files changed, 175 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f936f8c7efe..017c933d60a 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -796,7 +796,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * due to new FCF discovery */ if ((phba->hba_flag & HBA_FIP_SUPPORT) && - (phba->fcf.fcf_flag & FCF_DISCOVERY)) { + (phba->fcf.fcf_flag & FCF_DISCOVERY) && + (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2611 FLOGI failed on registered " "FCF record fcf_index:%d, trying " @@ -890,9 +892,39 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ if (sp->cmn.fPort) rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp); - else + else if (!(phba->hba_flag & HBA_FCOE_SUPPORT)) rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp); - + else { + lpfc_printf_vlog(vport, KERN_ERR, + LOG_FIP | LOG_ELS, + "2831 FLOGI response with cleared Fabric " + "bit fcf_index 0x%x " + "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x " + "Fabric Name " + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + phba->fcf.current_rec.fcf_indx, + phba->fcf.current_rec.switch_name[0], + phba->fcf.current_rec.switch_name[1], + phba->fcf.current_rec.switch_name[2], + phba->fcf.current_rec.switch_name[3], + phba->fcf.current_rec.switch_name[4], + phba->fcf.current_rec.switch_name[5], + phba->fcf.current_rec.switch_name[6], + phba->fcf.current_rec.switch_name[7], + phba->fcf.current_rec.fabric_name[0], + phba->fcf.current_rec.fabric_name[1], + phba->fcf.current_rec.fabric_name[2], + phba->fcf.current_rec.fabric_name[3], + phba->fcf.current_rec.fabric_name[4], + phba->fcf.current_rec.fabric_name[5], + phba->fcf.current_rec.fabric_name[6], + phba->fcf.current_rec.fabric_name[7]); + lpfc_nlp_put(ndlp); + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_DISCOVERY; + spin_unlock_irq(&phba->hbalock); + goto out; + } if (!rc) { /* Mark the FCF discovery process done */ if (phba->hba_flag & HBA_FIP_SUPPORT) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index d1c5c52b1c2..7cd5c47a66e 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1300,7 +1300,7 @@ lpfc_register_fcf(struct lpfc_hba *phba) * used for this FCF when the function returns. * If the FCF record need to be used with a particular vlan id, the vlan is * set in the vlan_id on return of the function. If not VLAN tagging need to - * be used with the FCF vlan_id will be set to 0xFFFF; + * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID; **/ static int lpfc_match_fcf_conn_list(struct lpfc_hba *phba, @@ -1336,7 +1336,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, if (phba->valid_vlan) *vlan_id = phba->vlan_id; else - *vlan_id = 0xFFFF; + *vlan_id = LPFC_FCOE_NULL_VID; return 1; } @@ -1360,7 +1360,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, if (fcf_vlan_id) *vlan_id = fcf_vlan_id; else - *vlan_id = 0xFFFF; + *vlan_id = LPFC_FCOE_NULL_VID; return 1; } @@ -1469,7 +1469,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, else if (fcf_vlan_id) *vlan_id = fcf_vlan_id; else - *vlan_id = 0xFFFF; + *vlan_id = LPFC_FCOE_NULL_VID; return 1; } @@ -1521,6 +1521,9 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS * flag */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, + "2833 Stop FCF discovery process due to link " + "state change (x%x)\n", phba->link_state); spin_lock_irq(&phba->hbalock); phba->hba_flag &= ~FCF_DISC_INPROGRESS; phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY); @@ -1695,6 +1698,37 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, next_fcf_index); } +/** + lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF + * @phba: pointer to lpfc hba data structure. + * @fcf_rec: pointer to an existing FCF record. + * @new_fcf_record: pointer to a new FCF record. + * @new_vlan_id: vlan id from the new FCF record. + * + * This function performs matching test of a new FCF record against an existing + * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id + * will not be used as part of the FCF record matching criteria. + * + * Returns true if all the fields matching, otherwise returns false. + */ +static bool +lpfc_sli4_fcf_record_match(struct lpfc_hba *phba, + struct lpfc_fcf_rec *fcf_rec, + struct fcf_record *new_fcf_record, + uint16_t new_vlan_id) +{ + if (new_vlan_id != LPFC_FCOE_IGNORE_VID) + if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id)) + return false; + if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record)) + return false; + if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record)) + return false; + if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record)) + return false; + return true; +} + /** * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler. * @phba: pointer to lpfc hba data structure. @@ -1758,7 +1792,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) */ if (!rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2781 FCF record fcf_index:x%x failed FCF " + "2781 FCF record (x%x) failed FCF " "connection list check, fcf_avail:x%x, " "fcf_valid:x%x\n", bf_get(lpfc_fcf_record_fcf_index, @@ -1767,6 +1801,32 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) new_fcf_record), bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)); + if ((phba->fcf.fcf_flag & FCF_IN_USE) && + lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, + new_fcf_record, LPFC_FCOE_IGNORE_VID)) { + /* + * In case the current in-use FCF record becomes + * invalid/unavailable during FCF discovery that + * was not triggered by fast FCF failover process, + * treat it as fast FCF failover. + */ + if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) && + !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2835 Invalid in-use FCF " + "record (x%x) reported, " + "entering fast FCF failover " + "mode scanning.\n", + phba->fcf.current_rec.fcf_indx); + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag |= FCF_REDISC_FOV; + spin_unlock_irq(&phba->hbalock); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + lpfc_sli4_fcf_scan_read_fcf_rec(phba, + LPFC_FCOE_FCF_GET_FIRST); + return; + } + } goto read_next_fcf; } else { fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); @@ -1783,14 +1843,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) */ spin_lock_irq(&phba->hbalock); if (phba->fcf.fcf_flag & FCF_IN_USE) { - if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name, - new_fcf_record) && - lpfc_sw_name_match(phba->fcf.current_rec.switch_name, - new_fcf_record) && - lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr, - new_fcf_record) && - lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id, - vlan_id)) { + if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, + new_fcf_record, vlan_id)) { phba->fcf.fcf_flag |= FCF_AVAILABLE; if (phba->fcf.fcf_flag & FCF_REDISC_PEND) /* Stop FCF redisc wait timer if pending */ @@ -1800,6 +1854,13 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY); spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2836 The new FCF record (x%x) " + "matches the in-use FCF record " + "(x%x)\n", + phba->fcf.current_rec.fcf_indx, + bf_get(lpfc_fcf_record_fcf_index, + new_fcf_record)); goto out; } /* @@ -1831,6 +1892,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) */ if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) { /* Choose this FCF record */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2837 Update current FCF record " + "(x%x) with new FCF record (x%x)\n", + fcf_rec->fcf_indx, + bf_get(lpfc_fcf_record_fcf_index, + new_fcf_record)); __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, addr_mode, vlan_id, BOOT_ENABLE); spin_unlock_irq(&phba->hbalock); @@ -1851,6 +1918,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) */ if (new_fcf_record->fip_priority < fcf_rec->priority) { /* Choose the new FCF record with lower priority */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2838 Update current FCF record " + "(x%x) with new FCF record (x%x)\n", + fcf_rec->fcf_indx, + bf_get(lpfc_fcf_record_fcf_index, + new_fcf_record)); __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, addr_mode, vlan_id, 0); /* Reset running random FCF selection count */ @@ -1860,11 +1933,18 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) phba->fcf.eligible_fcf_cnt++; select_new_fcf = lpfc_sli4_new_fcf_random_select(phba, phba->fcf.eligible_fcf_cnt); - if (select_new_fcf) + if (select_new_fcf) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2839 Update current FCF record " + "(x%x) with new FCF record (x%x)\n", + fcf_rec->fcf_indx, + bf_get(lpfc_fcf_record_fcf_index, + new_fcf_record)); /* Choose the new FCF by random selection */ __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, addr_mode, vlan_id, 0); + } } spin_unlock_irq(&phba->hbalock); goto read_next_fcf; @@ -1874,6 +1954,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) * initial best-fit FCF. */ if (fcf_rec) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2840 Update current FCF record " + "with initial FCF record (x%x)\n", + bf_get(lpfc_fcf_record_fcf_index, + new_fcf_record)); __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, addr_mode, vlan_id, (boot_flag ? BOOT_ENABLE : 0)); @@ -1931,6 +2016,12 @@ read_next_fcf: lpfc_unregister_fcf(phba); /* Replace in-use record with the new record */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2842 Replace the current in-use " + "FCF record (x%x) with failover FCF " + "record (x%x)\n", + phba->fcf.current_rec.fcf_indx, + phba->fcf.failover_rec.fcf_indx); memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec, sizeof(struct lpfc_fcf_rec)); @@ -1954,6 +2045,28 @@ read_next_fcf: if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) || (phba->fcf.fcf_flag & FCF_REDISC_PEND)) return; + + if (phba->fcf.fcf_flag & FCF_IN_USE) { + /* + * In case the current in-use FCF record no + * longer existed during FCF discovery that + * was not triggered by fast FCF failover + * process, treat it as fast FCF failover. + */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2841 In-use FCF record (x%x) " + "not reported, entering fast " + "FCF failover mode scanning.\n", + phba->fcf.current_rec.fcf_indx); + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag |= FCF_REDISC_FOV; + spin_unlock_irq(&phba->hbalock); + lpfc_sli4_mbox_cmd_free(phba, mboxq); + lpfc_sli4_fcf_scan_read_fcf_rec(phba, + LPFC_FCOE_FCF_GET_FIRST); + return; + } + /* * Otherwise, initial scan or post linkdown rescan, * register with the best FCF record found so far @@ -2036,6 +2149,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) next_fcf_index); /* Upload new FCF record to the failover FCF record */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2834 Update the current FCF record (x%x) " + "with the next FCF record (x%x)\n", + phba->fcf.failover_rec.fcf_indx, + bf_get(lpfc_fcf_record_fcf_index, new_fcf_record)); spin_lock_irq(&phba->hbalock); __lpfc_update_fcf_record(phba, &phba->fcf.failover_rec, new_fcf_record, addr_mode, vlan_id, @@ -2053,7 +2171,7 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_printf_log(phba, KERN_INFO, LOG_FIP, "2783 FLOGI round robin FCF failover from FCF " - "(index:x%x) to FCF (index:x%x).\n", + "(x%x) to FCF (x%x).\n", current_fcf_index, bf_get(lpfc_fcf_record_fcf_index, new_fcf_record)); @@ -5217,7 +5335,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); if (!(phba->hba_flag & HBA_FCOE_SUPPORT) || !(phba->fcf.fcf_flag & FCF_REGISTERED) || - !(phba->hba_flag & HBA_FIP_SUPPORT)) { + !(phba->hba_flag & HBA_FIP_SUPPORT) || + (phba->pport->port_state == LPFC_FLOGI)) { spin_unlock_irq(&phba->hbalock); return; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9c609546b4e..f38c05dc563 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -12404,7 +12404,8 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, LPFC_SLI4_FCF_TBL_INDX_MAX, 0); /* Round robin failover stop condition */ - if (next_fcf_index == phba->fcf.fcf_rr_init_indx) + if ((next_fcf_index == phba->fcf.fcf_rr_init_indx) || + (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)) return LPFC_FCOE_FCF_NEXT_NONE; return next_fcf_index; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index ccdb95774e8..7686c1a9a63 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -51,6 +51,9 @@ #define LPFC_FCOE_FCF_GET_FIRST 0xFFFF #define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF +#define LPFC_FCOE_NULL_VID 0xFFF +#define LPFC_FCOE_IGNORE_VID 0xFFFF + /* First 3 bytes of default FCF MAC is specified by FC_MAP */ #define LPFC_FCOE_FCF_MAC3 0xFF #define LPFC_FCOE_FCF_MAC4 0xFF -- cgit v1.2.3-70-g09d2 From d7c479929b6804f4e9d5fb5f721aba31622f3d97 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 8 Jun 2010 18:31:54 -0400 Subject: [SCSI] lpfc 8.3.14: SCSI and SLI API fixes - Fixed accounting of allocated SCSI buffers when post sgl fails. - Restrict scsi buffer allocation based on LUN count (sdev_cnt). - Create __lpfc_sli_free_rpi that doesn't take out the hbalock. - Modify lpfc_sli_free_rpi to call __lpfc_sli_free_rpi. - Call __lpfc_sli_free_rpi in lpfc_cleanup_pending_mbox. - Do not swap the strings returned in mailbox commands and do not swap byte aligned data in VPD. Signed-off-by: Alex Iannicelli 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 | 1 + drivers/scsi/lpfc/lpfc_init.c | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 20 ++++++++++++++++++++ drivers/scsi/lpfc/lpfc_scsi.c | 14 ++++++++++---- drivers/scsi/lpfc/lpfc_sli.c | 34 +++++++++++++++++++++++++++------- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 8 files changed, 62 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index fcfc495d1e0..bb40fcbe17c 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -815,6 +815,7 @@ struct lpfc_hba { #define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */ uint32_t iocb_cnt; uint32_t iocb_max; + atomic_t sdev_cnt; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 361f4e7e23e..03f4ddc1857 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -191,6 +191,7 @@ irqreturn_t lpfc_sli4_sp_intr_handler(int, void *); irqreturn_t lpfc_sli4_fp_intr_handler(int, void *); void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_sli4_swap_str(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 *); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7cd5c47a66e..9fcad20491e 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3845,6 +3845,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mempool_free(mbox, phba->mbox_mem_pool); } lpfc_no_rpi(phba, ndlp); + ndlp->nlp_rpi = 0; ndlp->nlp_flag &= ~NLP_RPI_VALID; ndlp->nlp_flag &= ~NLP_NPR_ADISC; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 08db674ec58..fb06933f8e6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4919,6 +4919,7 @@ lpfc_create_shost(struct lpfc_hba *phba) phba->fc_altov = FF_DEF_ALTOV; phba->fc_arbtov = FF_DEF_ARBTOV; + atomic_set(&phba->sdev_cnt, 0); vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); if (!vport) return -ENODEV; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 196371fae24..cb5d93b41b5 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -955,6 +955,26 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) return; } +void +lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + MAILBOX_t *mb = &pmb->u.mb; + struct lpfc_mqe *mqe; + + switch (mb->mbxCommand) { + case MBX_READ_REV: + mqe = &pmb->u.mqe; + lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name, + mqe->un.read_rev.fw_name, 16); + lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name, + mqe->un.read_rev.ulp_fw_name, 16); + break; + default: + break; + } + return; +} + /** * lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2 * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f68753ea941..7b66b71a14f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -747,7 +747,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) int status = 0, index; int bcnt; int non_sequential_xri = 0; - int rc = 0; LIST_HEAD(sblist); for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { @@ -860,7 +859,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) if (status) { /* Put this back on the abort scsi list */ psb->exch_busy = 1; - rc++; } else { psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; @@ -879,7 +877,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) if (status) { /* Put this back on the abort scsi list */ psb->exch_busy = 1; - rc++; } else { psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; @@ -889,7 +886,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) } } - return bcnt + non_sequential_xri - rc; + return bcnt + non_sequential_xri; } /** @@ -3572,11 +3569,13 @@ lpfc_slave_alloc(struct scsi_device *sdev) uint32_t total = 0; uint32_t num_to_alloc = 0; int num_allocated = 0; + uint32_t sdev_cnt; if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; sdev->hostdata = rport->dd_data; + sdev_cnt = atomic_inc_return(&phba->sdev_cnt); /* * Populate the cmds_per_lun count scsi_bufs into this host's globally @@ -3588,6 +3587,10 @@ lpfc_slave_alloc(struct scsi_device *sdev) total = phba->total_scsi_bufs; num_to_alloc = vport->cfg_lun_queue_depth + 2; + /* If allocated buffers are enough do nothing */ + if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total) + return 0; + /* Allow some exchanges to be available always to complete discovery */ if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, @@ -3669,6 +3672,9 @@ lpfc_slave_configure(struct scsi_device *sdev) static void lpfc_slave_destroy(struct scsi_device *sdev) { + struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; + struct lpfc_hba *phba = vport->phba; + atomic_dec(&phba->sdev_cnt); sdev->hostdata = NULL; return; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f38c05dc563..7ddf5268227 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -4236,7 +4236,8 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (mqe->un.read_rev.avail_vpd_len < *vpd_size) *vpd_size = mqe->un.read_rev.avail_vpd_len; - lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size); + memcpy(vpd, dmabuf->virt, *vpd_size); + dma_free_coherent(&phba->pcidev->dev, dma_size, dmabuf->virt, dmabuf->phys); kfree(dmabuf); @@ -5305,7 +5306,8 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) if (mcqe_status != MB_CQE_STATUS_SUCCESS) { bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status); rc = MBXERR_ERROR; - } + } else + lpfc_sli4_swap_str(phba, mboxq); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0356 Mailbox cmd x%x (x%x) Status x%x " @@ -7790,9 +7792,10 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, * if LPFC_MBX_WAKE flag is set the mailbox is completed * else do not free the resources. */ - if (pmboxq->mbox_flag & LPFC_MBX_WAKE) + if (pmboxq->mbox_flag & LPFC_MBX_WAKE) { retval = MBX_SUCCESS; - else { + lpfc_sli4_swap_str(phba, pmboxq); + } else { retval = MBX_TIMEOUT; pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } @@ -11967,6 +11970,22 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) return rpi; } +/** + * lpfc_sli4_free_rpi - Release an rpi for reuse. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release an rpi to the pool of + * available rpis maintained by the driver. + **/ +void +__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) +{ + if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) { + phba->sli4_hba.rpi_count--; + phba->sli4_hba.max_cfg_param.rpi_used--; + } +} + /** * lpfc_sli4_free_rpi - Release an rpi for reuse. * @phba: pointer to lpfc hba data structure. @@ -11978,9 +11997,7 @@ void lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) { spin_lock_irq(&phba->hbalock); - clear_bit(rpi, phba->sli4_hba.rpi_bmask); - phba->sli4_hba.rpi_count--; - phba->sli4_hba.max_cfg_param.rpi_used--; + __lpfc_sli4_free_rpi(phba, rpi); spin_unlock_irq(&phba->hbalock); } @@ -12751,6 +12768,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) continue; if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { + if (phba->sli_rev == LPFC_SLI_REV4) + __lpfc_sli4_free_rpi(phba, + mb->u.mb.un.varRegLogin.rpi); mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { __lpfc_mbuf_free(phba, mp->virt, mp->phys); diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 7686c1a9a63..c916079fbb3 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -528,6 +528,7 @@ int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *); struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *); void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *); int lpfc_sli4_alloc_rpi(struct lpfc_hba *); +void __lpfc_sli4_free_rpi(struct lpfc_hba *, int); void lpfc_sli4_free_rpi(struct lpfc_hba *, int); void lpfc_sli4_remove_rpis(struct lpfc_hba *); void lpfc_sli4_async_event_proc(struct lpfc_hba *); -- cgit v1.2.3-70-g09d2 From 2cae179486a356aca2a2617f0399f04c66598d8b Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 8 Jun 2010 18:32:13 -0400 Subject: [SCSI] lpfc 8.3.14: Update Driver version to 8.3.14 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index e79090df228..33d9d8db4d3 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.13" +#define LPFC_DRIVER_VERSION "8.3.14" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v1.2.3-70-g09d2 From fa95d206e4a4fb549bdb9fe71091417f4912178f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 9 Jun 2010 03:30:08 -0500 Subject: [SCSI] be2iscsi: fix disconnection cleanup This patch fixes 4 bugs in the connection connect/disconnect cleanup path. 1. If beiscsi_open_conn fails beiscsi_free_ep was always being called, and if beiscsi_open_conn failed because beiscsi_get_cid failed then we would free an unallocated cid. 2. If beiscsi_ep_connect failed due to a beiscsi_open_conn failure it was leaking iscsi_endpoints. 3. beiscsi_ep_disconnect was leaking iscsi_endpoints. beiscsi_ep_disconnect should free the iscsi_endpoint. We cannot do it in beiscsi_conn_stop because that is only called for iscsi connection cleanup. If beiscsi_ep_connect returns success, but then the poll function fails or the connect times out then beiscsi_ep_disconnect will be called to clean up the ep. The conn_stop callout will not be called in that path. 4. beiscsi_conn_stop was freeing the iscsi_endpoint then accessing it a couple lines later. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 123 +++++++++++++++++---------------------- drivers/scsi/be2iscsi/be_iscsi.h | 2 - drivers/scsi/be2iscsi/be_main.c | 2 +- 3 files changed, 56 insertions(+), 71 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index c3928cb8b04..454027ccbf1 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -441,6 +441,31 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba) return cid; } +/** + * beiscsi_put_cid - Free the cid + * @phba: The phba for which the cid is being freed + * @cid: The cid to free + */ +static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) +{ + phba->avlbl_cids++; + phba->cid_array[phba->cid_free++] = cid; + if (phba->cid_free == phba->params.cxns_per_ctrl) + phba->cid_free = 0; +} + +/** + * beiscsi_free_ep - free endpoint + * @ep: pointer to iscsi endpoint structure + */ +static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) +{ + struct beiscsi_hba *phba = beiscsi_ep->phba; + + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + beiscsi_ep->phba = NULL; +} + /** * beiscsi_open_conn - Ask FW to open a TCP connection * @ep: endpoint to be used @@ -475,7 +500,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); - return ret; + goto free_ep; } beiscsi_ep->cid_vld = 0; @@ -493,10 +518,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; if (status || extd_status) { SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" - " status = %d extd_status = %d \n", + " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); - return -1; + goto free_ep; } else { wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); @@ -508,31 +533,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); } return 0; -} - -/** - * beiscsi_put_cid - Free the cid - * @phba: The phba for which the cid is being freed - * @cid: The cid to free - */ -static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) -{ - phba->avlbl_cids++; - phba->cid_array[phba->cid_free++] = cid; - if (phba->cid_free == phba->params.cxns_per_ctrl) - phba->cid_free = 0; -} - -/** - * beiscsi_free_ep - free endpoint - * @ep: pointer to iscsi endpoint structure - */ -static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) -{ - struct beiscsi_hba *phba = beiscsi_ep->phba; - beiscsi_put_cid(phba, beiscsi_ep->ep_cid); - beiscsi_ep->phba = NULL; +free_ep: + beiscsi_free_ep(beiscsi_ep); + return -1; } /** @@ -585,7 +589,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, return ep; free_ep: - beiscsi_free_ep(beiscsi_ep); + iscsi_destroy_endpoint(ep); return ERR_PTR(ret); } @@ -631,30 +635,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) return ret; } -/** - * beiscsi_ep_disconnect - Tears down the TCP connection - * @ep: endpoint to be used - * - * Tears down the TCP connection - */ -void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) -{ - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_endpoint *beiscsi_ep; - struct beiscsi_hba *phba; - - beiscsi_ep = ep->dd_data; - phba = beiscsi_ep->phba; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", - beiscsi_ep->ep_cid); - - if (beiscsi_ep->conn) { - beiscsi_conn = beiscsi_ep->conn; - iscsi_suspend_queue(beiscsi_conn->conn); - } - -} - /** * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table * @phba: The phba instance @@ -673,28 +653,35 @@ static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, } /** - * beiscsi_conn_stop - Invalidate and stop the connection - * @cls_conn: pointer to get iscsi_conn - * @flag: The type of connection closure + * beiscsi_ep_disconnect - Tears down the TCP connection + * @ep: endpoint to be used + * + * Tears down the TCP connection */ -void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) { - struct iscsi_conn *conn = cls_conn->dd_data; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; + struct beiscsi_conn *beiscsi_conn; struct beiscsi_endpoint *beiscsi_ep; - struct iscsi_session *session = conn->session; - struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); - struct beiscsi_hba *phba = iscsi_host_priv(shost); + struct beiscsi_hba *phba; unsigned int tag; unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; - beiscsi_ep = beiscsi_conn->ep; - if (!beiscsi_ep) { - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n"); + beiscsi_ep = ep->dd_data; + phba = beiscsi_ep->phba; + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", + beiscsi_ep->ep_cid); + + if (!beiscsi_ep->conn) { + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no " + "beiscsi_ep\n"); return; } - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n", - beiscsi_ep->ep_cid); + beiscsi_conn = beiscsi_ep->conn; + iscsi_suspend_queue(beiscsi_conn->conn); + + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n", + beiscsi_ep->ep_cid); + tag = mgmt_invalidate_connection(phba, beiscsi_ep, beiscsi_ep->ep_cid, 1, savecfg_flag); @@ -707,9 +694,9 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } + beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); beiscsi_free_ep(beiscsi_ep); - iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); - iscsi_conn_stop(cls_conn, flag); + iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); } diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h index 1f512c28cbf..870cdb2a73e 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.h +++ b/drivers/scsi/be2iscsi/be_iscsi.h @@ -59,8 +59,6 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn); -void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag); - struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index dd5b105f8f4..854414551bb 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3955,7 +3955,7 @@ struct iscsi_transport beiscsi_iscsi_transport = { .get_session_param = iscsi_session_get_param, .get_host_param = beiscsi_get_host_param, .start_conn = beiscsi_conn_start, - .stop_conn = beiscsi_conn_stop, + .stop_conn = iscsi_conn_stop, .send_pdu = iscsi_conn_send_pdu, .xmit_task = beiscsi_task_xmit, .cleanup_task = beiscsi_cleanup_task, -- cgit v1.2.3-70-g09d2 From c5f10187965f93ef7ef67da9c7c449b13b6dee1b Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Wed, 9 Jun 2010 08:24:55 -0700 Subject: [SCSI] ipr: add writeq definition if needed Compiling the driver will fail on 32 bit powerpc and other architectures where writeq is not defined. This patch adds a definition for writeq. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index ea391ffc871..0ef9a67112a 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1860,4 +1860,12 @@ static inline int ipr_sdt_is_fmt2(u32 sdt_word) return 0; } +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel(((u32) (val >> 32)), addr); + writel(((u32) (val)), (addr + 4)); +} #endif + +#endif /* _IPR_H */ -- cgit v1.2.3-70-g09d2 From 1462b8ffd9a9e4798d4e0f9eaadbd1ac0373a11b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 10 Jun 2010 09:52:21 +0200 Subject: [SCSI] be2iscsi: fix memory leak on error path I added a kfree(pwrb_arr) in front of the return. Signed-off-by: Dan Carpenter Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 854414551bb..353a90b3574 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2750,6 +2750,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba, if (status != 0) { shost_printk(KERN_ERR, phba->shost, "wrbq create failed."); + kfree(pwrb_arr); return status; } phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i]. -- cgit v1.2.3-70-g09d2 From 82284c09c5dc5c5a5046f3c852f2683dab60109c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 10 Jun 2010 09:53:05 +0200 Subject: [SCSI] be2iscsi: fix null dereference on error path "phba" is always null here so we can't dereference it. Signed-off-by: Dan Carpenter Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 353a90b3574..0d35bf6c6ac 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3774,8 +3774,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, ret = beiscsi_enable_pci(pcidev); if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed to enable pci device \n"); + dev_err(&pcidev->dev, "beiscsi_dev_probe-" + " Failed to enable pci device\n"); return ret; } -- cgit v1.2.3-70-g09d2 From 56115598c571cadd4b465836e1423a452a908c89 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 10 Jun 2010 14:46:34 -0700 Subject: [SCSI] ipr: move setting of the allow_restart flag for vsets and disks A problem was found where the call to scsi_add_device() fails intermittently for an adapter. This is caused when __scsi_add_device() returns -ENODEV as a result of not calling scsi_probe_and_add_lun() since the call to scsi_host_scan_allowed() fails. scsi_host_scan_allowed() fails because the adapter state is set to SHOST_RECOVERY instead of SHOST_RUNNING. The state of the adapter is being set to SHOST_RECOVERY by scsi_eh_scmd_add() during error handling. This problem is avoided by moving the setting of the allow_restart flag to later in the device initialization sequence. This prevents further error handling if we get a NOT_READY response from a TUR command by causing scsi_check_sense() to return SUCCESS. Therefore, scsi_eh_scmd_add() will not run and the adapter state will remain as SHOST_RUNNING. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 62bbe31dd47..37158eab3c8 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4353,8 +4353,6 @@ static int ipr_slave_configure(struct scsi_device *sdev) IPR_VSET_RW_TIMEOUT); blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); } - if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) - sdev->allow_restart = 1; if (ipr_is_gata(res) && res->sata_port) ap = res->sata_port->ap; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); @@ -6771,7 +6769,8 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) list_move_tail(&res->queue, &ioa_cfg->used_res_q); ipr_init_res_entry(res, &cfgtew); res->add_to_ml = 1; - } + } else if (res->sdev && (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))) + res->sdev->allow_restart = 1; if (found) ipr_update_res_entry(res, &cfgtew); -- cgit v1.2.3-70-g09d2 From 281ae642a6475ede25ff86ec124214e346c25e22 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:43:33 -0700 Subject: [SCSI] libfcoe: FIP link keep-alive should continue while logged off A check in fcoe_ctlr_send_keep_alive() returns if there's no port_id for the local port. This could miss a keep alive if we just did a host reset and have logged off and will log back in. Return only if we are doing the port keep alive, in which case we need to be logged in. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 50aaa4bcfc5..cc5e8864b80 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -343,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, fcf = fip->sel_fcf; lp = fip->lp; - if (!fcf || !lp->port_id) + if (!fcf || (ports && !lp->port_id)) return; len = sizeof(*kal) + ports * sizeof(*vn); -- cgit v1.2.3-70-g09d2 From 1508f3ecd991ecbf272e08f5ee70d2618f49159e Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:43:38 -0700 Subject: [SCSI] libfcoe: Avoid hang when receiving non-critical descriptors Avoid infinite loop while processing FIP ELS or discovery advertisement with non-critical descriptors. Signed-off-by: Bhanu Prakash Gollapudi Acked-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index cc5e8864b80..66120f135d9 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -703,7 +703,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, /* standard says ignore unknown descriptors >= 128 */ if (desc->fip_dtype < FIP_DT_VENDOR_BASE) return -EINVAL; - continue; + break; } desc = (struct fip_desc *)((char *)desc + dlen); rlen -= dlen; @@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) /* standard says ignore unknown descriptors >= 128 */ if (desc->fip_dtype < FIP_DT_VENDOR_BASE) goto drop; - continue; + break; } desc = (struct fip_desc *)((char *)desc + dlen); rlen -= dlen; -- cgit v1.2.3-70-g09d2 From 516a648631c912e84e0035590f98eef1d716f4ea Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:43:44 -0700 Subject: [SCSI] libfcoe: No solicitation if adv is dropped Host does not send discovery solicitation messages if Disc. Adv from FCF are dropped. It restarts sending solicitation only after receiving a Discovery Adv. from FCF. Fix is to restart solicitation immediately after CVL processing. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 66120f135d9..1d5b949d4fd 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -1232,8 +1232,11 @@ static void fcoe_ctlr_timer_work(struct work_struct *work) fip->reset_req = 0; spin_unlock_bh(&fip->lock); - if (reset) + if (reset) { fc_lport_reset(fip->lp); + /* restart things with a solicitation */ + fcoe_ctlr_solicit(fip, NULL); + } if (fip->send_ctlr_ka) { fip->send_ctlr_ka = 0; -- cgit v1.2.3-70-g09d2 From 292e40b956982601dfc61fe8f0470eb18a616d7e Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:43:49 -0700 Subject: [SCSI] libfc: Retry a rejected PRLI request Retry upto max_rport_retry_count when a target responds with LS_RJT for a PRLI request. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 39e440f0f54..3ee497a0516 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -739,7 +739,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, } else { FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); - fc_rport_enter_delete(rdata, RPORT_EV_FAILED); + fc_rport_error_retry(rdata, fp); } out: -- cgit v1.2.3-70-g09d2 From 618461c02b00a658ec8aa07d409cd496a7e254e2 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:43:54 -0700 Subject: [SCSI] libfc: Honor LS_ACC response codes for PRLI As per FC-LS Rev 1.62 table 46, response codes are handled as follows: 1. If the Req executed is true, PRLI is accepted. 2. If Req executed is not set, if resp code is 5, PRLI is not retried and port is logged out. 3. If resp code is anything apart from 1 or 5, PRLI is retired upto max retry count. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 3ee497a0516..e33c5c7961a 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -698,6 +698,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, u32 roles = FC_RPORT_ROLE_UNKNOWN; u32 fcp_parm = 0; u8 op; + u8 resp_code = 0; mutex_lock(&rdata->rp_mutex); @@ -722,11 +723,25 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, op = fc_frame_payload_op(fp); if (op == ELS_LS_ACC) { pp = fc_frame_payload_get(fp, sizeof(*pp)); - if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) { - fcp_parm = ntohl(pp->spp.spp_params); - if (fcp_parm & FCP_SPPF_RETRY) - rdata->flags |= FC_RP_FLAGS_RETRY; + if (!pp) + goto out; + + resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); + FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n", + pp->spp.spp_flags); + if (resp_code != FC_SPP_RESP_ACK) { + if (resp_code == FC_SPP_RESP_CONF) + fc_rport_error(rdata, fp); + else + fc_rport_error_retry(rdata, fp); + goto out; } + if (pp->prli.prli_spp_len < sizeof(pp->spp)) + goto out; + + fcp_parm = ntohl(pp->spp.spp_params); + if (fcp_parm & FCP_SPPF_RETRY) + rdata->flags |= FC_RP_FLAGS_RETRY; rdata->supported_classes = FC_COS_CLASS3; if (fcp_parm & FCP_SPPF_INIT_FCN) -- cgit v1.2.3-70-g09d2 From 5d4a2e29fba5b2bef95b96a46b338ec4d76fa4fd Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:43:59 -0700 Subject: [SCSI] fcoe: clean up TBD comments in FCoE prototype header Some old comments in fc_fcoe.h say TBD long after the standard has been passed by T11. Clean them up. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- include/scsi/fc/fc_fcoe.h | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/include/scsi/fc/fc_fcoe.h b/include/scsi/fc/fc_fcoe.h index e6ad3d2ae47..d5dcd606281 100644 --- a/include/scsi/fc/fc_fcoe.h +++ b/include/scsi/fc/fc_fcoe.h @@ -22,23 +22,18 @@ /* * FCoE - Fibre Channel over Ethernet. + * See T11 FC-BB-5 Rev 2.00 (09-056v5.pdf) */ /* - * FC_FCOE_OUI hasn't been standardized yet. XXX TBD. + * Default FC_FCOE_OUI / FC-MAP value. */ -#ifndef FC_FCOE_OUI -#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE dest MAC TBD */ -#endif +#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE MAC */ /* - * The destination MAC address for the fabric login may get a different OUI. - * This isn't standardized yet. + * Fabric Login (FLOGI) MAC for non-FIP use. Non-FIP use is deprecated. */ -#ifndef FC_FCOE_FLOGI_MAC -/* gateway MAC - TBD */ #define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe } -#endif #define FC_FCOE_VER 0 /* version */ @@ -51,8 +46,6 @@ /* * FCoE frame header - 14 bytes - * - * This is the August 2007 version of the FCoE header as defined by T11. * This follows the VLAN header, which includes the ethertype. */ struct fcoe_hdr { -- cgit v1.2.3-70-g09d2 From f8fc6c2c99b8085368119d6cf39b997255052826 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:44:04 -0700 Subject: [SCSI] libfc: Handle unsolicited PRLO request Resubmitting after incorporating Joe's review comment. Unsolicited PRLO request is now handled by sending LS_ACC, and then relogin to the remote port if an N-port login session exists for that remote port. Note that this patch should be applied on top of Joe Eykholt's "Fix remote port restart problem" patch. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 71 ++++++++++++++++++++++++++++++++++++++----- include/scsi/fc/fc_els.h | 9 ++++++ 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index e33c5c7961a..df85e19079f 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -1573,30 +1573,85 @@ drop: * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests * @rdata: The remote port that sent the PRLO request * @sp: The sequence that the PRLO was on - * @fp: The PRLO request frame + * @rx_fp: The PRLO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, struct fc_seq *sp, - struct fc_frame *fp) + struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; - struct fc_frame_header *fh; + struct fc_exch *ep; + struct fc_frame *fp; + struct { + struct fc_els_prlo prlo; + struct fc_els_spp spp; + } *pp; + struct fc_els_spp *rspp; /* request service param page */ + struct fc_els_spp *spp; /* response spp */ + unsigned int len; + unsigned int plen; + u32 f_ctl; struct fc_seq_els_data rjt_data; - fh = fc_frame_header_get(fp); + rjt_data.fp = NULL; + fh = fc_frame_header_get(rx_fp); FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", fc_rport_state(rdata)); - rjt_data.fp = NULL; - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_NONE; + len = fr_len(rx_fp) - sizeof(*fh); + pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); + if (!pp) + goto reject_len; + plen = ntohs(pp->prlo.prlo_len); + if (plen != 20) + goto reject_len; + if (plen < len) + len = plen; + + rspp = &pp->spp; + + fp = fc_frame_alloc(lport, len); + if (!fp) { + rjt_data.reason = ELS_RJT_UNAB; + rjt_data.explan = ELS_EXPL_INSUF_RES; + goto reject; + } + + sp = lport->tt.seq_start_next(sp); + WARN_ON(!sp); + pp = fc_frame_payload_get(fp, len); + WARN_ON(!pp); + memset(pp, 0, len); + pp->prlo.prlo_cmd = ELS_LS_ACC; + pp->prlo.prlo_obs = 0x10; + pp->prlo.prlo_len = htons(len); + spp = &pp->spp; + spp->spp_type = rspp->spp_type; + spp->spp_type_ext = rspp->spp_type_ext; + spp->spp_flags = FC_SPP_RESP_ACK; + + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); + + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; + f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; + ep = fc_seq_exch(sp); + fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, + FC_TYPE_ELS, f_ctl, 0); + lport->tt.seq_send(lport, sp, fp); + goto drop; + +reject_len: + rjt_data.reason = ELS_RJT_PROT; + rjt_data.explan = ELS_EXPL_INV_LEN; +reject: lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); +drop: + fc_frame_free(rx_fp); } /** diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h index f94328132a2..70a7e92a766 100644 --- a/include/scsi/fc/fc_els.h +++ b/include/scsi/fc/fc_els.h @@ -404,6 +404,15 @@ struct fc_els_prli { /* service parameter pages follow */ }; +/* + * ELS_PRLO - Process logout request and response. + */ +struct fc_els_prlo { + __u8 prlo_cmd; /* command */ + __u8 prlo_obs; /* obsolete, but shall be set to 10h */ + __be16 prlo_len; /* payload length */ +}; + /* * ELS_ADISC payload */ -- cgit v1.2.3-70-g09d2 From 8690cb8359d8e9f8d7ca12791ef7ea32b709df8b Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:44:10 -0700 Subject: [SCSI] libfcoe: fix lenient aging of FCF advertisements [This patch has several improvements to the code in the fip timers. It hasn't been tested yet. I'm sending it out for review. Vasu, perhaps you can merge this with your patch and test it together.] The current code allows an advertisement to be used even if it has been 3 times the FCF keep-alive advertisement period (FKA) since one was received from that FCF. The spec. calls for 2.5 times FKA. Fix this and make sure we detect missed keep-alives promptly. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 76 +++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 1d5b949d4fd..3ab3db39fc5 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -557,38 +557,44 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send); * * Called with lock held and preemption disabled. * - * An FCF is considered old if we have missed three advertisements. - * That is, there have been no valid advertisement from it for three - * times its keep-alive period including fuzz. + * An FCF is considered old if we have missed two advertisements. + * That is, there have been no valid advertisement from it for 2.5 + * times its keep-alive period. * * In addition, determine the time when an FCF selection can occur. * * Also, increment the MissDiscAdvCount when no advertisement is received * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB). + * + * Returns the time in jiffies for the next call. */ -static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) +static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) { struct fcoe_fcf *fcf; struct fcoe_fcf *next; + unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); + unsigned long deadline; unsigned long sel_time = 0; - unsigned long mda_time = 0; struct fcoe_dev_stats *stats; list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - mda_time = fcf->fka_period + (fcf->fka_period >> 1); - if ((fip->sel_fcf == fcf) && - (time_after(jiffies, fcf->time + mda_time))) { - mod_timer(&fip->timer, jiffies + mda_time); - stats = per_cpu_ptr(fip->lp->dev_stats, - smp_processor_id()); - stats->MissDiscAdvCount++; - printk(KERN_INFO "libfcoe: host%d: Missing Discovery " - "Advertisement for fab %16.16llx count %lld\n", - fip->lp->host->host_no, fcf->fabric_name, - stats->MissDiscAdvCount); + deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2; + if (fip->sel_fcf == fcf) { + if (time_after(jiffies, deadline)) { + stats = per_cpu_ptr(fip->lp->dev_stats, + smp_processor_id()); + stats->MissDiscAdvCount++; + printk(KERN_INFO "libfcoe: host%d: " + "Missing Discovery Advertisement " + "for fab %16.16llx count %lld\n", + fip->lp->host->host_no, fcf->fabric_name, + stats->MissDiscAdvCount); + } else if (time_after(next_timer, deadline)) + next_timer = deadline; } - if (time_after(jiffies, fcf->time + fcf->fka_period * 3 + - msecs_to_jiffies(FIP_FCF_FUZZ * 3))) { + + deadline += fcf->fka_period; + if (time_after(jiffies, deadline)) { if (fip->sel_fcf == fcf) fip->sel_fcf = NULL; list_del(&fcf->list); @@ -598,19 +604,21 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) stats = per_cpu_ptr(fip->lp->dev_stats, smp_processor_id()); stats->VLinkFailureCount++; - } else if (fcoe_ctlr_mtu_valid(fcf) && - (!sel_time || time_before(sel_time, fcf->time))) { - sel_time = fcf->time; + } else { + if (time_after(next_timer, deadline)) + next_timer = deadline; + if (fcoe_ctlr_mtu_valid(fcf) && + (!sel_time || time_before(sel_time, fcf->time))) + sel_time = fcf->time; } } if (sel_time) { sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); fip->sel_time = sel_time; - if (time_before(sel_time, fip->timer.expires)) - mod_timer(&fip->timer, sel_time); } else { fip->sel_time = 0; } + return next_timer; } /** @@ -1148,7 +1156,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; struct fcoe_fcf *sel; struct fcoe_fcf *fcf; - unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); + unsigned long next_timer; spin_lock_bh(&fip->lock); if (fip->state == FIP_ST_DISABLED) { @@ -1157,13 +1165,16 @@ static void fcoe_ctlr_timeout(unsigned long arg) } fcf = fip->sel_fcf; - fcoe_ctlr_age_fcfs(fip); + next_timer = fcoe_ctlr_age_fcfs(fip); sel = fip->sel_fcf; - if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) { - fcoe_ctlr_select(fip); - sel = fip->sel_fcf; - fip->sel_time = 0; + if (!sel && fip->sel_time) { + if (time_after_eq(jiffies, fip->sel_time)) { + fcoe_ctlr_select(fip); + sel = fip->sel_fcf; + fip->sel_time = 0; + } else if (time_after(next_timer, fip->sel_time)) + next_timer = fip->sel_time; } if (sel != fcf) { @@ -1201,12 +1212,9 @@ static void fcoe_ctlr_timeout(unsigned long arg) } if (time_after(next_timer, fip->port_ka_time)) next_timer = fip->port_ka_time; - mod_timer(&fip->timer, next_timer); - } else if (fip->sel_time) { - next_timer = fip->sel_time + - msecs_to_jiffies(FCOE_CTLR_START_DELAY); - mod_timer(&fip->timer, next_timer); } + if (!list_empty(&fip->fcfs)) + mod_timer(&fip->timer, next_timer); if (fip->send_ctlr_ka || fip->send_port_ka) schedule_work(&fip->timer_work); spin_unlock_bh(&fip->lock); -- cgit v1.2.3-70-g09d2 From d99ee45b7cb89803b79745dc3014ba64bfd02b7d Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:44:15 -0700 Subject: [SCSI] libfcoe: Use fka_period as periodic timeouts to age out fcf if keep alives are disabled due to fd_flags set and also stop updating keep alive values in that case. Update select fcf time only if fcf is not already selected or select time is not already determined from parse adv, and then have select time cleared only once after fcf is selected. Changed deadline check to time_after_eq() from time_after() since now next timeout will be on exact 2.5 times FKA followed by first advertisement. Signed-off-by: Vasu Dev Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 3ab3db39fc5..4893098b3d3 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -594,7 +594,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) } deadline += fcf->fka_period; - if (time_after(jiffies, deadline)) { + if (time_after_eq(jiffies, deadline)) { if (fip->sel_fcf == fcf) fip->sel_fcf = NULL; list_del(&fcf->list); @@ -612,12 +612,11 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) sel_time = fcf->time; } } - if (sel_time) { + if (sel_time && !fip->sel_fcf && !fip->sel_time) { sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); fip->sel_time = sel_time; - } else { - fip->sel_time = 0; } + return next_timer; } @@ -775,7 +774,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) * ignored after a usable solicited advertisement * has been received. */ - if (fcf == fip->sel_fcf) { + if (fcf == fip->sel_fcf && !fcf->fd_flags) { fip->ctlr_ka_time -= fcf->fka_period; fip->ctlr_ka_time += new.fka_period; if (time_before(fip->ctlr_ka_time, fip->timer.expires)) @@ -813,7 +812,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) * If this is the first validated FCF, note the time and * set a timer to trigger selection. */ - if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) { + if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) { fip->sel_time = jiffies + msecs_to_jiffies(FCOE_CTLR_START_DELAY); if (!timer_pending(&fip->timer) || @@ -1187,6 +1186,8 @@ static void fcoe_ctlr_timeout(unsigned long arg) fip->port_ka_time = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); fip->ctlr_ka_time = jiffies + sel->fka_period; + if (time_after(next_timer, fip->ctlr_ka_time)) + next_timer = fip->ctlr_ka_time; } else { printk(KERN_NOTICE "libfcoe: host%d: " "FIP Fibre-Channel Forwarder timed out. " -- cgit v1.2.3-70-g09d2 From c600fea2d813e8734748202970722c3b6a76b9a1 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:44:20 -0700 Subject: [SCSI] libfcoe: update FIP FCF D flag from advertisments Allow the D flag (indicating that keep-alives are not needed) to be updated dynamically from received FIP advertisements. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 4893098b3d3..27c21ca802b 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -769,18 +769,21 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) list_add(&fcf->list, &fip->fcfs); } else { /* - * Flags in advertisements are ignored once the FCF is - * selected. Flags in unsolicited advertisements are - * ignored after a usable solicited advertisement - * has been received. + * Update the FCF's keep-alive descriptor flags. + * Other flag changes from new advertisements are + * ignored after a solicited advertisement is + * received and the FCF is selectable (usable). */ + fcf->fd_flags = new.fd_flags; + if (!fcoe_ctlr_fcf_usable(fcf)) + fcf->flags = new.flags; + if (fcf == fip->sel_fcf && !fcf->fd_flags) { fip->ctlr_ka_time -= fcf->fka_period; fip->ctlr_ka_time += new.fka_period; if (time_before(fip->ctlr_ka_time, fip->timer.expires)) mod_timer(&fip->timer, fip->ctlr_ka_time); - } else if (!fcoe_ctlr_fcf_usable(fcf)) - fcf->flags = new.flags; + } fcf->fka_period = new.fka_period; memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); } -- cgit v1.2.3-70-g09d2 From 0a9c5d344dbd983af59865f9880621e5cbbda899 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:44:25 -0700 Subject: [SCSI] libfcoe: Handle duplicate critical descriptors As per FC-BB-5 rev 2, section 7.8.6.2, malformed FIP frame shall be discarded. Drop discovery adv, ELS and CLV's with duplicate critical descriptors. [Resending after incorporating Joe's review comments] Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 27c21ca802b..db7185c0b96 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -640,6 +640,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, unsigned long t; size_t rlen; size_t dlen; + u32 desc_mask; memset(fcf, 0, sizeof(*fcf)); fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA); @@ -647,6 +648,12 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, fiph = (struct fip_header *)skb->data; fcf->flags = ntohs(fiph->fip_flags); + /* + * mask of required descriptors. validating each one clears its bit. + */ + desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | + BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA); + rlen = ntohs(fiph->fip_dl_len) * 4; if (rlen + sizeof(*fiph) > skb->len) return -EINVAL; @@ -656,11 +663,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, dlen = desc->fip_dlen * FIP_BPW; if (dlen < sizeof(*desc) || dlen > rlen) return -EINVAL; + /* Drop Adv if there are duplicate critical descriptors */ + if ((desc->fip_dtype < 32) && + !(desc_mask & 1U << desc->fip_dtype)) { + LIBFCOE_FIP_DBG(fip, "Duplicate Critical " + "Descriptors in FIP adv\n"); + return -EINVAL; + } switch (desc->fip_dtype) { case FIP_DT_PRI: if (dlen != sizeof(struct fip_pri_desc)) goto len_err; fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri; + desc_mask &= ~BIT(FIP_DT_PRI); break; case FIP_DT_MAC: if (dlen != sizeof(struct fip_mac_desc)) @@ -673,12 +688,14 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, "in FIP adv\n"); return -EINVAL; } + desc_mask &= ~BIT(FIP_DT_MAC); break; case FIP_DT_NAME: if (dlen != sizeof(struct fip_wwn_desc)) goto len_err; wwn = (struct fip_wwn_desc *)desc; fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn); + desc_mask &= ~BIT(FIP_DT_NAME); break; case FIP_DT_FAB: if (dlen != sizeof(struct fip_fab_desc)) @@ -687,6 +704,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn); fcf->vfid = ntohs(fab->fd_vfid); fcf->fc_map = ntoh24(fab->fd_map); + desc_mask &= ~BIT(FIP_DT_FAB); break; case FIP_DT_FKA: if (dlen != sizeof(struct fip_fka_desc)) @@ -697,6 +715,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, t = ntohl(fka->fd_fka_period); if (t >= FCOE_CTLR_MIN_FKA) fcf->fka_period = msecs_to_jiffies(t); + desc_mask &= ~BIT(FIP_DT_FKA); break; case FIP_DT_MAP_OUI: case FIP_DT_FCOE_SIZE: @@ -719,6 +738,11 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, return -EINVAL; if (!fcf->switch_name || !fcf->fabric_name) return -EINVAL; + if (desc_mask) { + LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n", + desc_mask); + return -EINVAL; + } return 0; len_err: @@ -847,6 +871,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) size_t els_len = 0; size_t rlen; size_t dlen; + u32 dupl_desc = 0; fiph = (struct fip_header *)skb->data; sub = fiph->fip_subcode; @@ -862,6 +887,15 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) dlen = desc->fip_dlen * FIP_BPW; if (dlen < sizeof(*desc) || dlen > rlen) goto drop; + /* Drop ELS if there are duplicate critical descriptors */ + if (desc->fip_dtype < 32) { + if (dupl_desc & 1U << desc->fip_dtype) { + LIBFCOE_FIP_DBG(fip, "Duplicate Critical " + "Descriptors in FIP ELS\n"); + goto drop; + } + dupl_desc |= (1 << desc->fip_dtype); + } switch (desc->fip_dtype) { case FIP_DT_MAC: if (dlen != sizeof(struct fip_mac_desc)) @@ -973,6 +1007,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, dlen = desc->fip_dlen * FIP_BPW; if (dlen > rlen) return; + /* Drop CVL if there are duplicate critical descriptors */ + if ((desc->fip_dtype < 32) && + !(desc_mask & 1U << desc->fip_dtype)) { + LIBFCOE_FIP_DBG(fip, "Duplicate Critical " + "Descriptors in FIP CVL\n"); + return; + } switch (desc->fip_dtype) { case FIP_DT_MAC: mp = (struct fip_mac_desc *)desc; -- cgit v1.2.3-70-g09d2 From 5550fda73d8bd3bed454e28c46f5a4e5288769bb Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:44:31 -0700 Subject: [SCSI] libfcoe: Host doesnt handle CVL to NPIV ports Clear virtual link for NPIV ports is now handled by resetting the matching vnport. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index db7185c0b96..ce651ca2a4b 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -989,7 +989,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, size_t dlen; struct fcoe_fcf *fcf = fip->sel_fcf; struct fc_lport *lport = fip->lp; - u32 desc_mask; + struct fc_lport *vn_port = NULL; + u32 desc_mask; + int is_vn_port = 0; LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); @@ -1038,8 +1040,26 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, if (compare_ether_addr(vp->fd_mac, fip->get_src_addr(lport)) == 0 && get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn && - ntoh24(vp->fd_fc_id) == lport->port_id) + ntoh24(vp->fd_fc_id) == lport->port_id) { desc_mask &= ~BIT(FIP_DT_VN_ID); + break; + } + /* check if clr_vlink is for NPIV port */ + mutex_lock(&lport->lp_mutex); + list_for_each_entry(vn_port, &lport->vports, list) { + if (compare_ether_addr(vp->fd_mac, + fip->get_src_addr(vn_port)) == 0 && + (get_unaligned_be64(&vp->fd_wwpn) + == vn_port->wwpn) && + (ntoh24(vp->fd_fc_id) == + fc_host_port_id(vn_port->host))) { + desc_mask &= ~BIT(FIP_DT_VN_ID); + is_vn_port = 1; + break; + } + } + mutex_unlock(&lport->lp_mutex); + break; default: /* standard says ignore unknown descriptors >= 128 */ @@ -1060,14 +1080,18 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, } else { LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n"); - spin_lock_bh(&fip->lock); - per_cpu_ptr(lport->dev_stats, - smp_processor_id())->VLinkFailureCount++; - fcoe_ctlr_reset(fip); - spin_unlock_bh(&fip->lock); + if (is_vn_port) + fc_lport_reset(vn_port); + else { + spin_lock_bh(&fip->lock); + per_cpu_ptr(lport->dev_stats, + smp_processor_id())->VLinkFailureCount++; + fcoe_ctlr_reset(fip); + spin_unlock_bh(&fip->lock); - fc_lport_reset(fip->lp); - fcoe_ctlr_solicit(fip, NULL); + fc_lport_reset(fip->lp); + fcoe_ctlr_solicit(fip, NULL); + } } } -- cgit v1.2.3-70-g09d2 From be61331d902e63011138723da3f737d34506f797 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Fri, 11 Jun 2010 16:44:36 -0700 Subject: [SCSI] libfcoe: Check for order and missing critical descriptors for FIP ELS requests As per FC-BB-5 rev.2, section 7.8.7.1, strict ordering of FIP descriptors is required for ELS requests. Also, look for missing and duplicate critical descriptors. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index ce651ca2a4b..f009191063f 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -871,7 +871,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) size_t els_len = 0; size_t rlen; size_t dlen; - u32 dupl_desc = 0; + u32 desc_mask = 0; + u32 desc_cnt = 0; fiph = (struct fip_header *)skb->data; sub = fiph->fip_subcode; @@ -884,20 +885,27 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) desc = (struct fip_desc *)(fiph + 1); while (rlen > 0) { + desc_cnt++; dlen = desc->fip_dlen * FIP_BPW; if (dlen < sizeof(*desc) || dlen > rlen) goto drop; /* Drop ELS if there are duplicate critical descriptors */ if (desc->fip_dtype < 32) { - if (dupl_desc & 1U << desc->fip_dtype) { + if (desc_mask & 1U << desc->fip_dtype) { LIBFCOE_FIP_DBG(fip, "Duplicate Critical " "Descriptors in FIP ELS\n"); goto drop; } - dupl_desc |= (1 << desc->fip_dtype); + desc_mask |= (1 << desc->fip_dtype); } switch (desc->fip_dtype) { case FIP_DT_MAC: + if (desc_cnt == 1) { + LIBFCOE_FIP_DBG(fip, "FIP descriptors " + "received out of order\n"); + goto drop; + } + if (dlen != sizeof(struct fip_mac_desc)) goto len_err; memcpy(granted_mac, @@ -914,6 +922,11 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) case FIP_DT_FDISC: case FIP_DT_LOGO: case FIP_DT_ELP: + if (desc_cnt != 1) { + LIBFCOE_FIP_DBG(fip, "FIP descriptors " + "received out of order\n"); + goto drop; + } if (fh) goto drop; if (dlen < sizeof(*els) + sizeof(*fh) + 1) @@ -929,6 +942,11 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) /* standard says ignore unknown descriptors >= 128 */ if (desc->fip_dtype < FIP_DT_VENDOR_BASE) goto drop; + if (desc_cnt <= 2) { + LIBFCOE_FIP_DBG(fip, "FIP descriptors " + "received out of order\n"); + goto drop; + } break; } desc = (struct fip_desc *)((char *)desc + dlen); @@ -944,6 +962,13 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) fip->flogi_oxid = FC_XID_UNKNOWN; + if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) && + (!(1U << FIP_DT_MAC & desc_mask)))) { + LIBFCOE_FIP_DBG(fip, "Missing critical descriptors " + "in FIP ELS\n"); + goto drop; + } + /* * Convert skb into an fc_frame containing only the ELS. */ -- cgit v1.2.3-70-g09d2 From 1c4bfe6305215f09f3e80a14a824e4ae45b2c7ed Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Fri, 11 Jun 2010 16:44:41 -0700 Subject: [SCSI] libfc: lport state is enum not bit mask lport state is enum not bit mask. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index ec1f66c4a9d..8914f1e95b7 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -745,7 +745,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) fh = fc_frame_header_get(fp); r_ctl = fh->fh_r_ctl; - if (!(lport->state & LPORT_ST_READY)) + if (lport->state != LPORT_ST_READY) goto out; if (fc_fcp_lock_pkt(fsp)) goto out; -- cgit v1.2.3-70-g09d2 From 0db6f4353d68c0108b5fe0bad8259de0197589c6 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 11 Jun 2010 16:44:46 -0700 Subject: [SCSI] fnic: fnic_scsi.c: clean up In fnic_abort_cmd() and fnic_device_reset() assign `rport' earlier to make FNIC_SCSI_DBG() calls cleaner. In fnic_clean_pending_aborts() `rport' is not used. Signed-off-by: Roel Kluin Acked-by: Abhijeet Joglekar Signed-off-by: Andrew Morton Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fnic/fnic_scsi.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 3cc47c6e1ad..198cbab3e89 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1246,11 +1246,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) lp = shost_priv(sc->device->host); fnic = lport_priv(lp); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n", - (starget_to_rport(scsi_target(sc->device)))->port_id, - sc->device->lun, sc->request->tag); + rport = starget_to_rport(scsi_target(sc->device)); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n", + rport->port_id, sc->device->lun, sc->request->tag); if (lp->state != LPORT_ST_READY || !(lp->link_up)) { ret = FAILED; @@ -1299,7 +1298,6 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) * port is up, then send abts to the remote port to terminate * the IO. Else, just locally terminate the IO in the firmware */ - rport = starget_to_rport(scsi_target(sc->device)); if (fc_remote_port_chkready(rport) == 0) task_req = FCPIO_ITMF_ABT_TASK; else @@ -1418,7 +1416,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, unsigned long flags; int ret = 0; struct scsi_cmnd *sc; - struct fc_rport *rport; struct scsi_lun fc_lun; struct scsi_device *lun_dev = lr_sc->device; DECLARE_COMPLETION_ONSTACK(tm_done); @@ -1458,7 +1455,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, /* Now queue the abort command to firmware */ int_to_scsilun(sc->device->lun, &fc_lun); - rport = starget_to_rport(scsi_target(sc->device)); if (fnic_queue_abort_io_req(fnic, tag, FCPIO_ITMF_ABT_TASK_TERM, @@ -1528,18 +1524,16 @@ int fnic_device_reset(struct scsi_cmnd *sc) lp = shost_priv(sc->device->host); fnic = lport_priv(lp); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Device reset called FCID 0x%x, LUN 0x%x\n", - (starget_to_rport(scsi_target(sc->device)))->port_id, - sc->device->lun); + rport = starget_to_rport(scsi_target(sc->device)); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + "Device reset called FCID 0x%x, LUN 0x%x\n", + rport->port_id, sc->device->lun); if (lp->state != LPORT_ST_READY || !(lp->link_up)) goto fnic_device_reset_end; /* Check if remote port up */ - rport = starget_to_rport(scsi_target(sc->device)); if (fc_remote_port_chkready(rport)) goto fnic_device_reset_end; -- cgit v1.2.3-70-g09d2 From 4b2164d4d212e437c9f080023a67f8f9356d2c4c Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:44:51 -0700 Subject: [SCSI] libfc: Fix remote port restart problem This patch somewhat combines two fixes to remote port handing in libfc. The first problem was that rport work could be queued on a deleted and freed rport. This is handled by not resetting rdata->event ton NONE if the rdata is about to be deleted. However, that fix led to the second problem, described by Bhanu Gollapudi, as follows: > Here is the sequence of events. T1 is first LOGO receive thread, T2 is > fc_rport_work() scheduled by T1 and T3 is second LOGO receive thread and > T4 is fc_rport_work scheduled by T3. > > 1. (T1)Received 1st LOGO in state Ready > 2. (T1)Delete port & enter to RESTART state. > 3. (T1)schdule event_work, since event is RPORT_EV_NONE. > 4. (T1)set event = RPORT_EV_LOGO > 5. (T1)Enter RESTART state as disc_id is set. > 6. (T2)remember to PLOGI, and set event = RPORT_EV_NONE > 6. (T3)Received 2nd LOGO > 7. (T3)Delete Port & enter to RESTART state. > 8. (T3)schedule event_work, since event is RPORT_EV_NONE. > 9. (T3)Enter RESTART state as disc_id is set. > 9. (T3)set event = RPORT_EV_LOGO > 10.(T2)work restart, enter PLOGI state and issues PLOGI > 11.(T4)Since state is not RESTART anymore, restart is not set, and the > event is not reset to RPORT_EV_NONE. (current event is RPORT_EV_LOGO). > 12. Now, PLOGI succeeds and fc_rport_enter_ready() will not schedule > event_work, and hence the rport will never be created, eventually losing > the target after dev_loss_tmo. So, the problem here is that we were tracking the desire for the rport be restarted by state RESTART, which was otherwise equivalent to DELETE. A contributing factor is that we dropped the lock between steps 6 and 10 in thread T2, which allows the state to change, and we didn't completely re-evaluate then. This is hopefully corrected by the following minor redesign: Simplify the rport restart logic by making the decision to restart after deleting the transport rport. That decision is based on a new STARTED flag that indicates fc_rport_login() has been called and fc_rport_logoff() has not been called since then. This replaces the need for the RESTART state. Only restart if the rdata is still in DELETED state and only if it still has the STARTED flag set. Also now, since we clear the event code much later in the work thread, allow for the possibility that the rport may have become READY again via incoming PLOGI, and if so, queue another event to handle that. In the problem scenario, the second LOGO received will cause the LOGO event to occur again. Reported-by: Bhanu Gollapudi Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 75 ++++++++++++++++++------------------------- include/scsi/libfc.h | 5 ++- 2 files changed, 33 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index df85e19079f..d385efc68c1 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -89,7 +89,6 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_LOGO] = "LOGO", [RPORT_ST_ADISC] = "ADISC", [RPORT_ST_DELETE] = "Delete", - [RPORT_ST_RESTART] = "Restart", }; /** @@ -246,7 +245,6 @@ static void fc_rport_work(struct work_struct *work) struct fc_rport_operations *rport_ops; struct fc_rport_identifiers ids; struct fc_rport *rport; - int restart = 0; mutex_lock(&rdata->rp_mutex); event = rdata->event; @@ -298,24 +296,6 @@ static void fc_rport_work(struct work_struct *work) port_id = rdata->ids.port_id; mutex_unlock(&rdata->rp_mutex); - if (port_id != FC_FID_DIR_SERV) { - /* - * We must drop rp_mutex before taking disc_mutex. - * Re-evaluate state to allow for restart. - * A transition to RESTART state must only happen - * while disc_mutex is held and rdata is on the list. - */ - mutex_lock(&lport->disc.disc_mutex); - mutex_lock(&rdata->rp_mutex); - if (rdata->rp_state == RPORT_ST_RESTART) - restart = 1; - else - list_del(&rdata->peers); - rdata->event = RPORT_EV_NONE; - mutex_unlock(&rdata->rp_mutex); - mutex_unlock(&lport->disc.disc_mutex); - } - if (rport_ops && rport_ops->event_callback) { FC_RPORT_DBG(rdata, "callback ev %d\n", event); rport_ops->event_callback(lport, rdata, event); @@ -336,13 +316,34 @@ static void fc_rport_work(struct work_struct *work) mutex_unlock(&rdata->rp_mutex); fc_remote_port_delete(rport); } - if (restart) { - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "work restart\n"); - fc_rport_enter_plogi(rdata); + + mutex_lock(&lport->disc.disc_mutex); + mutex_lock(&rdata->rp_mutex); + if (rdata->rp_state == RPORT_ST_DELETE) { + if (port_id == FC_FID_DIR_SERV) { + rdata->event = RPORT_EV_NONE; + mutex_unlock(&rdata->rp_mutex); + } else if (rdata->flags & FC_RP_STARTED) { + rdata->event = RPORT_EV_NONE; + FC_RPORT_DBG(rdata, "work restart\n"); + fc_rport_enter_plogi(rdata); + mutex_unlock(&rdata->rp_mutex); + } else { + FC_RPORT_DBG(rdata, "work delete\n"); + list_del(&rdata->peers); + mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, lport->tt.rport_destroy); + } + } else { + /* + * Re-open for events. Reissue READY event if ready. + */ + rdata->event = RPORT_EV_NONE; + if (rdata->rp_state == RPORT_ST_READY) + fc_rport_enter_ready(rdata); mutex_unlock(&rdata->rp_mutex); - } else - kref_put(&rdata->kref, lport->tt.rport_destroy); + } + mutex_unlock(&lport->disc.disc_mutex); break; default: @@ -367,16 +368,14 @@ int fc_rport_login(struct fc_rport_priv *rdata) { mutex_lock(&rdata->rp_mutex); + rdata->flags |= FC_RP_STARTED; switch (rdata->rp_state) { case RPORT_ST_READY: FC_RPORT_DBG(rdata, "ADISC port\n"); fc_rport_enter_adisc(rdata); break; - case RPORT_ST_RESTART: - break; case RPORT_ST_DELETE: FC_RPORT_DBG(rdata, "Restart deleted port\n"); - fc_rport_state_enter(rdata, RPORT_ST_RESTART); break; default: FC_RPORT_DBG(rdata, "Login to port\n"); @@ -431,15 +430,12 @@ int fc_rport_logoff(struct fc_rport_priv *rdata) FC_RPORT_DBG(rdata, "Remove port\n"); + rdata->flags &= ~FC_RP_STARTED; if (rdata->rp_state == RPORT_ST_DELETE) { FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); goto out; } - - if (rdata->rp_state == RPORT_ST_RESTART) - FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n"); - else - fc_rport_enter_logo(rdata); + fc_rport_enter_logo(rdata); /* * Change the state to Delete so that we discard @@ -503,7 +499,6 @@ static void fc_rport_timeout(struct work_struct *work) case RPORT_ST_READY: case RPORT_ST_INIT: case RPORT_ST_DELETE: - case RPORT_ST_RESTART: break; } @@ -527,6 +522,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) switch (rdata->rp_state) { case RPORT_ST_PLOGI: case RPORT_ST_LOGO: + rdata->flags &= ~FC_RP_STARTED; fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; case RPORT_ST_RTV: @@ -537,7 +533,6 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) fc_rport_enter_logo(rdata); break; case RPORT_ST_DELETE: - case RPORT_ST_RESTART: case RPORT_ST_READY: case RPORT_ST_INIT: break; @@ -1392,7 +1387,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, break; case RPORT_ST_DELETE: case RPORT_ST_LOGO: - case RPORT_ST_RESTART: FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", fc_rport_state(rdata)); mutex_unlock(&rdata->rp_mutex); @@ -1684,13 +1678,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, fc_rport_state(rdata)); fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - - /* - * If the remote port was created due to discovery, set state - * to log back in. It may have seen a stale RSCN about us. - */ - if (rdata->disc_id) - fc_rport_state_enter(rdata, RPORT_ST_RESTART); mutex_unlock(&rdata->rp_mutex); } else FC_RPORT_ID_DBG(lport, sid, diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 7495c0ba67e..db54c4a2d14 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -104,7 +104,6 @@ enum fc_disc_event { * @RPORT_ST_LOGO: Remote port logout (LOGO) sent * @RPORT_ST_ADISC: Discover Address sent * @RPORT_ST_DELETE: Remote port being deleted - * @RPORT_ST_RESTART: Remote port being deleted and will restart */ enum fc_rport_state { RPORT_ST_INIT, @@ -115,7 +114,6 @@ enum fc_rport_state { RPORT_ST_LOGO, RPORT_ST_ADISC, RPORT_ST_DELETE, - RPORT_ST_RESTART, }; /** @@ -173,6 +171,7 @@ struct fc_rport_libfc_priv { u16 flags; #define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) #define FC_RP_FLAGS_RETRY (1 << 1) + #define FC_RP_STARTED (1 << 2) unsigned int e_d_tov; unsigned int r_a_tov; }; @@ -185,7 +184,7 @@ struct fc_rport_libfc_priv { * @rp_state: Enumeration that tracks progress of PLOGI, PRLI, * and RTV exchanges * @ids: The remote port identifiers and roles - * @flags: REC and RETRY supported flags + * @flags: STARTED, REC and RETRY_SUPPORTED flags * @max_seq: Maximum number of concurrent sequences * @disc_id: The discovery identifier * @maxframe_size: The maximum frame size -- cgit v1.2.3-70-g09d2 From f034260db330bb3ffc815fcb682b1c84aca09591 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 11 Jun 2010 16:44:57 -0700 Subject: [SCSI] libfc: fix indefinite rport restart Remote ports were restarting indefinitely after getting rejects in PRLI. Fix by adding a counter of restarts and limiting that with the port login retry limit as well. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 6 +++++- include/scsi/libfc.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index d385efc68c1..363cde30c94 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -257,6 +257,7 @@ static void fc_rport_work(struct work_struct *work) case RPORT_EV_READY: ids = rdata->ids; rdata->event = RPORT_EV_NONE; + rdata->major_retries = 0; kref_get(&rdata->kref); mutex_unlock(&rdata->rp_mutex); @@ -323,7 +324,10 @@ static void fc_rport_work(struct work_struct *work) if (port_id == FC_FID_DIR_SERV) { rdata->event = RPORT_EV_NONE; mutex_unlock(&rdata->rp_mutex); - } else if (rdata->flags & FC_RP_STARTED) { + } else if ((rdata->flags & FC_RP_STARTED) && + rdata->major_retries < + lport->max_rport_retry_count) { + rdata->major_retries++; rdata->event = RPORT_EV_NONE; FC_RPORT_DBG(rdata, "work restart\n"); fc_rport_enter_plogi(rdata); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index db54c4a2d14..6d78df77dab 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -189,6 +189,7 @@ struct fc_rport_libfc_priv { * @disc_id: The discovery identifier * @maxframe_size: The maximum frame size * @retries: The retry count for the current state + * @major_retries: The retry count for the entire PLOGI/PRLI state machine * @e_d_tov: Error detect timeout value (in msec) * @r_a_tov: Resource allocation timeout value (in msec) * @rp_mutex: The mutex that protects the remote port @@ -206,6 +207,7 @@ struct fc_rport_priv { u16 disc_id; u16 maxframe_size; unsigned int retries; + unsigned int major_retries; unsigned int e_d_tov; unsigned int r_a_tov; struct mutex rp_mutex; -- cgit v1.2.3-70-g09d2 From ae52e7f09ff509df11cd408eabe90132b6be1231 Mon Sep 17 00:00:00 2001 From: Nick Cheng Date: Fri, 18 Jun 2010 15:39:12 +0800 Subject: [SCSI] arcmsr: Support 1024 scatter-gather list entries and improve AP while FW trapped and behaviors of EHs 1. To support 4M/1024 scatter-gather list entry, reorganize struct ARCMSR_CDB and struct CommandControlBlock 2. To modify arcmsr_probe 3. In order to help fix F/W issue, add the driver mode for type B card 4. To improve AP's behavior while F/W resets 5. To unify struct MessageUnit_B's members' naming in all OS drivers' 6. To improve error handlers, arcmsr_bus_reset(), arcmsr_abort() 7. To fix the arcmsr_queue_command() in bus reset stage, just let the commands pass down to FW, don't block Signed-off-by: Nick Cheng Signed-off-by: James Bottomley --- drivers/scsi/arcmsr/arcmsr.h | 135 ++--- drivers/scsi/arcmsr/arcmsr_hba.c | 1225 +++++++++++++++++++------------------- 2 files changed, 677 insertions(+), 683 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index ce5371b3cdd..c0861c05cd4 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -48,16 +48,22 @@ struct device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/11/03" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 +#define ARCMSR_MAX_XFER_SECTORS_C 304 #define ARCMSR_MAX_TARGETID 17 #define ARCMSR_MAX_TARGETLUN 8 #define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD #define ARCMSR_MAX_QBUFFER 4096 -#define ARCMSR_MAX_SG_ENTRIES 38 +#define ARCMSR_DEFAULT_SG_ENTRIES 38 #define ARCMSR_MAX_HBB_POSTQUEUE 264 +#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ +#define ARCMSR_CDB_SG_PAGE_LENGTH 256 +#ifndef PCI_DEVICE_ID_ARECA_1880 +#define PCI_DEVICE_ID_ARECA_1880 0x1880 + #endif /* ********************************************************************************** ** @@ -141,26 +147,19 @@ struct CMD_MESSAGE_FIELD ** structure for holding DMA address data ************************************************************* */ +#define IS_DMA64 (sizeof(dma_addr_t) == 8) #define IS_SG64_ADDR 0x01000000 /* bit24 */ struct SG32ENTRY { __le32 length; __le32 address; -}; +} __attribute__ ((packed)); struct SG64ENTRY { __le32 length; __le32 address; __le32 addresshigh; -}; -struct SGENTRY_UNION -{ - union - { - struct SG32ENTRY sg32entry; - struct SG64ENTRY sg64entry; - }u; -}; +} __attribute__ ((packed)); /* ******************************************************************** ** Q Buffer of IOP Message Transfer @@ -187,6 +186,9 @@ struct FIRMWARE_INFO char model[8]; /*15, 60-67*/ char firmware_ver[16]; /*17, 68-83*/ char device_map[16]; /*21, 84-99*/ + uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/ + uint8_t cfgSerial[16]; /*26,104-119*/ + uint32_t cfgPicStatus; /*30,120-123*/ }; /* signature of set and get firmware config */ #define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 @@ -213,6 +215,8 @@ struct FIRMWARE_INFO #define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 +/* ARC-1680 Bus Reset*/ +#define ARCMSR_ARC1680_BUS_RESET 0x00000003 /* ************************************************************************ @@ -264,11 +268,11 @@ struct FIRMWARE_INFO /* data tunnel buffer between user space program and its firmware */ /* user space data to iop 128bytes */ -#define ARCMSR_IOCTL_WBUFFER 0x0000fe00 +#define ARCMSR_MESSAGE_WBUFFER 0x0000fe00 /* iop data to user space 128bytes */ -#define ARCMSR_IOCTL_RBUFFER 0x0000ff00 +#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00 /* iop message_rwbuffer for message command */ -#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00 +#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -290,7 +294,7 @@ struct ARCMSR_CDB #define ARCMSR_CDB_FLAG_HEADQ 0x08 #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 - uint8_t Reserved1; + uint8_t msgPages; uint32_t Context; uint32_t DataLength; uint8_t Cdb[16]; @@ -303,10 +307,10 @@ struct ARCMSR_CDB uint8_t SenseData[15]; union { - struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; - struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES]; + struct SG32ENTRY sg32entry[1]; + struct SG64ENTRY sg64entry[1]; } u; -}; +} __attribute__ ((packed)); /* ******************************************************************************* ** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor @@ -344,13 +348,13 @@ struct MessageUnit_B uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; uint32_t postq_index; uint32_t doneq_index; - uint32_t __iomem *drv2iop_doorbell_reg; - uint32_t __iomem *drv2iop_doorbell_mask_reg; - uint32_t __iomem *iop2drv_doorbell_reg; - uint32_t __iomem *iop2drv_doorbell_mask_reg; - uint32_t __iomem *msgcode_rwbuffer_reg; - uint32_t __iomem *ioctl_wbuffer_reg; - uint32_t __iomem *ioctl_rbuffer_reg; + uint32_t __iomem *drv2iop_doorbell; + uint32_t __iomem *drv2iop_doorbell_mask; + uint32_t __iomem *iop2drv_doorbell; + uint32_t __iomem *iop2drv_doorbell_mask; + uint32_t __iomem *message_rwbuffer; + uint32_t __iomem *message_wbuffer; + uint32_t __iomem *message_rbuffer; }; /* @@ -370,14 +374,17 @@ struct AdapterControlBlock unsigned long vir2phy_offset; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; - + spinlock_t eh_lock; + spinlock_t ccblist_lock; union { struct MessageUnit_A __iomem * pmuA; struct MessageUnit_B * pmuB; }; /* message unit ATU inbound base address0 */ - + void __iomem *mem_base0; + void __iomem *mem_base1; uint32_t acb_flags; + u16 dev_id; uint8_t adapter_index; #define ACB_F_SCSISTOPADAPTER 0x0001 #define ACB_F_MSG_STOP_BGRB 0x0002 @@ -394,6 +401,7 @@ struct AdapterControlBlock #define ACB_F_BUS_RESET 0x0080 #define ACB_F_IOP_INITED 0x0100 /* iop init */ + #define ACB_F_ABORT 0x0200 #define ACB_F_FIRMWARE_TRAP 0x0400 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ @@ -408,7 +416,8 @@ struct AdapterControlBlock /* dma_coherent used for memory free */ dma_addr_t dma_coherent_handle; /* dma_coherent_handle used for memory free */ - + dma_addr_t dma_coherent_handle_hbb_mu; + unsigned int uncache_size; uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; /* data collection buffer for read from 80331 */ int32_t rqbuf_firstindex; @@ -432,14 +441,18 @@ struct AdapterControlBlock uint32_t firm_numbers_queue; uint32_t firm_sdram_size; uint32_t firm_hd_channels; + uint32_t firm_cfg_version; char firm_model[12]; char firm_version[20]; char device_map[20]; /*21,84-99*/ struct work_struct arcmsr_do_message_isr_bh; struct timer_list eternal_timer; - unsigned short fw_state; + unsigned short fw_flag; + #define FW_NORMAL 0x0000 + #define FW_BOG 0x0001 + #define FW_DEADLOCK 0x0010 atomic_t rq_map_token; - int ante_token_value; + atomic_t ante_token_value; };/* HW_DEVICE_EXTENSION */ /* ******************************************************************************* @@ -449,65 +462,31 @@ struct AdapterControlBlock */ struct CommandControlBlock { - struct ARCMSR_CDB arcmsr_cdb; - /* - ** 0-503 (size of CDB = 504): - ** arcmsr messenger scsi command descriptor size 504 bytes - */ - uint32_t cdb_shifted_phyaddr; - /* 504-507 */ - uint32_t reserved1; - /* 508-511 */ -#if BITS_PER_LONG == 64 - /* ======================512+64 bytes======================== */ - struct list_head list; - /* 512-527 16 bytes next/prev ptrs for ccb lists */ - struct scsi_cmnd * pcmd; - /* 528-535 8 bytes pointer of linux scsi command */ - struct AdapterControlBlock * acb; - /* 536-543 8 bytes pointer of acb */ - - uint16_t ccb_flags; - /* 544-545 */ + /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ + struct list_head list; /*x32: 8byte, x64: 16byte*/ + struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */ + struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/ + uint32_t shifted_cdb_phyaddr; /*x32: 4byte, x64: 4byte*/ + uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ #define CCB_FLAG_READ 0x0000 #define CCB_FLAG_WRITE 0x0001 #define CCB_FLAG_ERROR 0x0002 #define CCB_FLAG_FLUSHCACHE 0x0004 #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; - /* 546-547 */ + uint16_t startdone; /*x32:2byte,x32:2byte*/ #define ARCMSR_CCB_DONE 0x0000 #define ARCMSR_CCB_START 0x55AA #define ARCMSR_CCB_ABORTED 0xAA55 #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[7]; - /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */ + #if BITS_PER_LONG == 64 + /* ======================512+64 bytes======================== */ + uint32_t reserved[6]; /*24 byte*/ #else /* ======================512+32 bytes======================== */ - struct list_head list; - /* 512-519 8 bytes next/prev ptrs for ccb lists */ - struct scsi_cmnd * pcmd; - /* 520-523 4 bytes pointer of linux scsi command */ - struct AdapterControlBlock * acb; - /* 524-527 4 bytes pointer of acb */ - - uint16_t ccb_flags; - /* 528-529 */ - #define CCB_FLAG_READ 0x0000 - #define CCB_FLAG_WRITE 0x0001 - #define CCB_FLAG_ERROR 0x0002 - #define CCB_FLAG_FLUSHCACHE 0x0004 - #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; - /* 530-531 */ - #define ARCMSR_CCB_DONE 0x0000 - #define ARCMSR_CCB_START 0x55AA - #define ARCMSR_CCB_ABORTED 0xAA55 - #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[3]; - /* 532-535 536-539 540-543 */ + uint32_t reserved[2]; /*8 byte*/ #endif - /* ========================================================== */ + /* ======================================================= */ + struct ARCMSR_CDB arcmsr_cdb; }; /* ******************************************************************************* diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index ffa54792bb3..ba33473b27a 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -71,20 +70,13 @@ #include #include #include "arcmsr.h" - -#ifdef CONFIG_SCSI_ARCMSR_RESET - static int sleeptime = 20; - static int retrycount = 12; - module_param(sleeptime, int, S_IRUGO|S_IWUSR); - MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset"); - module_param(retrycount, int, S_IRUGO|S_IWUSR); - MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset"); -#endif -MODULE_AUTHOR("Erich Chen "); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter"); +MODULE_AUTHOR("Nick Cheng "); +MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); - +static int sleeptime = 20; +static int retrycount = 12; +wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); @@ -108,7 +100,7 @@ static void arcmsr_request_device_map(unsigned long pacb); static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb); static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb); static void arcmsr_message_isr_bh_fn(struct work_struct *work); -static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode); +static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); @@ -135,10 +127,10 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, .change_queue_depth = arcmsr_adjust_disk_queue_depth, - .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, + .can_queue = ARCMSR_MAX_FREECCB_NUM, .this_id = ARCMSR_SCSI_INITIATOR_ID, - .sg_tablesize = ARCMSR_MAX_SG_ENTRIES, - .max_sectors = ARCMSR_MAX_XFER_SECTORS, + .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, + .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = arcmsr_host_attrs, @@ -162,6 +154,7 @@ static struct pci_device_id arcmsr_device_id_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)}, {0, 0}, /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); @@ -173,15 +166,72 @@ static struct pci_driver arcmsr_pci_driver = { .shutdown = arcmsr_shutdown, }; +static void arcmsr_free_mu(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + break; + case ACB_ADAPTER_TYPE_B:{ + struct MessageUnit_B *reg = acb->pmuB; + dma_free_coherent(&acb->pdev->dev, + sizeof(struct MessageUnit_B), + reg, acb->dma_coherent_handle_hbb_mu); + } + } +} + +static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) +{ + struct pci_dev *pdev = acb->pdev; + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A:{ + acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!acb->pmuA) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + break; + } + case ACB_ADAPTER_TYPE_B:{ + void __iomem *mem_base0, *mem_base1; + mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!mem_base0) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); + if (!mem_base1) { + iounmap(mem_base0); + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + acb->mem_base0 = mem_base0; + acb->mem_base1 = mem_base1; + } + } + return true; +} + +static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A:{ + iounmap(acb->pmuA); + } + case ACB_ADAPTER_TYPE_B:{ + iounmap(acb->mem_base0); + iounmap(acb->mem_base1); + } + } +} + static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) { irqreturn_t handle_state; struct AdapterControlBlock *acb = dev_id; - spin_lock(acb->host->host_lock); handle_state = arcmsr_interrupt(acb); - spin_unlock(acb->host->host_lock); - return handle_state; } @@ -218,6 +268,7 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) struct pci_dev *pdev = acb->pdev; u16 dev_id; pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); + acb->dev_id = dev_id; switch (dev_id) { case 0x1201 : { acb->adapter_type = ACB_ADAPTER_TYPE_B; @@ -228,141 +279,210 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) } } -static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = acb->pmuA; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return 0x00; + } + msleep(10); + } /*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) { + struct MessageUnit_B *reg = acb->pmuB; + uint32_t Index; + uint8_t Retries = 0x00; + do { + for (Index = 0; Index < 100; Index++) { + if (readl(reg->iop2drv_doorbell) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN + , reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); + return 0x00; + } + msleep(10); + } /*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = acb->pmuA; + int retry_count = 30; + + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); + do { + if (!arcmsr_hba_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout, retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = acb->pmuB; + int retry_count = 30; + + writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); + do { + if (!arcmsr_hbb_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) +{ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - struct pci_dev *pdev = acb->pdev; - void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; - struct CommandControlBlock *ccb_tmp; - int i, j; + arcmsr_flush_hba_cache(acb); + } + break; - acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - if (!acb->pmuA) { - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", - acb->host->host_no); - return -ENOMEM; + case ACB_ADAPTER_TYPE_B: { + arcmsr_flush_hbb_cache(acb); } + } +} - dma_coherent = dma_alloc_coherent(&pdev->dev, - ARCMSR_MAX_FREECCB_NUM * - sizeof (struct CommandControlBlock) + 0x20, - &dma_coherent_handle, GFP_KERNEL); +static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +{ + struct pci_dev *pdev = acb->pdev; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + void *dma_coherent; + dma_addr_t dma_coherent_handle; + struct CommandControlBlock *ccb_tmp; + int i = 0, j = 0; + dma_addr_t cdb_phyaddr; + unsigned long roundup_ccbsize = 0; + unsigned long max_xfer_len; + unsigned long max_sg_entrys; + uint32_t firm_config_version; + + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; + + max_xfer_len = ARCMSR_MAX_XFER_LEN; + max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; + firm_config_version = acb->firm_cfg_version; + if ((firm_config_version & 0xFF) >= 3) { + max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ + max_sg_entrys = (max_xfer_len/4096); + } + acb->host->max_sectors = max_xfer_len/512; + acb->host->sg_tablesize = max_sg_entrys; + roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) { - iounmap(acb->pmuA); + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); return -ENOMEM; } - + memset(dma_coherent, 0, acb->uncache_size); acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; - - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } - - dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; + acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; + cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); + ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; acb->pccb_pool[i] = ccb_tmp; + ccb_tmp->acb = acb; + INIT_LIST_HEAD(&ccb_tmp->list); list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof(struct CommandControlBlock); - ccb_tmp++; - } - - acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } break; - + } case ACB_ADAPTER_TYPE_B: { - struct pci_dev *pdev = acb->pdev; - struct MessageUnit_B *reg; - void __iomem *mem_base0, *mem_base1; void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; + dma_addr_t dma_coherent_handle; struct CommandControlBlock *ccb_tmp; - int i, j; - - dma_coherent = dma_alloc_coherent(&pdev->dev, - ((ARCMSR_MAX_FREECCB_NUM * - sizeof(struct CommandControlBlock) + 0x20) + - sizeof(struct MessageUnit_B)), + uint32_t cdb_phyaddr; + unsigned int roundup_ccbsize = 0; + unsigned long max_xfer_len; + unsigned long max_sg_entrys; + unsigned long firm_config_version; + unsigned long max_freeccb_num = 0; + int i = 0, j = 0; + + max_freeccb_num = ARCMSR_MAX_FREECCB_NUM; + max_xfer_len = ARCMSR_MAX_XFER_LEN; + max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; + firm_config_version = acb->firm_cfg_version; + if ((firm_config_version & 0xFF) >= 3) { + max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << + ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ + max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/ + } + acb->host->max_sectors = max_xfer_len / 512; + acb->host->sg_tablesize = max_sg_entrys; + roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+ + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) - return -ENOMEM; + if (!dma_coherent) { + printk(KERN_NOTICE "DMA allocation failed...........................\n"); + return -ENOMEM; + } + memset(dma_coherent, 0, acb->uncache_size); acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; - - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } - - dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; + acb->vir2phy_offset = (unsigned long)dma_coherent - + (unsigned long)dma_coherent_handle; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; + cdb_phyaddr = dma_coherent_handle + + offsetof(struct CommandControlBlock, arcmsr_cdb); + ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; acb->pccb_pool[i] = ccb_tmp; + ccb_tmp->acb = acb; + INIT_LIST_HEAD(&ccb_tmp->list); list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof(struct CommandControlBlock); - ccb_tmp++; - } - - reg = (struct MessageUnit_B *)(dma_coherent + - ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); - acb->pmuB = reg; - mem_base0 = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!mem_base0) - goto out; - - mem_base1 = ioremap(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); - if (!mem_base1) { - iounmap(mem_base0); - goto out; + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } - - reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL; - reg->drv2iop_doorbell_mask_reg = mem_base0 + - ARCMSR_DRV2IOP_DOORBELL_MASK; - reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL; - reg->iop2drv_doorbell_mask_reg = mem_base0 + - ARCMSR_IOP2DRV_DOORBELL_MASK; - reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER; - reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER; - reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER; - - acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GOOD; + acb->devstate[i][j] = ARECA_RAID_GONE; } break; } return 0; - -out: - dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); - return -ENOMEM; } static void arcmsr_message_isr_bh_fn(struct work_struct *work) { @@ -411,8 +531,8 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer_reg[0]); - char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer_reg[21]); + uint32_t __iomem *signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); + char __iomem *devicemap = (char __iomem *)(®->message_rwbuffer[21]); int target, lun; struct scsi_device *psdev; char diff; @@ -447,8 +567,7 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) } } -static int arcmsr_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *host; struct AdapterControlBlock *acb; @@ -456,19 +575,13 @@ static int arcmsr_probe(struct pci_dev *pdev, int error; error = pci_enable_device(pdev); - if (error) - goto out; - pci_set_master(pdev); - - host = scsi_host_alloc(&arcmsr_scsi_host_template, - sizeof(struct AdapterControlBlock)); + if (error) { + return -ENODEV; + } + host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); if (!host) { - error = -ENOMEM; - goto out_disable_device; + goto pci_disable_dev; } - acb = (struct AdapterControlBlock *)host->hostdata; - memset(acb, 0, sizeof (struct AdapterControlBlock)); - error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (error) { error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); @@ -476,126 +589,90 @@ static int arcmsr_probe(struct pci_dev *pdev, printk(KERN_WARNING "scsi%d: No suitable DMA mask available\n", host->host_no); - goto out_host_put; + goto scsi_host_release; } } + init_waitqueue_head(&wait_q); bus = pdev->bus->number; dev_fun = pdev->devfn; - acb->host = host; + acb = (struct AdapterControlBlock *) host->hostdata; + memset(acb, 0, sizeof(struct AdapterControlBlock)); acb->pdev = pdev; - host->max_sectors = ARCMSR_MAX_XFER_SECTORS; + acb->host = host; host->max_lun = ARCMSR_MAX_TARGETLUN; host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ - host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; - host->irq = pdev->irq; + pci_set_drvdata(pdev, host); + pci_set_master(pdev); error = pci_request_regions(pdev, "arcmsr"); if (error) { - goto out_host_put; + goto scsi_host_release; } - arcmsr_define_adapter_type(acb); - + spin_lock_init(&acb->eh_lock); + spin_lock_init(&acb->ccblist_lock); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; INIT_LIST_HEAD(&acb->ccb_free_list); - INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); + arcmsr_define_adapter_type(acb); + error = arcmsr_remap_pciregion(acb); + if (!error) { + goto pci_release_regs; + } + error = arcmsr_get_firmware_spec(acb); + if (!error) { + goto unmap_pci_region; + } error = arcmsr_alloc_ccb_pool(acb); - if (error) - goto out_release_regions; - + if (error) { + goto free_hbb_mu; + } arcmsr_iop_init(acb); - error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_SHARED, "arcmsr", acb); - if (error) - goto out_free_ccb_pool; - - pci_set_drvdata(pdev, host); - if (strncmp(acb->firm_version, "V1.42", 5) >= 0) - host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B; - error = scsi_add_host(host, &pdev->dev); - if (error) - goto out_free_irq; - - error = arcmsr_alloc_sysfs_attr(acb); - if (error) - goto out_free_sysfs; - + if (error) { + goto RAID_controller_stop; + } + error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); + if (error) { + goto scsi_host_remove; + } + host->irq = pdev->irq; scsi_scan_host(host); - #ifdef CONFIG_SCSI_ARCMSR_AER - pci_enable_pcie_error_reporting(pdev); - #endif + INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); atomic_set(&acb->rq_map_token, 16); - acb->fw_state = true; + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); acb->eternal_timer.data = (unsigned long) acb; acb->eternal_timer.function = &arcmsr_request_device_map; add_timer(&acb->eternal_timer); - + if (arcmsr_alloc_sysfs_attr(acb)) + goto out_free_sysfs; return 0; out_free_sysfs: - out_free_irq: - free_irq(pdev->irq, acb); - out_free_ccb_pool: +scsi_host_remove: + scsi_remove_host(host); +RAID_controller_stop: + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); arcmsr_free_ccb_pool(acb); - out_release_regions: +free_hbb_mu: + arcmsr_free_mu(acb); +unmap_pci_region: + arcmsr_unmap_pciregion(acb); +pci_release_regs: pci_release_regions(pdev); - out_host_put: +scsi_host_release: scsi_host_put(host); - out_disable_device: +pci_disable_dev: pci_disable_device(pdev); - out: - return error; -} - -static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) & - ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, - ®->outbound_intstatus); - return 0x00; - } - msleep(10); - }/*max 1 seconds*/ - - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; -} - -static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(reg->iop2drv_doorbell_reg) - & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN - , reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); - return 0x00; - } - msleep(10); - }/*max 1 seconds*/ - - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return -ENODEV; } static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) @@ -616,7 +693,7 @@ static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" @@ -642,76 +719,41 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) return rtnval; } +static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb) +{ + struct MessageUnit_B *reg = pacb->pmuB; + + writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); + if (arcmsr_hbb_wait_msgint_ready(pacb)) { + printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no); + return false; +} + return true; +} + static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) { struct scsi_cmnd *pcmd = ccb->pcmd; scsi_dma_unmap(pcmd); -} + } -static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag) +static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) { struct AdapterControlBlock *acb = ccb->acb; struct scsi_cmnd *pcmd = ccb->pcmd; + unsigned long flags; + atomic_dec(&acb->ccboutstandingcount); arcmsr_pci_unmap_dma(ccb); - if (stand_flag == 1) - atomic_dec(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_DONE; ccb->ccb_flags = 0; + spin_lock_irqsave(&acb->ccblist_lock, flags); list_add_tail(&ccb->list, &acb->ccb_free_list); + spin_unlock_irqrestore(&acb->ccblist_lock, flags); pcmd->scsi_done(pcmd); } -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - int retry_count = 30; - - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - do { - if (!arcmsr_hba_wait_msgint_ready(acb)) - break; - else { - retry_count--; - printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ - timeout, retry count down = %d \n", acb->host->host_no, retry_count); - } - } while (retry_count != 0); -} - -static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - int retry_count = 30; - - writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg); - do { - if (!arcmsr_hbb_wait_msgint_ready(acb)) - break; - else { - retry_count--; - printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ - timeout,retry count down = %d \n", acb->host->host_no, retry_count); - } - } while (retry_count != 0); -} - -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - arcmsr_flush_hba_cache(acb); - } - break; - - case ACB_ADAPTER_TYPE_B: { - arcmsr_flush_hbb_cache(acb); - } - } -} - static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) { @@ -745,15 +787,15 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B : { struct MessageUnit_B *reg = acb->pmuB; - orig_mask = readl(reg->iop2drv_doorbell_mask_reg); - writel(0, reg->iop2drv_doorbell_mask_reg); + orig_mask = readl(reg->iop2drv_doorbell_mask); + writel(0, reg->iop2drv_doorbell_mask); } break; } return orig_mask; } -static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ +static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, uint32_t flag_ccb) { @@ -764,13 +806,13 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ if (acb->devstate[id][lun] == ARECA_RAID_GONE) acb->devstate[id][lun] = ARECA_RAID_GOOD; ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } else { switch (ccb->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: { acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } break; @@ -779,14 +821,14 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ case ARCMSR_DEV_INIT_FAIL: { acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } break; case ARCMSR_DEV_CHECK_CONDITION: { acb->devstate[id][lun] = ARECA_RAID_GOOD; arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } break; @@ -801,7 +843,7 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ , ccb->arcmsr_cdb.DeviceStatus); acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); break; } } @@ -811,14 +853,19 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla { struct CommandControlBlock *ccb; + struct ARCMSR_CDB *arcmsr_cdb; + int id, lun; - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); + ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if (ccb->startdone == ARCMSR_CCB_ABORTED) { struct scsi_cmnd *abortcmd = ccb->pcmd; if (abortcmd) { + id = abortcmd->device->id; + lun = abortcmd->device->lun; abortcmd->result |= DID_ABORT << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \ isr got aborted command \n", acb->host->host_no, ccb); } @@ -883,6 +930,7 @@ static void arcmsr_remove(struct pci_dev *pdev) int poll_count = 0; arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); + scsi_host_put(host); flush_scheduled_work(); del_timer_sync(&acb->eternal_timer); arcmsr_disable_outbound_ints(acb); @@ -908,17 +956,14 @@ static void arcmsr_remove(struct pci_dev *pdev) if (ccb->startdone == ARCMSR_CCB_START) { ccb->startdone = ARCMSR_CCB_ABORTED; ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } } } - free_irq(pdev->irq, acb); arcmsr_free_ccb_pool(acb); + arcmsr_free_mu(acb); pci_release_regions(pdev); - - scsi_host_put(host); - pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -973,7 +1018,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); - writel(mask, reg->iop2drv_doorbell_mask_reg); + writel(mask, reg->iop2drv_doorbell_mask); acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; } } @@ -986,6 +1031,9 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, int8_t *psge = (int8_t *)&arcmsr_cdb->u; __le32 address_lo, address_hi; int arccdbsize = 0x30; + __le32 length = 0; + int i, cdb_sgcount = 0; + struct scatterlist *sg; int nseg; ccb->pcmd = pcmd; @@ -995,19 +1043,12 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, arcmsr_cdb->LUN = pcmd->device->lun; arcmsr_cdb->Function = 1; arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len; - arcmsr_cdb->Context = (unsigned long)arcmsr_cdb; + arcmsr_cdb->Context = 0; memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); - if (nseg > ARCMSR_MAX_SG_ENTRIES) + if (nseg > acb->host->sg_tablesize || nseg < 0) return FAILED; - BUG_ON(nseg < 0); - - if (nseg) { - __le32 length; - int i, cdb_sgcount = 0; - struct scatterlist *sg; - /* map stor port SG list to our iop SG List. */ scsi_for_each_sg(pcmd, sg, nseg, i) { /* Get the physical address of the current data pointer */ @@ -1034,10 +1075,10 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, } arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount; arcmsr_cdb->DataLength = scsi_bufflen(pcmd); + arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0); if ( arccdbsize > 256) arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; - } - if (pcmd->sc_data_direction == DMA_TO_DEVICE ) { + if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) { arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; ccb->ccb_flags |= CCB_FLAG_WRITE; } @@ -1046,7 +1087,7 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; + uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; @@ -1056,10 +1097,10 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr struct MessageUnit_A __iomem *reg = acb->pmuA; if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); else { - writel(cdb_shifted_phyaddr, ®->inbound_queueport); + writel(shifted_cdb_phyaddr, ®->inbound_queueport); } } break; @@ -1071,16 +1112,16 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); writel(0, ®->post_qbuffer[ending_index]); if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ + writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ ®->post_qbuffer[index]); } else { - writel(cdb_shifted_phyaddr, ®->post_qbuffer[index]); + writel(shifted_cdb_phyaddr, ®->post_qbuffer[index]); } index++; index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ reg->postq_index = index; - writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg); + writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell); } break; } @@ -1103,7 +1144,7 @@ static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; - writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE @@ -1131,23 +1172,14 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { + dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); iounmap(acb->pmuA); - dma_free_coherent(&acb->pdev->dev, - ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, - acb->dma_coherent, - acb->dma_coherent_handle); - break; } + break; case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); - iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); - dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); + dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); } } - } void arcmsr_iop_message_read(struct AdapterControlBlock *acb) @@ -1161,7 +1193,7 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); } break; } @@ -1186,7 +1218,7 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) ** push inbound doorbell tell iop, driver data write ok ** and wait reply on next hwinterrupt for next Qbuffer post */ - writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg); + writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell); } break; } @@ -1206,7 +1238,7 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; - qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg; + qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; } break; } @@ -1227,7 +1259,7 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; - pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg; + pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; } break; } @@ -1362,7 +1394,7 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) struct MessageUnit_B *reg = acb->pmuB; /*clear interrupt and message state*/ - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); schedule_work(&acb->arcmsr_do_message_isr_bh); } static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) @@ -1394,16 +1426,16 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) uint32_t outbound_doorbell; struct MessageUnit_B *reg = acb->pmuB; - outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & + outbound_doorbell = readl(reg->iop2drv_doorbell) & acb->outbound_int_enable; if (!outbound_doorbell) return 1; - writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); + writel(~outbound_doorbell, reg->iop2drv_doorbell); /*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/ - readl(reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); + readl(reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } @@ -1523,12 +1555,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, goto message_out; } - if (!acb->fw_state) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; - } - ptmpQbuffer = ver_addr; while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) && (allxfer_len < 1031)) { @@ -1560,7 +1586,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, } memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; + if (acb->fw_flag == FW_DEADLOCK) { + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + } else { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + } kfree(ver_addr); } break; @@ -1575,12 +1605,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } - ptmpuserbuffer = ver_addr; user_len = pcmdmessagefld->cmdmessage.Length; memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); @@ -1633,12 +1664,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { uint8_t *pQbuffer = acb->rqbuffer; - if (!acb->fw_state) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; - } - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); @@ -1647,16 +1672,24 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->fw_flag == FW_DEADLOCK) { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; + } } break; case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { uint8_t *pQbuffer = acb->wqbuffer; - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { @@ -1669,18 +1702,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, acb->wqbuf_firstindex = 0; acb->wqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { uint8_t *pQbuffer; - if (!acb->fw_state) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; - } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; @@ -1698,47 +1724,52 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, memset(pQbuffer, 0, sizeof(struct QBUFFER)); pQbuffer = acb->wqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->fw_flag == FW_DEADLOCK) { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; + } } break; case ARCMSR_MESSAGE_RETURN_CODE_3F: { - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; - } - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_3F; } break; - + } case ARCMSR_MESSAGE_SAY_HELLO: { int8_t *hello_string = "Hello! I am ARCMSR"; - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; + } else { + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } memcpy(pcmdmessagefld->messagedatabuffer, hello_string , (int16_t)strlen(hello_string)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_SAY_GOODBYE: - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; } arcmsr_iop_parking(acb); break; case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: - if (!acb->fw_state) { + if (acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - goto message_out; } arcmsr_flush_adapter_cache(acb); break; @@ -1756,11 +1787,16 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock { struct list_head *head = &acb->ccb_free_list; struct CommandControlBlock *ccb = NULL; - + unsigned long flags; + spin_lock_irqsave(&acb->ccblist_lock, flags); if (!list_empty(head)) { ccb = list_entry(head->next, struct CommandControlBlock, list); - list_del(head->next); + list_del_init(&ccb->list); + } else { + spin_unlock_irqrestore(&acb->ccblist_lock, flags); + return 0; } + spin_unlock_irqrestore(&acb->ccblist_lock, flags); return ccb; } @@ -1835,66 +1871,12 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, return 0; } - if (acb->acb_flags & ACB_F_BUS_RESET) { - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t intmask_org, outbound_doorbell; - - if ((readl(®->outbound_msgaddr1) & - ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n", - acb->host->host_no); - return SCSI_MLQUEUE_HOST_BUSY; - } - - acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP; - printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n", - acb->host->host_no); - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_get_firmware_spec(acb, 1); - /*start background rebuild*/ - arcmsr_start_adapter_bgrb(acb); - /* clear Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - /*clear interrupt */ - writel(outbound_doorbell, ®->outbound_doorbell); - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); - /* enable outbound Post Queue,outbound doorbell Interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - acb->acb_flags |= ACB_F_IOP_INITED; - acb->acb_flags &= ~ACB_F_BUS_RESET; - } - break; - case ACB_ADAPTER_TYPE_B: { - } - } - } - if (target == 16) { /* virtual device for iop message transfer */ arcmsr_handle_virtual_command(acb, cmd); return 0; } - if (acb->devstate[target][lun] == ARECA_RAID_GONE) { - uint8_t block_cmd; - block_cmd = cmd->cmnd[0] & 0x0f; - if (block_cmd == 0x08 || block_cmd == 0x0a) { - printk(KERN_NOTICE - "arcmsr%d: block 'read/write'" - "command with gone raid volume" - " Cmd = %2x, TargetId = %d, Lun = %d \n" - , acb->host->host_no - , cmd->cmnd[0] - , target, lun); - cmd->result = (DID_NO_CONNECT << 16); - cmd->scsi_done(cmd); - return 0; - } - } if (atomic_read(&acb->ccboutstandingcount) >= ARCMSR_MAX_OUTSTANDING_CMD) return SCSI_MLQUEUE_HOST_BUSY; @@ -1911,7 +1893,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, return 0; } -static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode) +static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; char *acb_firm_model = acb->firm_model; @@ -1926,10 +1908,8 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode) if (arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); - return NULL; + return false; } - - if (mode == 1) { count = 8; while (count) { *acb_firm_model = readb(iop_firm_model); @@ -1953,53 +1933,68 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode) iop_device_map++; count--; } - - printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" - , acb->host->host_no - , acb->firm_version); + printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + acb->host->host_no, + acb->firm_version, + acb->firm_model); acb->signature = readl(®->message_rwbuffer[0]); acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); acb->firm_sdram_size = readl(®->message_rwbuffer[3]); acb->firm_hd_channels = readl(®->message_rwbuffer[4]); + acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ + return true; } - return reg->message_rwbuffer; -} -static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode) +static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; - uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg; + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle; char *acb_firm_model = acb->firm_model; char *acb_firm_version = acb->firm_version; char *acb_device_map = acb->device_map; - char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]); + char __iomem *iop_firm_model; /*firm_model,15,60-67*/ - char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]); + char __iomem *iop_firm_version; /*firm_version,17,68-83*/ - char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]); + char __iomem *iop_device_map; /*firm_version,21,84-99*/ int count; - - writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg); + dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL); + if (!dma_coherent) { + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no); + return false; + } + acb->dma_coherent_handle_hbb_mu = dma_coherent_handle; + reg = (struct MessageUnit_B *)dma_coherent; + acb->pmuB = reg; + reg->drv2iop_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); + reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK); + reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL); + reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK); + reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER); + reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER); + reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER); + iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); /*firm_model,15,60-67*/ + iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); /*firm_version,17,68-83*/ + iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); /*firm_version,21,84-99*/ + + writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); - return NULL; + return false; } - - if (mode == 1) { count = 8; - while (count) - { + while (count) { *acb_firm_model = readb(iop_firm_model); acb_firm_model++; iop_firm_model++; count--; } - count = 16; - while (count) - { + while (count) { *acb_firm_version = readb(iop_firm_version); acb_firm_version++; iop_firm_version++; @@ -2014,46 +2009,41 @@ static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int count--; } - printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", + printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", acb->host->host_no, - acb->firm_version); + acb->firm_version, + acb->firm_model); - acb->signature = readl(lrwbuffer++); + acb->signature = readl(®->message_rwbuffer[1]); /*firm_signature,1,00-03*/ - acb->firm_request_len = readl(lrwbuffer++); + acb->firm_request_len = readl(®->message_rwbuffer[2]); /*firm_request_len,1,04-07*/ - acb->firm_numbers_queue = readl(lrwbuffer++); + acb->firm_numbers_queue = readl(®->message_rwbuffer[3]); /*firm_numbers_queue,2,08-11*/ - acb->firm_sdram_size = readl(lrwbuffer++); + acb->firm_sdram_size = readl(®->message_rwbuffer[4]); /*firm_sdram_size,3,12-15*/ - acb->firm_hd_channels = readl(lrwbuffer); + acb->firm_hd_channels = readl(®->message_rwbuffer[5]); /*firm_ide_channels,4,16-19*/ + acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ + /*firm_ide_channels,4,16-19*/ + return true; } - return reg->msgcode_rwbuffer_reg; -} -static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode) +static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) { - void *rtnval = 0; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - rtnval = arcmsr_get_hba_config(acb, mode); - } - break; - - case ACB_ADAPTER_TYPE_B: { - rtnval = arcmsr_get_hbb_config(acb, mode); - } - break; - } - return rtnval; + if (acb->adapter_type == ACB_ADAPTER_TYPE_A) + return arcmsr_get_hba_config(acb); + else + return arcmsr_get_hbb_config(acb); } -static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, +static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_A __iomem *reg = acb->pmuA; struct CommandControlBlock *ccb; + struct ARCMSR_CDB *arcmsr_cdb; uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; + int rtn; polling_hba_ccb_retry: poll_count++; @@ -2061,16 +2051,19 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (1) { if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { - if (poll_ccb_done) + if (poll_ccb_done) { + rtn = SUCCESS; break; - else { - msleep(25); - if (poll_count > 100) + } else { + if (poll_count > 100) { + rtn = FAILED; break; + } goto polling_hba_ccb_retry; } } - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); + ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); poll_ccb_done = (ccb == poll_ccb) ? 1:0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { @@ -2081,8 +2074,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, , ccb->pcmd->device->lun , ccb); ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb, 1); - poll_ccb_done = 1; + arcmsr_ccb_complete(ccb); continue; } printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" @@ -2092,32 +2084,38 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, , ccb , atomic_read(&acb->ccboutstandingcount)); continue; - } + } else { arcmsr_report_ccb_state(acb, ccb, flag_ccb); } } + return rtn; +} -static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, +static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_B *reg = acb->pmuB; + struct ARCMSR_CDB *arcmsr_cdb; struct CommandControlBlock *ccb; uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; - int index; + int index, rtn; polling_hbb_ccb_retry: poll_count++; /* clear doorbell interrupt */ - writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); while (1) { index = reg->doneq_index; if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { - if (poll_ccb_done) + if (poll_ccb_done) { + rtn = SUCCESS; break; - else { + } else { msleep(25); - if (poll_count > 100) + if (poll_count > 100) { + rtn = FAILED; break; + } goto polling_hbb_ccb_retry; } } @@ -2127,19 +2125,19 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, index %= ARCMSR_MAX_HBB_POSTQUEUE; reg->doneq_index = index; /* check ifcommand done with no error*/ - ccb = (struct CommandControlBlock *)\ - (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); + ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); poll_ccb_done = (ccb == poll_ccb) ? 1:0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { - printk(KERN_NOTICE "arcmsr%d: \ - scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" + printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" + " poll command abort successfully \n" ,acb->host->host_no ,ccb->pcmd->device->id ,ccb->pcmd->device->lun ,ccb); ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); continue; } printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" @@ -2149,30 +2147,34 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, , ccb , atomic_read(&acb->ccboutstandingcount)); continue; - } + } else { arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } } /*drain reply FIFO*/ + return rtn; } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, +static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { + int rtn = 0; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - arcmsr_polling_hba_ccbdone(acb,poll_ccb); + rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb); } break; case ACB_ADAPTER_TYPE_B: { - arcmsr_polling_hbb_ccbdone(acb,poll_ccb); + rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb); } } + return rtn; } static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) { - uint32_t cdb_phyaddr, ccb_phyaddr_hi32; + uint32_t cdb_phyaddr, cdb_phyaddr_hi32; dma_addr_t dma_coherent_handle; /* ******************************************************************** @@ -2182,7 +2184,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) */ dma_coherent_handle = acb->dma_coherent_handle; cdb_phyaddr = (uint32_t)(dma_coherent_handle); - ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); + cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); /* *********************************************************************** ** if adapter type B, set window of "post command Q" @@ -2191,13 +2193,13 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - if (ccb_phyaddr_hi32 != 0) { + if (cdb_phyaddr_hi32 != 0) { struct MessageUnit_A __iomem *reg = acb->pmuA; uint32_t intmask_org; intmask_org = arcmsr_disable_outbound_ints(acb); writel(ARCMSR_SIGNATURE_SET_CONFIG, \ ®->message_rwbuffer[0]); - writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); + writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ ®->inbound_msgaddr0); if (arcmsr_hba_wait_msgint_ready(acb)) { @@ -2220,19 +2222,18 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) intmask_org = arcmsr_disable_outbound_ints(acb); reg->postq_index = 0; reg->doneq_index = 0; - writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ acb->host->host_no); return 1; } - post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \ - sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ; - rwbuffer = reg->msgcode_rwbuffer_reg; + post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu; + rwbuffer = reg->message_rwbuffer; /* driver "set config" signature */ writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); /* normal should be zero */ - writel(ccb_phyaddr_hi32, rwbuffer++); + writel(cdb_phyaddr_hi32, rwbuffer++); /* postQ size (256 + 8)*4 */ writel(post_queue_phyaddr, rwbuffer++); /* doneQ size (256 + 8)*4 */ @@ -2240,19 +2241,13 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) /* ccb maxQ size must be --> [(256 + 8)*4]*/ writel(1056, rwbuffer); - writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ timeout \n",acb->host->host_no); return 1; } - - writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg); - if (arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\ - ,acb->host->host_no); - return 1; - } + arcmsr_hbb_enable_driver_mode(acb); arcmsr_enable_outbound_ints(acb, intmask_org); } break; @@ -2277,9 +2272,9 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; do { - firmware_state = readl(reg->iop2drv_doorbell_reg); + firmware_state = readl(reg->iop2drv_doorbell); } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); } break; } @@ -2288,22 +2283,19 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; - - if (unlikely(atomic_read(&acb->rq_map_token) == 0)) { - acb->fw_state = false; + if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { + return; } else { - /*to prevent rq_map_token from changing by other interrupt, then - avoid the dead-lock*/ - acb->fw_state = true; - atomic_dec(&acb->rq_map_token); - if (!(acb->fw_state) || - (acb->ante_token_value == atomic_read(&acb->rq_map_token))) { + acb->fw_flag = FW_NORMAL; + if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { atomic_set(&acb->rq_map_token, 16); } - acb->ante_token_value = atomic_read(&acb->rq_map_token); + atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); + if (atomic_dec_and_test(&acb->rq_map_token)) + return; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); } - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000)); return; } @@ -2311,21 +2303,19 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_B __iomem *reg = acb->pmuB; - if (unlikely(atomic_read(&acb->rq_map_token) == 0)) { - acb->fw_state = false; + if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { + return; } else { - /*to prevent rq_map_token from changing by other interrupt, then - avoid the dead-lock*/ - acb->fw_state = true; - atomic_dec(&acb->rq_map_token); - if (!(acb->fw_state) || - (acb->ante_token_value == atomic_read(&acb->rq_map_token))) { + acb->fw_flag = FW_NORMAL; + if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { atomic_set(&acb->rq_map_token, 16); } - acb->ante_token_value = atomic_read(&acb->rq_map_token); - writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg); + atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); + if (atomic_dec_and_test(&acb->rq_map_token)) + return; + writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); } - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000)); return; } @@ -2360,7 +2350,7 @@ static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n",acb->host->host_no); @@ -2396,8 +2386,8 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; /*clear interrupt and message state*/ - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); /* let IOP know data has been read */ } break; @@ -2412,7 +2402,7 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); if(arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); return; @@ -2427,13 +2417,19 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) { uint8_t value[64]; int i; + struct MessageUnit_A __iomem *reg = acb->pmuA; /* backup pci config data */ + printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); for (i = 0; i < 64; i++) { pci_read_config_byte(acb->pdev, i, &value[i]); } /* hardware reset signal */ + if ((acb->dev_id == 0x1680)) { + writel(ARCMSR_ARC1680_BUS_RESET, ®->reserved1[0]); + } else { pci_write_config_byte(acb->pdev, 0x84, 0x20); + } msleep(1000); /* write back pci config data */ for (i = 0; i < 64; i++) { @@ -2446,37 +2442,25 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) **************************************************************************** **************************************************************************** */ -#ifdef CONFIG_SCSI_ARCMSR_RESET int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) { struct Scsi_Host *shost = NULL; - spinlock_t *host_lock = NULL; int i, isleep; shost = cmd->device->host; - host_lock = shost->host_lock; - - printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n", - shost->host_no, sleeptime, shost->host_busy, shost->can_queue); isleep = sleeptime / 10; - spin_unlock_irq(host_lock); if (isleep > 0) { for (i = 0; i < isleep; i++) { msleep(10000); - printk(KERN_NOTICE "^%d^\n", i); } } isleep = sleeptime % 10; if (isleep > 0) { msleep(isleep * 1000); - printk(KERN_NOTICE "^v^\n"); } - spin_lock_irq(host_lock); - printk(KERN_NOTICE "***** wake up *****\n"); return 0; } -#endif static void arcmsr_iop_init(struct AdapterControlBlock *acb) { uint32_t intmask_org; @@ -2485,7 +2469,6 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb) intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_wait_firmware_ready(acb); arcmsr_iop_confirm(acb); - arcmsr_get_firmware_spec(acb, 1); /*start background rebuild*/ arcmsr_start_adapter_bgrb(acb); /* empty doorbell Qbuffer if door bell ringed */ @@ -2508,14 +2491,12 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) intmask_org = arcmsr_disable_outbound_ints(acb); /* talk to iop 331 outstanding command aborted */ rtnval = arcmsr_abort_allcmd(acb); - /* wait for 3 sec for all command aborted*/ - ssleep(3); /* clear all outbound posted Q */ arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { - arcmsr_ccb_complete(ccb, 1); + arcmsr_ccb_complete(ccb); } } atomic_set(&acb->ccboutstandingcount, 0); @@ -2530,54 +2511,49 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) { struct AdapterControlBlock *acb = (struct AdapterControlBlock *)cmd->device->host->hostdata; - int retry = 0; - - if (acb->acb_flags & ACB_F_BUS_RESET) - return SUCCESS; + uint32_t intmask_org, outbound_doorbell; + int retry_count = 0; + int rtn = FAILED; - printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index); - acb->acb_flags |= ACB_F_BUS_RESET; + acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; + printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \ + num_aborts = %d \n", acb->num_resets, acb->num_aborts); acb->num_resets++; - while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) { - arcmsr_interrupt(acb); - retry++; - } - if (arcmsr_iop_reset(acb)) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n", - acb->adapter_index, acb->num_resets, acb->num_aborts); + if (acb->acb_flags & ACB_F_BUS_RESET) { + long timeout; + timeout = wait_event_timeout(wait_q, + (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); + if (timeout) { + return SUCCESS; + } + } + acb->acb_flags |= ACB_F_BUS_RESET; + if (arcmsr_iop_reset(acb)) { + struct MessageUnit_A __iomem *reg; + reg = acb->pmuA; arcmsr_hardware_reset(acb); - acb->acb_flags |= ACB_F_FIRMWARE_TRAP; acb->acb_flags &= ~ACB_F_IOP_INITED; - #ifdef CONFIG_SCSI_ARCMSR_RESET - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t intmask_org, outbound_doorbell; - int retry_count = 0; sleep_again: arcmsr_sleep_for_bus_reset(cmd); - if ((readl(®->outbound_msgaddr1) & - ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n", - acb->host->host_no, retry_count); + if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \ + retry=%d \n", acb->host->host_no, retry_count); if (retry_count > retrycount) { - printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n", - acb->host->host_no); - return SUCCESS; + acb->fw_flag = FW_DEADLOCK; + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \ + RETRY TERMINATED!! \n", acb->host->host_no); + return FAILED; } retry_count++; goto sleep_again; } - acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP; acb->acb_flags |= ACB_F_IOP_INITED; - acb->acb_flags &= ~ACB_F_BUS_RESET; - printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n", - acb->host->host_no); /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_get_firmware_spec(acb, 1); - /*start background rebuild*/ + arcmsr_get_firmware_spec(acb); arcmsr_start_adapter_bgrb(acb); /* clear Qbuffer if door bell ringed */ outbound_doorbell = readl(®->outbound_doorbell); @@ -2586,38 +2562,74 @@ sleep_again: /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + init_timer(&acb->eternal_timer); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); + acb->acb_flags &= ~ACB_F_BUS_RESET; + rtn = SUCCESS; + printk(KERN_ERR "arcmsr: scsi eh bus reset succeeds\n"); + } else { + acb->acb_flags &= ~ACB_F_BUS_RESET; + if (atomic_read(&acb->rq_map_token) == 0) { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); acb->eternal_timer.data = (unsigned long) acb; acb->eternal_timer.function = &arcmsr_request_device_map; add_timer(&acb->eternal_timer); - #endif + } else { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); } - break; - case ACB_ADAPTER_TYPE_B: { + rtn = SUCCESS; } + break; } + case ACB_ADAPTER_TYPE_B:{ + acb->acb_flags |= ACB_F_BUS_RESET; + if (arcmsr_iop_reset(acb)) { + acb->acb_flags &= ~ACB_F_BUS_RESET; + rtn = FAILED; } else { acb->acb_flags &= ~ACB_F_BUS_RESET; + if (atomic_read(&acb->rq_map_token) == 0) { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + init_timer(&acb->eternal_timer); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); + } else { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); + } + rtn = SUCCESS; } - return SUCCESS; + } + } + return rtn; } -static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, +static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - u32 intmask; - - ccb->startdone = ARCMSR_CCB_ABORTED; - - /* - ** Wait for 3 sec for all command done. - */ - ssleep(3); - - intmask = arcmsr_disable_outbound_ints(acb); - arcmsr_polling_ccbdone(acb, ccb); - arcmsr_enable_outbound_ints(acb, intmask); + int rtn; + spin_lock_irq(&acb->eh_lock); + rtn = arcmsr_polling_ccbdone(acb, ccb); + spin_unlock_irq(&acb->eh_lock); + return rtn; } static int arcmsr_abort(struct scsi_cmnd *cmd) @@ -2625,10 +2637,12 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) struct AdapterControlBlock *acb = (struct AdapterControlBlock *)cmd->device->host->hostdata; int i = 0; + int rtn = FAILED; printk(KERN_NOTICE "arcmsr%d: abort device command of scsi id = %d lun = %d \n", acb->host->host_no, cmd->device->id, cmd->device->lun); + acb->acb_flags |= ACB_F_ABORT; acb->num_aborts++; /* ************************************************ @@ -2637,17 +2651,18 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) ************************************************ */ if (!atomic_read(&acb->ccboutstandingcount)) - return SUCCESS; + return rtn; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { struct CommandControlBlock *ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { - arcmsr_abort_one_cmd(acb, ccb); + ccb->startdone = ARCMSR_CCB_ABORTED; + rtn = arcmsr_abort_one_cmd(acb, ccb); break; } } - - return SUCCESS; + acb->acb_flags &= ~ACB_F_ABORT; + return rtn; } static const char *arcmsr_info(struct Scsi_Host *host) -- cgit v1.2.3-70-g09d2 From 2e931f3176d61c693ace27498fdb823ef605e619 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:15 -0500 Subject: [SCSI] hpsa: add new controllers Add 5 CCISSE smart array controllers Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 1133b5fda0e..ec9b3a279f5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -86,6 +86,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254}, #define PCI_DEVICE_ID_HP_CISSF 0x333f {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -109,6 +114,11 @@ static struct board_type products[] = { {0x324b103C, "Smart Array P711m", &SA5_access}, {0x3233103C, "StorageWorks P1210m", &SA5_access}, {0x333F103C, "StorageWorks P1210m", &SA5_access}, + {0x3250103C, "Smart Array", &SA5_access}, + {0x3250113C, "Smart Array", &SA5_access}, + {0x3250123C, "Smart Array", &SA5_access}, + {0x3250133C, "Smart Array", &SA5_access}, + {0x3250143C, "Smart Array", &SA5_access}, {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; -- cgit v1.2.3-70-g09d2 From 6798cc0a4964ceabc27de762c41929f8a875e3fd Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:20 -0500 Subject: [SCSI] hpsa: Make "hpsa_allow_any=1" boot param enable Compaq Smart Arrays. We were previously only accepting HP boards. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ec9b3a279f5..25faaae324a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -95,6 +95,8 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, + {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} }; @@ -3293,7 +3295,9 @@ static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id) if (*board_id == products[i].board_id) return i; - if (subsystem_vendor_id != PCI_VENDOR_ID_HP || !hpsa_allow_any) { + if ((subsystem_vendor_id != PCI_VENDOR_ID_HP && + subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) || + !hpsa_allow_any) { dev_warn(&pdev->dev, "unrecognized board ID: " "0x%08x, ignoring.\n", *board_id); return -ENODEV; -- cgit v1.2.3-70-g09d2 From 12d2cd4711b9e3ddcf911281ec4fe511b5cfff63 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:25 -0500 Subject: [SCSI] hpsa: make hpsa_find_memory_BAR not require the per HBA structure. Rationale for this is that in order to fix the hard reset code used by kdump, we need to use this function before we even have the per HBA structure. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 25faaae324a..f5305a4b8b3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3313,20 +3313,20 @@ static inline bool hpsa_board_disabled(struct pci_dev *pdev) return ((command & PCI_COMMAND_MEMORY) == 0); } -static int __devinit hpsa_pci_find_memory_BAR(struct ctlr_info *h, +static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, unsigned long *memory_bar) { int i; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) - if (pci_resource_flags(h->pdev, i) & IORESOURCE_MEM) { + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { /* addressing mode bits already removed */ - *memory_bar = pci_resource_start(h->pdev, i); - dev_dbg(&h->pdev->dev, "memory BAR = %lx\n", + *memory_bar = pci_resource_start(pdev, i); + dev_dbg(&pdev->dev, "memory BAR = %lx\n", *memory_bar); return 0; } - dev_warn(&h->pdev->dev, "no memory BAR found\n"); + dev_warn(&pdev->dev, "no memory BAR found\n"); return -ENODEV; } @@ -3503,7 +3503,7 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) return err; } hpsa_interrupt_mode(h); - err = hpsa_pci_find_memory_BAR(h, &h->paddr); + err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); if (err) goto err_out_free_res; h->vaddr = remap_pci_mem(h->paddr, 0x250); -- cgit v1.2.3-70-g09d2 From a51fd47f1b8f2b9937011c433269d2ec182b9879 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:30 -0500 Subject: [SCSI] hpsa: factor out hpsa_find_cfg_addrs. Rationale for this is that I will also need to use this code in fixing kdump host reset code prior to having the hba structure. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f5305a4b8b3..44f81a0ae53 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3345,29 +3345,39 @@ static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h) return -ENODEV; } +static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, + void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, + u64 *cfg_offset) +{ + *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET); + *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET); + *cfg_base_addr &= (u32) 0x0000ffff; + *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr); + if (*cfg_base_addr_index == -1) { + dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n"); + return -ENODEV; + } + return 0; +} + static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) { u64 cfg_offset; u32 cfg_base_addr; u64 cfg_base_addr_index; u32 trans_offset; + int rc; - /* get the address index number */ - cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET); - cfg_base_addr &= (u32) 0x0000ffff; - cfg_base_addr_index = find_PCI_BAR_index(h->pdev, cfg_base_addr); - if (cfg_base_addr_index == -1) { - dev_warn(&h->pdev->dev, "cannot find cfg_base_addr_index\n"); - return -ENODEV; - } - cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET); + rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr, + &cfg_base_addr_index, &cfg_offset); + if (rc) + return rc; h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index) + cfg_offset, - sizeof(h->cfgtable)); + cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); if (!h->cfgtable) return -ENOMEM; /* Find performant mode table. */ - trans_offset = readl(&(h->cfgtable->TransMethodOffset)); + trans_offset = readl(&h->cfgtable->TransMethodOffset); h->transtable = remap_pci_mem(pci_resource_start(h->pdev, cfg_base_addr_index)+cfg_offset+trans_offset, sizeof(*h->transtable)); -- cgit v1.2.3-70-g09d2 From 4c2a8c40d877effc25774f00406a4a7df1967102 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:35 -0500 Subject: [SCSI] hpsa: factor out the code to reset controllers on driver load for kdump support Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 44f81a0ae53..b2f478596df 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3571,33 +3571,44 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h) } } +static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) +{ + int i; + + if (!reset_devices) + return 0; + + /* Reset the controller with a PCI power-cycle */ + if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev)) + return -ENODEV; + + /* Some devices (notably the HP Smart Array 5i Controller) + need a little pause here */ + msleep(HPSA_POST_RESET_PAUSE_MSECS); + + /* Now try to get the controller to respond to a no-op */ + for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { + if (hpsa_noop(pdev) == 0) + break; + else + dev_warn(&pdev->dev, "no-op failed%s\n", + (i < 11 ? "; re-trying" : "")); + } + return 0; +} + static int __devinit hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - int i, rc; - int dac; + int dac, rc; struct ctlr_info *h; if (number_of_controllers == 0) printk(KERN_INFO DRIVER_NAME "\n"); - if (reset_devices) { - /* Reset the controller with a PCI power-cycle */ - if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev)) - return -ENODEV; - - /* Some devices (notably the HP Smart Array 5i Controller) - need a little pause here */ - msleep(HPSA_POST_RESET_PAUSE_MSECS); - /* Now try to get the controller to respond to a no-op */ - for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { - if (hpsa_noop(pdev) == 0) - break; - else - dev_warn(&pdev->dev, "no-op failed%s\n", - (i < 11 ? "; re-trying" : "")); - } - } + rc = hpsa_init_reset_devices(pdev); + if (rc) + return rc; /* Command structures must be aligned on a 32-byte boundary because * the 5 lower bits of the address are used by the hardware. and by -- cgit v1.2.3-70-g09d2 From 1df8552abf36519ca8b9e2a8d1e204bac2076d51 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:40 -0500 Subject: [SCSI] hpsa: Fix hard reset code. Smart Array controllers newer than the P600 do not honor the PCI power state method of resetting the controllers. Instead, in these cases we can get them to reset via the "doorbell" register. This escaped notice until we began using "performant" mode because the fact that the controllers did not reset did not normally impede subsequent operation, and so things generally appeared to "work". Once the performant mode code was added, if the controller does not reset, it remains in performant mode. The code immediately after the reset presumes the controller is in "simple" mode (which previously, it had remained in simple mode the whole time). If the controller remains in performant mode any code which presumes it is in simple mode will not work. So the reset needs to be fixed. Unfortunately there are some controllers which cannot be reset by either method. (eg. p800). We detect these cases by noticing that the controller seems to remain in performant mode even after a reset has been attempted. In those case, we proceed anyway, as if the reset has happened (and skip the step of waiting for the controller to become ready -- which is expecting it to be in "simple" mode.) To sum up, we try to do a better job of resetting the controller if "reset_devices" is set, and if it doesn't work, we print a message and try to continue anyway. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 174 ++++++++++++++++++++++++++++++++++++------------ drivers/scsi/hpsa_cmd.h | 4 ++ 2 files changed, 137 insertions(+), 41 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index b2f478596df..f57d533f747 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -174,6 +174,11 @@ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, int *bucket_map); static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); static inline u32 next_command(struct ctlr_info *h); +static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, + void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, + u64 *cfg_offset); +static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, + unsigned long *memory_bar); static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); @@ -3078,17 +3083,75 @@ static __devinit int hpsa_reset_msi(struct pci_dev *pdev) return 0; } +static int hpsa_controller_hard_reset(struct pci_dev *pdev, + void * __iomem vaddr, bool use_doorbell) +{ + u16 pmcsr; + int pos; + + if (use_doorbell) { + /* For everything after the P600, the PCI power state method + * of resetting the controller doesn't work, so we have this + * other way using the doorbell register. + */ + dev_info(&pdev->dev, "using doorbell to reset controller\n"); + writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL); + msleep(1000); + } else { /* Try to do it the PCI power state way */ + + /* Quoting from the Open CISS Specification: "The Power + * Management Control/Status Register (CSR) controls the power + * state of the device. The normal operating state is D0, + * CSR=00h. The software off state is D3, CSR=03h. To reset + * the controller, place the interface device in D3 then to D0, + * this causes a secondary PCI reset which will reset the + * controller." */ + + pos = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pos == 0) { + dev_err(&pdev->dev, + "hpsa_reset_controller: " + "PCI PM not supported\n"); + return -ENODEV; + } + dev_info(&pdev->dev, "using PCI PM to reset controller\n"); + /* enter the D3hot power management state */ + pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= PCI_D3hot; + pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + msleep(500); + + /* enter the D0 power management state */ + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= PCI_D0; + pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + msleep(500); + } + return 0; +} + /* This does a hard reset of the controller using PCI power management - * states. + * states or the using the doorbell register. */ -static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev) +static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) { - u16 pmcsr, saved_config_space[32]; - int i, pos; + u16 saved_config_space[32]; + u64 cfg_offset; + u32 cfg_base_addr; + u64 cfg_base_addr_index; + void __iomem *vaddr; + unsigned long paddr; + u32 misc_fw_support, active_transport; + int rc, i; + struct CfgTable __iomem *cfgtable; + bool use_doorbell; - dev_info(&pdev->dev, "using PCI PM to reset controller\n"); - /* This is very nearly the same thing as + /* For controllers as old as the P600, this is very nearly + * the same thing as * * pci_save_state(pci_dev); * pci_set_power_state(pci_dev, PCI_D3hot); @@ -3102,41 +3165,42 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev) * violate the ordering requirements for restoring the * configuration space from the CCISS document (see the * comment below). So we roll our own .... + * + * For controllers newer than the P600, the pci power state + * method of resetting doesn't work so we have another way + * using the doorbell register. */ - for (i = 0; i < 32; i++) pci_read_config_word(pdev, 2*i, &saved_config_space[i]); - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos == 0) { - dev_err(&pdev->dev, - "hpsa_reset_controller: PCI PM not supported\n"); - return -ENODEV; - } - - /* Quoting from the Open CISS Specification: "The Power - * Management Control/Status Register (CSR) controls the power - * state of the device. The normal operating state is D0, - * CSR=00h. The software off state is D3, CSR=03h. To reset - * the controller, place the interface device in D3 then to - * D0, this causes a secondary PCI reset which will reset the - * controller." - */ - /* enter the D3hot power management state */ - pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D3hot; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + /* find the first memory BAR, so we can find the cfg table */ + rc = hpsa_pci_find_memory_BAR(pdev, &paddr); + if (rc) + return rc; + vaddr = remap_pci_mem(paddr, 0x250); + if (!vaddr) + return -ENOMEM; - msleep(500); + /* find cfgtable in order to check if reset via doorbell is supported */ + rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr, + &cfg_base_addr_index, &cfg_offset); + if (rc) + goto unmap_vaddr; + cfgtable = remap_pci_mem(pci_resource_start(pdev, + cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable)); + if (!cfgtable) { + rc = -ENOMEM; + goto unmap_vaddr; + } - /* enter the D0 power management state */ - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D0; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + /* If reset via doorbell register is supported, use that. */ + misc_fw_support = readl(&cfgtable->misc_fw_support); + use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; - msleep(500); + rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); + if (rc) + goto unmap_cfgtable; /* Restore the PCI configuration space. The Open CISS * Specification says, "Restore the PCI Configuration @@ -3153,7 +3217,29 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev) wmb(); pci_write_config_word(pdev, 4, saved_config_space[2]); - return 0; + /* Some devices (notably the HP Smart Array 5i Controller) + need a little pause here */ + msleep(HPSA_POST_RESET_PAUSE_MSECS); + + /* Controller should be in simple mode at this point. If it's not, + * It means we're on one of those controllers which doesn't support + * the doorbell reset method and on which the PCI power management reset + * method doesn't work (P800, for example.) + * In those cases, pretend the reset worked and hope for the best. + */ + active_transport = readl(&cfgtable->TransportActive); + if (active_transport & PERFORMANT_MODE) { + dev_warn(&pdev->dev, "Unable to successfully reset controller," + " proceeding anyway.\n"); + rc = -ENOTSUPP; + } + +unmap_cfgtable: + iounmap(cfgtable); + +unmap_vaddr: + iounmap(vaddr); + return rc; } /* @@ -3573,18 +3659,24 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h) static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) { - int i; + int rc, i; if (!reset_devices) return 0; - /* Reset the controller with a PCI power-cycle */ - if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev)) - return -ENODEV; + /* Reset the controller with a PCI power-cycle or via doorbell */ + rc = hpsa_kdump_hard_reset_controller(pdev); - /* Some devices (notably the HP Smart Array 5i Controller) - need a little pause here */ - msleep(HPSA_POST_RESET_PAUSE_MSECS); + /* -ENOTSUPP here means we cannot reset the controller + * but it's already (and still) up and running in + * "performant mode". + */ + if (rc == -ENOTSUPP) + return 0; /* just try to do the kdump anyhow. */ + if (rc) + return -ENODEV; + if (hpsa_reset_msi(pdev)) + return -ENODEV; /* Now try to get the controller to respond to a no-op */ for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 78de9b6d1e0..f5c4c3cc053 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -100,6 +100,7 @@ /* Configuration Table */ #define CFGTBL_ChangeReq 0x00000001l #define CFGTBL_AccCmds 0x00000001l +#define DOORBELL_CTLR_RESET 0x00000004l #define CFGTBL_Trans_Simple 0x00000002l #define CFGTBL_Trans_Performant 0x00000004l @@ -339,6 +340,9 @@ struct CfgTable { u32 MaxPhysicalDevices; u32 MaxPhysicalDrivesPerLogicalUnit; u32 MaxPerformantModeCommands; + u8 reserved[0x78 - 0x58]; + u32 misc_fw_support; /* offset 0x78 */ +#define MISC_FW_DOORBELL_RESET (0x02) }; #define NUM_BLOCKFETCH_ENTRIES 8 -- cgit v1.2.3-70-g09d2 From 1886765906686cdb08c35afae20e4ad8f82367f5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:45 -0500 Subject: [SCSI] hpsa: forbid hard reset of 640x boards The 6402/6404 are two PCI devices -- two Smart Array controllers -- that fit into one slot. It is possible to reset them independently, however, they share a battery backed cache module. One of the pair controls the cache and the 2nd one access the cache through the first one. If you reset the one controlling the cache, the other one will not be a happy camper. So we just forbid resetting this conjoined mess. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f57d533f747..d903cc690eb 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -179,6 +179,7 @@ static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, u64 *cfg_offset); static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, unsigned long *memory_bar); +static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); @@ -3148,7 +3149,7 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) int rc, i; struct CfgTable __iomem *cfgtable; bool use_doorbell; - + u32 board_id; /* For controllers as old as the P600, this is very nearly * the same thing as @@ -3170,6 +3171,18 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) * method of resetting doesn't work so we have another way * using the doorbell register. */ + + /* Exclude 640x boards. These are two pci devices in one slot + * which share a battery backed cache module. One controls the + * cache, the other accesses the cache through the one that controls + * it. If we reset the one controlling the cache, the other will + * likely not be happy. Just forbid resetting this conjoined mess. + * The 640x isn't really supported by hpsa anyway. + */ + hpsa_lookup_board_id(pdev, &board_id); + if (board_id == 0x409C0E11 || board_id == 0x409D0E11) + return -ENOTSUPP; + for (i = 0; i < 32; i++) pci_read_config_word(pdev, 2*i, &saved_config_space[i]); @@ -3669,7 +3682,8 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) /* -ENOTSUPP here means we cannot reset the controller * but it's already (and still) up and running in - * "performant mode". + * "performant mode". Or, it might be 640x, which can't reset + * due to concerns about shared bbwc between 6402/6404 pair. */ if (rc == -ENOTSUPP) return 0; /* just try to do the kdump anyhow. */ -- cgit v1.2.3-70-g09d2 From 10f66018088fd0c9fe81b1e328e3264c7b10caa5 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:50 -0500 Subject: [SCSI] hpsa: separate intx and msi/msix interrupt handlers There are things which need to be done in the intx interrupt handler which do not need to be done in the msi/msix interrupt handler, like checking that the interrupt is actually for us, and checking that the interrupt pending bit on the hardware is set (which we weren't previously doing at all, which means old controllers wouldn't work), so it makes sense to separate these into two functions. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index d903cc690eb..f8b614b591e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -126,7 +126,8 @@ static struct board_type products[] = { static int number_of_controllers; -static irqreturn_t do_hpsa_intr(int irq, void *dev_id); +static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); +static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); static void start_io(struct ctlr_info *h); @@ -2858,9 +2859,8 @@ static inline bool interrupt_pending(struct ctlr_info *h) static inline long interrupt_not_for_us(struct ctlr_info *h) { - return !(h->msi_vector || h->msix_vector) && - ((h->access.intr_pending(h) == 0) || - (h->interrupts_enabled == 0)); + return (h->access.intr_pending(h) == 0) || + (h->interrupts_enabled == 0); } static inline int bad_tag(struct ctlr_info *h, u32 tag_index, @@ -2934,7 +2934,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h, return next_command(h); } -static irqreturn_t do_hpsa_intr(int irq, void *dev_id) +static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) { struct ctlr_info *h = dev_id; unsigned long flags; @@ -2942,6 +2942,26 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id) if (interrupt_not_for_us(h)) return IRQ_NONE; + spin_lock_irqsave(&h->lock, flags); + while (interrupt_pending(h)) { + raw_tag = get_next_completion(h); + while (raw_tag != FIFO_EMPTY) { + if (hpsa_tag_contains_index(raw_tag)) + raw_tag = process_indexed_cmd(h, raw_tag); + else + raw_tag = process_nonindexed_cmd(h, raw_tag); + } + } + spin_unlock_irqrestore(&h->lock, flags); + return IRQ_HANDLED; +} + +static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id) +{ + struct ctlr_info *h = dev_id; + unsigned long flags; + u32 raw_tag; + spin_lock_irqsave(&h->lock, flags); raw_tag = get_next_completion(h); while (raw_tag != FIFO_EMPTY) { @@ -3754,8 +3774,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev, /* make sure the board interrupts are off */ h->access.set_intr_mask(h, HPSA_INTR_OFF); - rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr, - IRQF_DISABLED, h->devname, h); + + if (h->msix_vector || h->msi_vector) + rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi, + IRQF_DISABLED, h->devname, h); + else + rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx, + IRQF_DISABLED, h->devname, h); if (rc) { dev_err(&pdev->dev, "unable to get irq %d for %s\n", h->intr[PERF_MODE_INT], h->devname); -- cgit v1.2.3-70-g09d2 From cba3d38b6cf85bd91b7c6f65f43863d1fd19259c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Wed, 16 Jun 2010 13:51:56 -0500 Subject: [SCSI] hpsa: sanitize max commands Some controllers might try to tell us they support 0 commands in performant mode. This is a lie told by buggy firmware. We have to be wary of this lest we try to allocate a negative number of command blocks, which will be treated as unsigned, and get an out of memory condition. Signed-off-by: Stephen M. Cameron Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index f8b614b591e..4f5551b5fe5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3505,13 +3505,25 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) return 0; } +static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) +{ + h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); + if (h->max_commands < 16) { + dev_warn(&h->pdev->dev, "Controller reports " + "max supported commands of %d, an obvious lie. " + "Using 16. Ensure that firmware is up to date.\n", + h->max_commands); + h->max_commands = 16; + } +} + /* Interrogate the hardware for some limits: * max commands, max SG elements without chaining, and with chaining, * SG chain block size, etc. */ static void __devinit hpsa_find_board_params(struct ctlr_info *h) { - h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); + hpsa_get_max_perf_mode_cmds(h); h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); /* @@ -4056,7 +4068,7 @@ static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) if (!(trans_support & PERFORMANT_MODE)) return; - h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); + hpsa_get_max_perf_mode_cmds(h); h->max_sg_entries = 32; /* Performant mode ring buffer and supporting data structures */ h->reply_pool_size = h->max_commands * sizeof(u64); -- cgit v1.2.3-70-g09d2 From 593d5720745658a4a973952fb74f6d863c531e97 Mon Sep 17 00:00:00 2001 From: Karen Xie Date: Wed, 16 Jun 2010 17:10:37 -0700 Subject: [SCSI] cxgb3i: zero out reserved or un-used fields. Zero out the reserved or un-used CPL message fields to prevent any garbage value. Signed-off-by: Karen Xie Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/cxgb3i/cxgb3i_ddp.c | 2 ++ drivers/scsi/cxgb3i/cxgb3i_offload.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index b58d9134ac1..be0e23042c7 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c @@ -499,6 +499,7 @@ static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx, /* set up ulp submode and page size */ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); req->reply = V_NO_REPLY(reply ? 0 : 1); req->cpu_idx = 0; @@ -564,6 +565,7 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid, /* set up ulp submode and page size */ req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); req->reply = V_NO_REPLY(reply ? 0 : 1); req->cpu_idx = 0; diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c index a175be9c496..246a6c246ed 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_offload.c +++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c @@ -264,6 +264,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, skb->priority = CPL_PRIORITY_SETUP; req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid)); req->local_port = c3cn->saddr.sin_port; req->peer_port = c3cn->daddr.sin_port; @@ -273,6 +274,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb, V_TX_CHANNEL(e->smt_idx)); req->opt0l = htonl(calc_opt0l(c3cn)); req->params = 0; + req->opt2 = 0; } static void fail_act_open(struct s3_conn *c3cn, int errno) @@ -379,6 +381,7 @@ static void send_abort_req(struct s3_conn *c3cn) c3cn->cpl_abort_req = NULL; req = (struct cpl_abort_req *)skb->head; + memset(req, 0, sizeof(*req)); skb->priority = CPL_PRIORITY_DATA; set_arp_failure_handler(skb, abort_arp_failure); @@ -406,6 +409,7 @@ static void send_abort_rpl(struct s3_conn *c3cn, int rst_status) c3cn->cpl_abort_rpl = NULL; skb->priority = CPL_PRIORITY_DATA; + memset(rpl, 0, sizeof(*rpl)); rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid)); OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid)); @@ -430,6 +434,7 @@ static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack) req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req)); req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + req->wr.wr_lo = 0; OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid)); req->credit_dack = htonl(dack | V_RX_CREDITS(credits)); skb->priority = CPL_PRIORITY_ACK; -- cgit v1.2.3-70-g09d2 From ab6ce92541ea24c6a92be8498d7d1b26c14ec62d Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:25:13 +0530 Subject: [SCSI] mpt2sas: Fix to use sas device list instead of enclosure list for _transpor_get_enclosure_identifier. Enclosure_identifier not being returned by mpt2sas The driver exports callback function to the sas transport layer for obtaining the enclosure logical id. This function is called _transport_get_enclosure_identifier. The driver was searching the wrong list for the enclosure_identifier. The driver should be searching the sas device list instead of enclosure list. The sas address that is passed to the driver is for the end device, not enclosure. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_transport.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 2727c3b6510..778e149f963 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1007,18 +1007,18 @@ static int _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); - struct _sas_node *sas_expander; + struct _sas_device *sas_device; unsigned long flags; - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, rphy->identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_expander) + if (!sas_device) return -ENXIO; - *identifier = sas_expander->enclosure_logical_id; + *identifier = sas_device->enclosure_logical_id; return 0; } -- cgit v1.2.3-70-g09d2 From d274213a1ae59e8abde8d43e1e3a478fe9f28794 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:28:55 +0530 Subject: [SCSI] mpt2sas: Hold Controller reset when another reset is in progress Driver should not allow multiple host reset when already host reset is in progress. It is possible that host reset was sent by scsi mid layer while there was already an host reset active, either issued via IOCTL interface or internaly, like a config page timeout. Since there was a host reset active, the driver would return a FAILED response to the scsi mid layer. The solution is make sure pending host resets will wait for the active host reset to complete before returning control back up the call stack. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 29 ++++++++++++++++++++++------- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 ++++ drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1 + 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 0ec1ed389c2..f0c0df4278d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3804,7 +3804,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) return; /* wait for pending commands to complete */ - wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ); + wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); } /** @@ -3828,13 +3828,24 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if (mpt2sas_fwfault_debug) mpt2sas_halt_firmware(ioc); - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) { - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: busy\n", - ioc->name, __func__); - return -EBUSY; + /* TODO - What we really should be doing is pulling + * out all the code associated with NO_SLEEP; its never used. + * That is legacy code from mpt fusion driver, ported over. + * I will leave this BUG_ON here for now till its been resolved. + */ + BUG_ON(sleep_flag == NO_SLEEP); + + /* wait for an active reset in progress to complete */ + if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { + do { + ssleep(1); + } while (ioc->shost_recovery == 1); + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name, + __func__)); + return ioc->ioc_reset_in_progress_status; } + + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); ioc->shost_recovery = 1; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); @@ -3853,9 +3864,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); + ioc->ioc_reset_in_progress_status = r; ioc->shost_recovery = 0; complete(&ioc->shost_recovery_done); spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); + mutex_unlock(&ioc->reset_in_progress_mutex); + dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name, + __func__)); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 0f41fcd4e52..6032cbf31c7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -600,9 +600,13 @@ struct MPT2SAS_ADAPTER { int aen_event_read_flag; u8 broadcast_aen_busy; u8 shost_recovery; + + struct mutex reset_in_progress_mutex; struct completion shost_recovery_done; spinlock_t ioc_reset_in_progress_lock; u8 ioc_link_reset_in_progress; + int ioc_reset_in_progress_status; + u8 ignore_loginfos; u8 remove_host; u8 wait_for_port_enable_to_complete; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 456ea7c3b09..9ce22530393 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -6557,6 +6557,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; ioc->logging_level = logging_level; /* misc semaphores and spin locks */ + mutex_init(&ioc->reset_in_progress_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); spin_lock_init(&ioc->scsi_lookup_lock); spin_lock_init(&ioc->sas_device_lock); -- cgit v1.2.3-70-g09d2 From dd5fd3323abcb799d4d81f3c4b3e2a5fcbfce7bf Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:31:17 +0530 Subject: [SCSI] mpt2sas: staged device discovery. disable_discovery module parameter is added. Added command line option called disable_discovery. When enabled on the command line, the driver will not send a port_enable when loaded for the first time. If port_enable is not called, then there is no discovery of devices, as well as the sas topology. Then later if one desires to invoke discovery, then they will need to issue a diagnostic reset. A diagnostic reset can be issued various ways. One of the way is throught sysfs. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index f0c0df4278d..68cb000bf48 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -95,6 +95,10 @@ int mpt2sas_fwfault_debug; MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " "and halt firmware - (default=0)"); +static int disable_discovery = -1; +module_param(disable_discovery, int, 0); +MODULE_PARM_DESC(disable_discovery, " disable discovery "); + /** * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. * @@ -3520,6 +3524,9 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); + if (ioc->wait_for_port_enable_to_complete && disable_discovery > 0) + return r; + r = _base_send_port_enable(ioc, sleep_flag); if (r) return r; -- cgit v1.2.3-70-g09d2 From d5f491e65851627358b2c1a4e322681b17539550 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:32:54 +0530 Subject: [SCSI] mpt2sas: Added expander phy counter support Added support to retrieve the invalid_dword_count, running_disparity_error_count, loss_of_dword_sync_count, and phy_reset_problem_count for expanders. This will be exported to attributes within the sas transport layer. A new wrapper function was added for sending SMP passthru to retrieve the expander phy error log. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_transport.c | 242 +++++++++++++++++++++++++++++-- 1 file changed, 233 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 778e149f963..a96501fdba0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -951,11 +951,229 @@ _transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy) return NULL; } +/* report phy error log structure */ +struct phy_error_log_request{ + u8 smp_frame_type; /* 0x40 */ + u8 function; /* 0x11 */ + u8 allocated_response_length; + u8 request_length; /* 02 */ + u8 reserved_1[5]; + u8 phy_identifier; + u8 reserved_2[2]; +}; + +/* report phy error log reply structure */ +struct phy_error_log_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x11 */ + u8 function_result; + u8 response_length; + u16 expander_change_count; + u8 reserved_1[3]; + u8 phy_identifier; + u8 reserved_2[2]; + u32 invalid_dword; + u32 running_disparity_error; + u32 loss_of_dword_sync; + u32 phy_reset_problem; +}; + /** - * _transport_get_linkerrors - + * _transport_get_expander_phy_error_log - return expander counters + * @ioc: per adapter object + * @phy: The sas phy object + * + * Returns 0 for success, non-zero for failure. + * + */ +static int +_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, + struct sas_phy *phy) +{ + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + struct phy_error_log_request *phy_error_log_request; + struct phy_error_log_reply *phy_error_log_reply; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + void *data_out = NULL; + dma_addr_t data_out_dma; + u32 sz; + u64 *sas_address_le; + u16 wait_state_count; + + if (ioc->shost_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + + mutex_lock(&ioc->transport_cmds.mutex); + + if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + ioc->transport_cmds.status = MPT2_CMD_PENDING; + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + sz = sizeof(struct phy_error_log_request) + + sizeof(struct phy_error_log_reply); + data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + rc = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + rc = -EINVAL; + memset(data_out, 0, sz); + phy_error_log_request = data_out; + phy_error_log_request->smp_frame_type = 0x40; + phy_error_log_request->function = 0x11; + phy_error_log_request->request_length = 2; + phy_error_log_request->allocated_response_length = 0; + phy_error_log_request->phy_identifier = phy->number; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct phy_error_log_request)); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_error_log_request), data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_error_log_reply), data_out_dma + + sizeof(struct phy_error_log_request)); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " + "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, + (unsigned long long)phy->identify.sas_address, phy->number)); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); + timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, + 10*HZ); + + if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SmpPassthroughRequest_t)/4); + if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " + "complete\n", ioc->name)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - reply data transfer size(%d)\n", + ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + + if (le16_to_cpu(mpi_reply->ResponseDataLength) != + sizeof(struct phy_error_log_reply)) + goto out; + + phy_error_log_reply = data_out + + sizeof(struct phy_error_log_request); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - function_result(%d)\n", + ioc->name, phy_error_log_reply->function_result)); + + phy->invalid_dword_count = + be32_to_cpu(phy_error_log_reply->invalid_dword); + phy->running_disparity_error_count = + be32_to_cpu(phy_error_log_reply->running_disparity_error); + phy->loss_of_dword_sync_count = + be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); + phy->phy_reset_problem_count = + be32_to_cpu(phy_error_log_reply->phy_reset_problem); + rc = 0; + } else + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_error_log - no reply\n", ioc->name)); + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + out: + ioc->transport_cmds.status = MPT2_CMD_NOT_USED; + if (data_out) + pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); + + mutex_unlock(&ioc->transport_cmds.mutex); + return rc; +} + +/** + * _transport_get_linkerrors - return phy counters for both hba and expanders * @phy: The sas phy object * - * Only support sas_host direct attached phys. * Returns 0 for success, non-zero for failure. * */ @@ -963,17 +1181,24 @@ static int _transport_get_linkerrors(struct sas_phy *phy) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - struct _sas_phy *mpt2sas_phy; + unsigned long flags; Mpi2ConfigReply_t mpi_reply; Mpi2SasPhyPage1_t phy_pg1; - mpt2sas_phy = _transport_find_local_phy(ioc, phy); - - if (!mpt2sas_phy) /* this phy not on sas_host */ + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_get_expander_phy_error_log(ioc, phy); + /* get hba phy error logs */ if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, - mpt2sas_phy->phy_id))) { + phy->number))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); return -ENXIO; @@ -982,8 +1207,7 @@ _transport_get_linkerrors(struct sas_phy *phy) if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" "(0x%04x), loginfo(0x%08x)\n", ioc->name, - mpt2sas_phy->phy_id, - le16_to_cpu(mpi_reply.IOCStatus), + phy->number, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); -- cgit v1.2.3-70-g09d2 From b8d7d7bb37b5e25ea740369eb12de5279fe6ab30 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:34:31 +0530 Subject: [SCSI] mpt2sas: Added expander phy control support Added support to send link resets, hard resets, enable/disable phys, and changing link rates for for expanders. This will be exported to attributes within the sas transport layer. A new wrapper function was added for sending SMP passthru to expanders for phy control. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_transport.c | 305 ++++++++++++++++++++++++++++--- 1 file changed, 275 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index a96501fdba0..6c94deeb7be 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -940,16 +940,6 @@ rphy_to_ioc(struct sas_rphy *rphy) return shost_priv(shost); } -static struct _sas_phy * -_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy) -{ - int i; - - for (i = 0; i < ioc->sas_hba.num_phys; i++) - if (ioc->sas_hba.phy[i].phy == phy) - return(&ioc->sas_hba.phy[i]); - return NULL; -} /* report phy error log structure */ struct phy_error_log_request{ @@ -1270,32 +1260,260 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) return sas_device->slot; } +/* phy control request structure */ +struct phy_control_request{ + u8 smp_frame_type; /* 0x40 */ + u8 function; /* 0x91 */ + u8 allocated_response_length; + u8 request_length; /* 0x09 */ + u16 expander_change_count; + u8 reserved_1[3]; + u8 phy_identifier; + u8 phy_operation; + u8 reserved_2[13]; + u64 attached_device_name; + u8 programmed_min_physical_link_rate; + u8 programmed_max_physical_link_rate; + u8 reserved_3[6]; +}; + +/* phy control reply structure */ +struct phy_control_reply{ + u8 smp_frame_type; /* 0x41 */ + u8 function; /* 0x11 */ + u8 function_result; + u8 response_length; +}; + +#define SMP_PHY_CONTROL_LINK_RESET (0x01) +#define SMP_PHY_CONTROL_HARD_RESET (0x02) +#define SMP_PHY_CONTROL_DISABLE (0x03) + +/** + * _transport_expander_phy_control - expander phy control + * @ioc: per adapter object + * @phy: The sas phy object + * + * Returns 0 for success, non-zero for failure. + * + */ +static int +_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, + struct sas_phy *phy, u8 phy_operation) +{ + Mpi2SmpPassthroughRequest_t *mpi_request; + Mpi2SmpPassthroughReply_t *mpi_reply; + struct phy_control_request *phy_control_request; + struct phy_control_reply *phy_control_reply; + int rc; + u16 smid; + u32 ioc_state; + unsigned long timeleft; + void *psge; + u32 sgl_flags; + u8 issue_reset = 0; + void *data_out = NULL; + dma_addr_t data_out_dma; + u32 sz; + u64 *sas_address_le; + u16 wait_state_count; + + if (ioc->shost_recovery) { + printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", + __func__, ioc->name); + return -EFAULT; + } + + mutex_lock(&ioc->transport_cmds.mutex); + + if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { + printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + ioc->transport_cmds.status = MPT2_CMD_PENDING; + + wait_state_count = 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { + if (wait_state_count++ == 10) { + printk(MPT2SAS_ERR_FMT + "%s: failed due to ioc not operational\n", + ioc->name, __func__); + rc = -EFAULT; + goto out; + } + ssleep(1); + ioc_state = mpt2sas_base_get_iocstate(ioc, 1); + printk(MPT2SAS_INFO_FMT "%s: waiting for " + "operational state(count=%d)\n", ioc->name, + __func__, wait_state_count); + } + if (wait_state_count) + printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", + ioc->name, __func__); + + smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + rc = -EAGAIN; + goto out; + } + + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + ioc->transport_cmds.smid = smid; + + sz = sizeof(struct phy_control_request) + + sizeof(struct phy_control_reply); + data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); + if (!data_out) { + printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + rc = -ENOMEM; + mpt2sas_base_free_smid(ioc, smid); + goto out; + } + + rc = -EINVAL; + memset(data_out, 0, sz); + phy_control_request = data_out; + phy_control_request->smp_frame_type = 0x40; + phy_control_request->function = 0x91; + phy_control_request->request_length = 9; + phy_control_request->allocated_response_length = 0; + phy_control_request->phy_identifier = phy->number; + phy_control_request->phy_operation = phy_operation; + phy_control_request->programmed_min_physical_link_rate = + phy->minimum_linkrate << 4; + phy_control_request->programmed_max_physical_link_rate = + phy->maximum_linkrate << 4; + + memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; + mpi_request->PhysicalPort = 0xFF; + mpi_request->VF_ID = 0; /* TODO */ + mpi_request->VP_ID = 0; + sas_address_le = (u64 *)&mpi_request->SASAddress; + *sas_address_le = cpu_to_le64(phy->identify.sas_address); + mpi_request->RequestDataLength = + cpu_to_le16(sizeof(struct phy_error_log_request)); + psge = &mpi_request->SGL; + + /* WRITE sgel first */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_control_request), data_out_dma); + + /* incr sgel */ + psge += ioc->sge_size; + + /* READ sgel last */ + sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | + MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | + MPI2_SGE_FLAGS_END_OF_LIST); + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + ioc->base_add_sg_single(psge, sgl_flags | + sizeof(struct phy_control_reply), data_out_dma + + sizeof(struct phy_control_request)); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " + "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, + (unsigned long long)phy->identify.sas_address, phy->number, + phy_operation)); + mpt2sas_base_put_smid_default(ioc, smid); + init_completion(&ioc->transport_cmds.done); + timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, + 10*HZ); + + if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { + printk(MPT2SAS_ERR_FMT "%s: timeout\n", + ioc->name, __func__); + _debug_dump_mf(mpi_request, + sizeof(Mpi2SmpPassthroughRequest_t)/4); + if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) + issue_reset = 1; + goto issue_host_reset; + } + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " + "complete\n", ioc->name)); + + if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { + + mpi_reply = ioc->transport_cmds.reply; + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - reply data transfer size(%d)\n", + ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); + + if (le16_to_cpu(mpi_reply->ResponseDataLength) != + sizeof(struct phy_control_reply)) + goto out; + + phy_control_reply = data_out + + sizeof(struct phy_control_request); + + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - function_result(%d)\n", + ioc->name, phy_control_reply->function_result)); + + rc = 0; + } else + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT + "phy_control - no reply\n", ioc->name)); + + issue_host_reset: + if (issue_reset) + mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, + FORCE_BIG_HAMMER); + out: + ioc->transport_cmds.status = MPT2_CMD_NOT_USED; + if (data_out) + pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); + + mutex_unlock(&ioc->transport_cmds.mutex); + return rc; +} + /** * _transport_phy_reset - * @phy: The sas phy object * @hard_reset: * - * Only support sas_host direct attached phys. * Returns 0 for success, non-zero for failure. */ static int _transport_phy_reset(struct sas_phy *phy, int hard_reset) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - struct _sas_phy *mpt2sas_phy; Mpi2SasIoUnitControlReply_t mpi_reply; Mpi2SasIoUnitControlRequest_t mpi_request; + unsigned long flags; - mpt2sas_phy = _transport_find_local_phy(ioc, phy); - - if (!mpt2sas_phy) /* this phy not on sas_host */ + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_expander_phy_control(ioc, phy, + (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : + SMP_PHY_CONTROL_LINK_RESET); + + /* handle hba phys */ memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request.Operation = hard_reset ? MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; - mpi_request.PhyNum = mpt2sas_phy->phy_id; + mpi_request.PhyNum = phy->number; if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", @@ -1306,8 +1524,7 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset) if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" "(0x%04x), loginfo(0x%08x)\n", ioc->name, - mpt2sas_phy->phy_id, - le16_to_cpu(mpi_reply.IOCStatus), + phy->number, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo)); return 0; @@ -1325,17 +1542,28 @@ static int _transport_phy_enable(struct sas_phy *phy, int enable) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - struct _sas_phy *mpt2sas_phy; Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; u16 sz; int rc = 0; + unsigned long flags; - mpt2sas_phy = _transport_find_local_phy(ioc, phy); - - if (!mpt2sas_phy) /* this phy not on sas_host */ + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); + + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) + return _transport_expander_phy_control(ioc, phy, + (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : + SMP_PHY_CONTROL_DISABLE); + + /* handle hba phys */ /* sas_iounit page 1 */ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * @@ -1364,14 +1592,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable) } if (enable) - sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + sas_iounit_pg1->PhyData[phy->number].PhyFlags &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; else - sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags + sas_iounit_pg1->PhyData[phy->number].PhyFlags |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); + /* link reset */ + if (enable) + _transport_phy_reset(phy, 0); + out: kfree(sas_iounit_pg1); return rc; @@ -1389,7 +1621,6 @@ static int _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) { struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - struct _sas_phy *mpt2sas_phy; Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; Mpi2SasPhyPage0_t phy_pg0; Mpi2ConfigReply_t mpi_reply; @@ -1397,11 +1628,15 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) u16 sz; int i; int rc = 0; + unsigned long flags; - mpt2sas_phy = _transport_find_local_phy(ioc, phy); - - if (!mpt2sas_phy) /* this phy not on sas_host */ + spin_lock_irqsave(&ioc->sas_node_lock, flags); + if (_transport_sas_node_find_by_sas_address(ioc, + phy->identify.sas_address) == NULL) { + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); return -EINVAL; + } + spin_unlock_irqrestore(&ioc->sas_node_lock, flags); if (!rates->minimum_linkrate) rates->minimum_linkrate = phy->minimum_linkrate; @@ -1413,6 +1648,16 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) rates->maximum_linkrate = phy->maximum_linkrate_hw; + /* handle expander phys */ + if (phy->identify.sas_address != ioc->sas_hba.sas_address) { + phy->minimum_linkrate = rates->minimum_linkrate; + phy->maximum_linkrate = rates->maximum_linkrate; + return _transport_expander_phy_control(ioc, phy, + SMP_PHY_CONTROL_LINK_RESET); + } + + /* handle hba phys */ + /* sas_iounit page 1 */ sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit1PhyData_t)); @@ -1440,7 +1685,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) } for (i = 0; i < ioc->sas_hba.num_phys; i++) { - if (mpt2sas_phy->phy_id != i) { + if (phy->number != i) { sas_iounit_pg1->PhyData[i].MaxMinLinkRate = (ioc->sas_hba.phy[i].phy->minimum_linkrate + (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); @@ -1464,7 +1709,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) /* read phy page 0, then update the rates in the sas transport phy */ if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - mpt2sas_phy->phy_id)) { + phy->number)) { phy->minimum_linkrate = _transport_convert_phy_link_rate( phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); phy->maximum_linkrate = _transport_convert_phy_link_rate( -- cgit v1.2.3-70-g09d2 From d32a8c15e1116e87f0105356eca1afb99842ab49 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:36:53 +0530 Subject: [SCSI] mpt2sas: Added sysfs counter for ioc reset Added a new sysfs shost attribute called ioc_reset_count. This will keep count of host resets (both diagnostic and message unit). Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 9 +++++++-- drivers/scsi/mpt2sas/mpt2sas_base.h | 1 + drivers/scsi/mpt2sas/mpt2sas_ctl.c | 24 ++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 68cb000bf48..88befc79846 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3402,6 +3402,7 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, enum reset_type type) { u32 ioc_state; + int rc; dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, __func__)); @@ -3430,11 +3431,15 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) if (!(_base_send_ioc_reset(ioc, - MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) + MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { + ioc->ioc_reset_count++; return 0; + } issue_diag_reset: - return _base_diag_reset(ioc, CAN_SLEEP); + rc = _base_diag_reset(ioc, CAN_SLEEP); + ioc->ioc_reset_count++; + return rc; } /** diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 6032cbf31c7..a4a73152922 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -615,6 +615,7 @@ struct MPT2SAS_ADAPTER { u16 msix_vector_count; u32 *msix_table; u32 *msix_table_backup; + u32 ioc_reset_count; /* internal commands, callback index */ u8 scsi_io_cb_idx; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index d88e9756d8f..25c866e3e90 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -2581,6 +2581,29 @@ _ctl_fwfault_debug_store(struct device *cdev, static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); + +/** + * _ctl_ioc_reset_count_show - ioc reset count + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is firmware queue depth limit + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); +} +static DEVICE_ATTR(ioc_reset_count, S_IRUGO, + _ctl_ioc_reset_count_show, NULL); + + struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_version_fw, &dev_attr_version_bios, @@ -2597,6 +2620,7 @@ struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_fwfault_debug, &dev_attr_fw_queue_depth, &dev_attr_host_sas_address, + &dev_attr_ioc_reset_count, NULL, }; -- cgit v1.2.3-70-g09d2 From 203d65b16cfef448dbfb79f66b672be4511fc6a9 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:37:59 +0530 Subject: [SCSI] mpt2sas: MPI header version N is updated. Updating MPI header version N. Removed mpi_history.txt. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpi/mpi2.h | 17 ++- drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 193 +++++++++++++++++++++++++++++++---- drivers/scsi/mpt2sas/mpi/mpi2_init.h | 17 +-- drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 119 ++++++++++++++++++++- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 7 +- 5 files changed, 308 insertions(+), 45 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h index dada0a13223..4b1c2f0350f 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.14 + * mpi2.h Version: 02.00.15 * * Version History * --------------- @@ -57,6 +57,10 @@ * Added MSI-x index mask and shift for Reply Post Host * Index register. * Added function code for Host Based Discovery Action. + * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. + * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. + * Added defines for product-specific range of message + * function codes, 0xF0 to 0xFF. * -------------------------------------------------------------------------- */ @@ -82,7 +86,7 @@ #define MPI2_VERSION_02_00 (0x0200) /* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x0E) +#define MPI2_HEADER_VERSION_UNIT (0x0F) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) @@ -473,8 +477,6 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION /***************************************************************************** * * Message Functions -* 0x80 -> 0x8F reserved for private message use per product -* * *****************************************************************************/ @@ -506,6 +508,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION #define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ /* Host Based Discovery Action */ #define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) +/* Power Management Control */ +#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) +/* beginning of product-specific range */ +#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) +/* end of product-specific range */ +#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) + diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h index d4e9d6f8452..e3728d736d8 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.13 + * mpi2_cnfg.h Version: 02.00.14 * * Version History * --------------- @@ -109,6 +109,18 @@ * Added Ethernet configuration pages. * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. * Added SAS PHY Page 4 structure and defines. + * 02-10-10 02.00.14 Modified the comments for the configuration page + * structures that contain an array of data. The host + * should use the "count" field in the page data (e.g. the + * NumPhys field) to determine the number of valid elements + * in the array. + * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. + * Added PowerManagementCapabilities to IO Unit Page 7. + * Added PortWidthModGroup field to + * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. + * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. * -------------------------------------------------------------------------- */ @@ -373,8 +385,9 @@ typedef struct _MPI2_CONFIG_REPLY #define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) #define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) #define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086) -#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087) +#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) +#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) +#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) /* Manufacturing Page 0 */ @@ -540,7 +553,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES #define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) @@ -618,7 +631,7 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX #define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) @@ -731,7 +744,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. + * one and check the value returned for GPIOCount at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) @@ -760,7 +773,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 /* * Upper layer code (drivers, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumDmaEngines at runtime. + * one and check the value returned for NumDmaEngines at runtime. */ #ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES #define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) @@ -823,7 +836,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { U8 PCIeWidth; /* 0x06 */ U8 PCIeSpeed; /* 0x07 */ U32 ProcessorState; /* 0x08 */ - U32 Reserved2; /* 0x0C */ + U32 PowerManagementCapabilities; /* 0x0C */ U16 IOCTemperature; /* 0x10 */ U8 IOCTemperatureUnits; /* 0x12 */ U8 IOCSpeed; /* 0x13 */ @@ -831,7 +844,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { } MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00) +#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01) /* defines for IO Unit Page 7 PCIeWidth field */ #define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) @@ -852,6 +865,14 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { #define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) #define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) +/* defines for IO Unit Page 7 PowerManagementCapabilities field */ +#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) +#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) +#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) +#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) + + /* defines for IO Unit Page 7 IOCTemperatureUnits field */ #define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) #define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) @@ -1195,7 +1216,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES #define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) @@ -1269,7 +1290,7 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. + * one and check the value returned for NumPhysDisks at runtime. */ #ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX #define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) @@ -1471,7 +1492,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength or NumPhysDiskPaths at runtime. + * one and check the value returned for NumPhysDiskPaths at runtime. */ #ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX #define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) @@ -1633,7 +1654,7 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT0_PHY_MAX #define MPI2_SAS_IOUNIT0_PHY_MAX (1) @@ -1704,7 +1725,7 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT1_PHY_MAX #define MPI2_SAS_IOUNIT1_PHY_MAX (1) @@ -1795,7 +1816,7 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * four and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT4_PHY_MAX #define MPI2_SAS_IOUNIT4_PHY_MAX (4) @@ -1833,7 +1854,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { U8 ControlFlags; /* 0x00 */ - U8 Reserved1; /* 0x01 */ + U8 PortWidthModGroup; /* 0x01 */ U16 InactivityTimerExponent; /* 0x02 */ U8 SATAPartialTimeout; /* 0x04 */ U8 Reserved2; /* 0x05 */ @@ -1853,6 +1874,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { #define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) #define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) +/* defines for PortWidthModeGroup field */ +#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) + /* defines for InactivityTimerExponent field */ #define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) #define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) @@ -1874,7 +1898,7 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumPhys at runtime. */ #ifndef MPI2_SAS_IOUNIT5_PHY_MAX #define MPI2_SAS_IOUNIT5_PHY_MAX (1) @@ -1892,7 +1916,132 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; -#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00) +#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) + + +/* SAS IO Unit Page 6 */ + +typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { + U8 CurrentStatus; /* 0x00 */ + U8 CurrentModulation; /* 0x01 */ + U8 CurrentUtilization; /* 0x02 */ + U8 Reserved1; /* 0x03 */ + U32 Reserved2; /* 0x04 */ +} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, + Mpi2SasIOUnit6PortWidthModGroupStatus_t, + MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; + +/* defines for CurrentStatus field */ +#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) +#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) +#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) +#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) +#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) +#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) +#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) + +/* defines for CurrentModulation field */ +#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) +#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) +#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) +#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX +#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 Reserved2; /* 0x0C */ + U8 NumGroups; /* 0x10 */ + U8 Reserved3; /* 0x11 */ + U16 Reserved4; /* 0x12 */ + MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS + PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_6, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, + Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; + +#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 7 */ + +typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { + U8 Flags; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U8 Threshold75Pct; /* 0x04 */ + U8 Threshold50Pct; /* 0x05 */ + U8 Threshold25Pct; /* 0x06 */ + U8 Reserved3; /* 0x07 */ +} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, + Mpi2SasIOUnit7PortWidthModGroupSettings_t, + MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; + +/* defines for Flags field */ +#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) + + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check the value returned for NumGroups at runtime. + */ +#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX +#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) +#endif + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U8 SamplingInterval; /* 0x08 */ + U8 WindowLength; /* 0x09 */ + U16 Reserved1; /* 0x0A */ + U32 Reserved2; /* 0x0C */ + U32 Reserved3; /* 0x10 */ + U8 NumGroups; /* 0x14 */ + U8 Reserved4; /* 0x15 */ + U16 Reserved5; /* 0x16 */ + MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS + PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_7, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, + Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; + +#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) + + +/* SAS IO Unit Page 8 */ + +typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { + MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ + U32 Reserved1; /* 0x08 */ + U32 PowerManagementCapabilities;/* 0x0C */ + U32 Reserved2; /* 0x10 */ +} MPI2_CONFIG_PAGE_SASIOUNIT_8, + MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, + Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; + +#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) + +/* defines for PowerManagementCapabilities field */ +#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800) +#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200) +#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100) +#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002) +#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001) @@ -2182,7 +2331,7 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT { /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhyEvents at runtime. + * one and check the value returned for NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY2_PHY_EVENT_MAX #define MPI2_SASPHY2_PHY_EVENT_MAX (1) @@ -2274,7 +2423,7 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhyEvents at runtime. + * one and check the value returned for NumPhyEvents at runtime. */ #ifndef MPI2_SASPHY3_PHY_EVENT_MAX #define MPI2_SASPHY3_PHY_EVENT_MAX (1) @@ -2385,7 +2534,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumLogEntries at runtime. */ #ifndef MPI2_LOG_0_NUM_LOG_ENTRIES #define MPI2_LOG_0_NUM_LOG_ENTRIES (1) @@ -2435,7 +2584,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.ExtPageLength or NumPhys at runtime. + * one and check the value returned for NumElements at runtime. */ #ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS #define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 220bf65a921..c4c99dfcb82 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -6,7 +6,7 @@ * Title: MPI SCSI initiator mode messages and structures * Creation Date: June 23, 2006 * - * mpi2_init.h Version: 02.00.08 + * mpi2_init.h Version: 02.00.09 * * Version History * --------------- @@ -31,6 +31,7 @@ * both SCSI IO Error Reply and SCSI Task Management Reply. * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. + * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. * -------------------------------------------------------------------------- */ @@ -57,20 +58,6 @@ typedef struct } MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; -/* TBD: I don't think this is needed for MPI2/Gen2 */ -#if 0 -typedef struct -{ - U8 CDB[16]; /* 0x00 */ - U32 DataLength; /* 0x10 */ - U32 PrimaryReferenceTag; /* 0x14 */ - U16 PrimaryApplicationTag; /* 0x18 */ - U16 PrimaryApplicationTagMask; /* 0x1A */ - U32 TransferLength; /* 0x1C */ -} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16, - Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t; -#endif - typedef union { U8 CDB32[32]; diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h index f18f114922b..495bedc4d1f 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.13 + * mpi2_ioc.h Version: 02.00.14 * * Version History * --------------- @@ -98,6 +98,9 @@ * (MPI2_FW_HEADER_PID_). * Modified values for SAS ProductID Family * (MPI2_FW_HEADER_PID_FAMILY_). + * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. + * Added PowerManagementControl Request structures and + * defines. * -------------------------------------------------------------------------- */ @@ -469,6 +472,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY #define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) #define MPI2_EVENT_GPIO_INTERRUPT (0x0023) #define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) +#define MPI2_EVENT_SAS_QUIESCE (0x0025) /* Log Entry Added Event data */ @@ -895,6 +899,22 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { * */ +/* SAS Quiesce Event data */ + +typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { + U8 ReasonCode; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U16 Reserved2; /* 0x02 */ + U32 Reserved3; /* 0x04 */ +} MPI2_EVENT_DATA_SAS_QUIESCE, + MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, + Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; + +/* SAS Quiesce Event data ReasonCode values */ +#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) +#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) + + /* Host Based Discovery Phy Event data */ typedef struct _MPI2_EVENT_HBD_PHY_SAS { @@ -1006,6 +1026,7 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) #define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) #define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) +#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) #define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) /* FWDownload TransactionContext Element */ @@ -1183,7 +1204,6 @@ typedef struct _MPI2_FW_IMAGE_HEADER #define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI2_FW_HEADER_PID_PROD_A (0x0000) -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) #define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) @@ -1407,5 +1427,100 @@ typedef struct _MPI2_INIT_IMAGE_FOOTER #define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) +/**************************************************************************** +* PowerManagementControl message +****************************************************************************/ + +/* PowerManagementControl Request message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 ChainOffset; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U8 Parameter1; /* 0x0C */ + U8 Parameter2; /* 0x0D */ + U8 Parameter3; /* 0x0E */ + U8 Parameter4; /* 0x0F */ + U32 Reserved5; /* 0x10 */ + U32 Reserved6; /* 0x14 */ +} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, + Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; + +/* defines for the Feature field */ +#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) +#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) +#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) +#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) +#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ +/* Parameter1 contains a PHY number */ +/* Parameter2 indicates power condition action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) +#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) +#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION + * Feature */ +/* Parameter1 contains SAS port width modulation group number */ +/* Parameter2 indicates IOC action using these defines */ +#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) +#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) +#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) +/* Parameter3 indicates desired modulation level using these defines */ +#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) +#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) +#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) +#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) +/* Parameter4 is reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ +/* Parameter1 indicates desired PCIe link speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) +#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) +#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) +/* Parameter2 indicates desired PCIe link width using these defines */ +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) +#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) +/* Parameter3 and Parameter4 are reserved */ + +/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ +/* Parameter1 indicates desired IOC hardware clock speed using these defines */ +#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) +#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) +#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) +#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) +/* Parameter2, Parameter3, and Parameter4 are reserved */ + + +/* PowerManagementControl Reply message */ +typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { + U8 Feature; /* 0x00 */ + U8 Reserved1; /* 0x01 */ + U8 MsgLength; /* 0x02 */ + U8 Function; /* 0x03 */ + U16 Reserved2; /* 0x04 */ + U8 Reserved3; /* 0x06 */ + U8 MsgFlags; /* 0x07 */ + U8 VP_ID; /* 0x08 */ + U8 VF_ID; /* 0x09 */ + U16 Reserved4; /* 0x0A */ + U16 Reserved5; /* 0x0C */ + U16 IOCStatus; /* 0x0E */ + U32 IOCLogInfo; /* 0x10 */ +} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, + Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; + + #endif diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 9ce22530393..87c686525f0 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -223,9 +223,12 @@ static struct pci_device_id scsih_pci_table[] = { PCI_ANY_ID, PCI_ANY_ID }, { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7, + /* Mustang ~ 2308 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_8, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; -- cgit v1.2.3-70-g09d2 From 570c67ac443dab5c46e5744e950f0539724cb65d Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:43:17 +0530 Subject: [SCSI] mpt2sas: Added sysfs support for trace buffer Added support so the diag ring buffer can be pulled via sysfs Added three new shost attributes: host_trace_buffer, host_trace_buffer_enable, and host_trace_buffer_size. The host_trace_buffer_enable attribute is used to either post or release the trace buffers. The host_trace_buffer_size attribute contains the size of the trace buffer. The host_trace_buffer atttribute contains a maximum 4KB window of the buffer. In order to read the entire host buffer, you will need to write the offset to host_trace_buffer prior to reading it. release the host buffer, then write the entire host buffer contents to a file. In addition to this enhancement, we moved the automatic posting of host buffers at driver load time to be called prior to port_enable, instead of after. That way discovery is available in the host buffer. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 10 +- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 + drivers/scsi/mpt2sas/mpt2sas_ctl.c | 192 ++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 88befc79846..93c06239d95 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3529,8 +3529,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (sleep_flag == CAN_SLEEP) _base_static_config_pages(ioc); - if (ioc->wait_for_port_enable_to_complete && disable_discovery > 0) - return r; + if (ioc->wait_for_port_enable_to_complete) { + if (diag_buffer_enable != 0) + mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); + if (disable_discovery > 0) + return r; + } r = _base_send_port_enable(ioc, sleep_flag); if (r) @@ -3679,8 +3683,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; mpt2sas_base_start_watchdog(ioc); - if (diag_buffer_enable != 0) - mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); return 0; out_free_resources: diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index a4a73152922..ffe93984e56 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -750,6 +750,8 @@ struct MPT2SAS_ADAPTER { Mpi2ManufacturingPage10_t manu_pg10; u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; + u32 ring_buffer_offset; + u32 ring_buffer_sz; }; typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 25c866e3e90..371f063a926 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -2603,6 +2603,195 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); +struct DIAG_BUFFER_START { + u32 Size; + u32 DiagVersion; + u8 BufferType; + u8 Reserved[3]; + u32 Reserved1; + u32 Reserved2; + u32 Reserved3; +}; +/** + * _ctl_host_trace_buffer_size_show - host buffer size (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_host_trace_buffer_size_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + u32 size = 0; + struct DIAG_BUFFER_START *request_data; + + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + request_data = (struct DIAG_BUFFER_START *) + ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; + if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || + le32_to_cpu(request_data->DiagVersion) == 0x01000000) && + le32_to_cpu(request_data->Reserved3) == 0x4742444c) + size = le32_to_cpu(request_data->Size); + + ioc->ring_buffer_sz = size; + return snprintf(buf, PAGE_SIZE, "%d\n", size); +} +static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, + _ctl_host_trace_buffer_size_show, NULL); + +/** + * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * You will only be able to read 4k bytes of ring buffer at a time. + * In order to read beyond 4k bytes, you will have to write out the + * offset to the same attribute, it will move the pointer. + */ +static ssize_t +_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + void *request_data; + u32 size; + + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { + printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " + "registered\n", ioc->name, __func__); + return 0; + } + + if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) + return 0; + + size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; + size = (size > PAGE_SIZE) ? PAGE_SIZE : size; + request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; + memcpy(buf, request_data, size); + return size; +} + +static ssize_t +_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + ioc->ring_buffer_offset = val; + return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, + _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); + +/*****************************************/ + +/** + * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read/write' shost attribute. + * + * This is a mechnism to post/release host_trace_buffers + */ +static ssize_t +_ctl_host_trace_buffer_enable_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + + if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || + ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) + return snprintf(buf, PAGE_SIZE, "off\n"); + else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED)) + return snprintf(buf, PAGE_SIZE, "release\n"); + else + return snprintf(buf, PAGE_SIZE, "post\n"); +} + +static ssize_t +_ctl_host_trace_buffer_enable_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); + char str[10] = ""; + struct mpt2_diag_register diag_register; + u8 issue_reset = 0; + + if (sscanf(buf, "%s", str) != 1) + return -EINVAL; + + if (!strcmp(str, "post")) { + /* exit out if host buffers are already posted */ + if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && + (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) && + ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) + goto out; + memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); + printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", + ioc->name); + diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; + diag_register.requested_buffer_size = (1024 * 1024); + diag_register.unique_id = 0x7075900; + ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; + _ctl_diag_register_2(ioc, &diag_register); + } else if (!strcmp(str, "release")) { + /* exit out if host buffers are already released */ + if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) + goto out; + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) + goto out; + if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT2_DIAG_BUFFER_IS_RELEASED)) + goto out; + printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", + ioc->name); + _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); + } + + out: + return strlen(buf); +} +static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, + _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_version_fw, @@ -2621,6 +2810,9 @@ struct device_attribute *mpt2sas_host_attrs[] = { &dev_attr_fw_queue_depth, &dev_attr_host_sas_address, &dev_attr_ioc_reset_count, + &dev_attr_host_trace_buffer_size, + &dev_attr_host_trace_buffer, + &dev_attr_host_trace_buffer_enable, NULL, }; -- cgit v1.2.3-70-g09d2 From eabb08ad2d3b0257cd2c9aed4f106fb39d14604a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:43:57 +0530 Subject: [SCSI] mpt2sas: print level KERN_DEBUG is replaced by KERN_INFO Converting print level from MPT2SAS_DEBUG_FMT to MPT2SAS_INFO_FMT. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 82 ++++++++++++++++---------------- drivers/scsi/mpt2sas/mpt2sas_base.h | 1 - drivers/scsi/mpt2sas/mpt2sas_config.c | 4 +- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 68 +++++++++++++------------- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 56 +++++++++++----------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 16 +++---- 6 files changed, 113 insertions(+), 114 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 93c06239d95..3774b0742b2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1242,7 +1242,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) u64 pio_chip = 0; u64 chip_phys = 0; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); @@ -1865,7 +1865,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) static void _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) { - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); if (ioc->request) { @@ -1951,7 +1951,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u32 retry_sz; u16 max_request_credit; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); retry_sz = 0; @@ -2378,7 +2378,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, do { int_status = readl(&ioc->chip->HostInterruptStatus); if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2419,7 +2419,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, do { int_status = readl(&ioc->chip->HostInterruptStatus); if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2467,7 +2467,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, do { doorbell_reg = readl(&ioc->chip->Doorbell); if (!(doorbell_reg & MPI2_DOORBELL_USED)) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "successfull count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; @@ -2641,9 +2641,9 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, if (ioc->logging_level & MPT_DEBUG_INIT) { mfp = (u32 *)reply; - printk(KERN_DEBUG "\toffset:data\n"); + printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < reply_bytes/4; i++) - printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, le32_to_cpu(mfp[i])); } return 0; @@ -2676,7 +2676,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mutex_lock(&ioc->base_cmds.mutex); @@ -2781,7 +2781,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, void *request; u16 wait_state_count; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mutex_lock(&ioc->base_cmds.mutex); @@ -2869,7 +2869,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) Mpi2PortFactsReply_t mpi_reply, *pfacts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); @@ -2911,7 +2911,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) Mpi2IOCFactsReply_t mpi_reply, *facts; int mpi_reply_sz, mpi_request_sz, r; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); @@ -2983,7 +2983,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) struct timeval current_time; u16 ioc_status; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); @@ -3044,9 +3044,9 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) int i; mfp = (u32 *)&mpi_request; - printk(KERN_DEBUG "\toffset:data\n"); + printk(KERN_INFO "\toffset:data\n"); for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) - printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4, + printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, le32_to_cpu(mfp[i])); } @@ -3125,7 +3125,7 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) r = -ETIME; goto out; } else - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", ioc->name, __func__)); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL, @@ -3185,7 +3185,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) int r = 0; int i; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); if (ioc->base_cmds.status & MPT2_CMD_PENDING) { @@ -3223,7 +3223,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) else r = -ETIME; } else - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n", + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", ioc->name, __func__)); ioc->base_cmds.status = MPT2_CMD_NOT_USED; return r; @@ -3285,7 +3285,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) _base_save_msix_table(ioc); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", ioc->name)); count = 0; @@ -3293,7 +3293,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) /* Write magic sequence to WriteSequence register * Loop until in diagnostic mode */ - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic " "sequence\n", ioc->name)); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); @@ -3313,7 +3313,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) goto out; host_diagnostic = readl(&ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic " "sequence: count(%d), host_diagnostic(0x%08x)\n", ioc->name, count, host_diagnostic)); @@ -3321,7 +3321,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) hcb_size = readl(&ioc->chip->HCBSize); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n", ioc->name)); writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, &ioc->chip->HostDiagnostic); @@ -3348,29 +3348,29 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter " "assuming the HCB Address points to good F/W\n", ioc->name)); host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; writel(host_diagnostic, &ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "re-enable the HCDW\n", ioc->name)); writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, &ioc->chip->HCBSize); } - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter\n", + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n", ioc->name)); writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, &ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "disable writes to the " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the " "diagnostic register\n", ioc->name)); writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "Wait for FW to go to the " + drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the " "READY state\n", ioc->name)); ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, sleep_flag); @@ -3404,18 +3404,18 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, u32 ioc_state; int rc; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n", + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", ioc->name, __func__, ioc_state)); if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) return 0; if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); goto issue_diag_reset; } @@ -3458,7 +3458,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u16 smid; struct _tr_list *delayed_tr, *delayed_tr_next; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); /* clean the delayed target reset list */ @@ -3554,7 +3554,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) { struct pci_dev *pdev = ioc->pdev; - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); _base_mask_interrupts(ioc); @@ -3587,7 +3587,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) { int r, i; - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); r = mpt2sas_base_map_resources(ioc); @@ -3719,7 +3719,7 @@ void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) { - dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); mpt2sas_base_stop_watchdog(ioc); @@ -3752,11 +3752,11 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) { switch (reset_phase) { case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); break; case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { ioc->transport_cmds.status |= MPT2_CMD_RESET; @@ -3776,7 +3776,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } break; case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); break; } @@ -3836,7 +3836,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, int r; unsigned long flags; - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); if (mpt2sas_fwfault_debug) @@ -3854,7 +3854,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, do { ssleep(1); } while (ioc->shost_recovery == 1); - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, __func__)); return ioc->ioc_reset_in_progress_status; } @@ -3874,7 +3874,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, if (!r) _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); out: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n", + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n", ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); @@ -3884,7 +3884,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); mutex_unlock(&ioc->reset_in_progress_mutex); - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: exit\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, __func__)); return r; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index ffe93984e56..08404b331f7 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -124,7 +124,6 @@ * logging format */ #define MPT2SAS_FMT "%s: " -#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT #define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT #define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT #define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index c65442982d7..e26f9206a52 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -159,7 +159,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), " + printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), " "smid(%d)\n", ioc->name, calling_function_name, desc, mpi_request->Header.PageNumber, mpi_request->Action, le32_to_cpu(mpi_request->PageAddress), smid); @@ -168,7 +168,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, return; if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_DEBUG_FMT + printk(MPT2SAS_INFO_FMT "\tiocstatus(0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 371f063a926..55fbd5b69b8 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -188,14 +188,14 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, if (!desc) return; - printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n", + printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n", ioc->name, calling_function_name, desc, smid); if (!mpi_reply) return; if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_DEBUG_FMT + printk(MPT2SAS_INFO_FMT "\tiocstatus(0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); @@ -206,7 +206,7 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, Mpi2SCSIIOReply_t *scsi_reply = (Mpi2SCSIIOReply_t *)mpi_reply; if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - printk(MPT2SAS_DEBUG_FMT + printk(MPT2SAS_INFO_FMT "\tscsi_state(0x%02x), scsi_status" "(0x%02x)\n", ioc->name, scsi_reply->SCSIState, @@ -392,7 +392,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) switch (reset_phase) { case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { if (!(ioc->diag_buffer_status[i] & @@ -405,7 +405,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } break; case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { ioc->ctl_cmds.status |= MPT2_CMD_RESET; @@ -414,7 +414,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) } break; case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { @@ -531,7 +531,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); if (!found) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, desc, le16_to_cpu(tm_request->DevHandle), lun)); tm_reply = ioc->ctl_cmds.reply; @@ -549,7 +549,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, return 1; } - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, desc, le16_to_cpu(tm_request->DevHandle), lun, le16_to_cpu(tm_request->TaskMID))); @@ -756,7 +756,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, Mpi2SCSITaskManagementRequest_t *tm_request = (Mpi2SCSITaskManagementRequest_t *)mpi_request; - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " "handle(0x%04x), task_type(0x%02x)\n", ioc->name, le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); @@ -851,7 +851,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, Mpi2SCSITaskManagementReply_t *tm_reply = (Mpi2SCSITaskManagementReply_t *)mpi_reply; - printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: " + printk(MPT2SAS_INFO_FMT "TASK_MGMT: " "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " "TerminationCount(0x%08x)\n", ioc->name, le16_to_cpu(tm_reply->IOCStatus), @@ -950,7 +950,7 @@ _ctl_getiocinfo(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); memset(&karg, 0 , sizeof(karg)); @@ -998,7 +998,7 @@ _ctl_eventquery(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; @@ -1031,7 +1031,7 @@ _ctl_eventenable(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); if (ioc->event_log) @@ -1073,7 +1073,7 @@ _ctl_eventreport(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); number_bytes = karg.hdr.max_data_size - @@ -1118,7 +1118,7 @@ _ctl_do_reset(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, @@ -1219,7 +1219,7 @@ _ctl_btdh_mapping(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); rc = _ctl_btdh_search_sas_device(ioc, &karg); @@ -1288,7 +1288,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, u16 ioc_status; u8 issue_reset = 0; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { @@ -1376,7 +1376,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, mpi_request->VF_ID = 0; /* TODO */ mpi_request->VP_ID = 0; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), " "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, (unsigned long long)request_data_dma, le32_to_cpu(mpi_request->BufferLength))); @@ -1414,10 +1414,10 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; @@ -1541,7 +1541,7 @@ _ctl_diag_unregister(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1611,7 +1611,7 @@ _ctl_diag_query(void __user *arg) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); karg.application_flags = 0; @@ -1689,7 +1689,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) int rc; unsigned long timeleft; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); rc = 0; @@ -1697,7 +1697,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) ioc_state = mpt2sas_base_get_iocstate(ioc, 1); if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "skipping due to FAULT state\n", ioc->name, __func__)); rc = -EAGAIN; @@ -1759,10 +1759,10 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT2_DIAG_BUFFER_IS_RELEASED; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; @@ -1800,7 +1800,7 @@ _ctl_diag_release(void __user *arg, enum block_state state) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1896,7 +1896,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name, + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); buffer_type = karg.unique_id & 0x000000ff; @@ -1927,7 +1927,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) } diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); @@ -1942,11 +1942,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) return 0; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister " "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); if ((ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "buffer_type(0x%02x) is still registered\n", ioc->name, __func__, buffer_type)); return 0; @@ -2020,10 +2020,10 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n", + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", ioc->name, __func__)); } else { - printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) " + printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " "log_info(0x%08x)\n", ioc->name, __func__, ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); rc = -EFAULT; @@ -2140,7 +2140,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !ioc) return -ENODEV; - dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); break; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 87c686525f0..82c2d4c5ece 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -435,7 +435,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.ReqBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: req_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -450,7 +450,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.ReqAltBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.RequestedAltBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: req_alt_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -465,7 +465,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, (ioc->bios_pg2.CurrentBootDeviceForm & MPI2_BIOSPAGE2_FORM_MASK), &ioc->bios_pg2.CurrentBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: current_boot_device(0x%016llx)\n", ioc->name, __func__, (unsigned long long)sas_address)); @@ -566,7 +566,7 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); @@ -593,7 +593,7 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); @@ -695,7 +695,7 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, { unsigned long flags; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle" + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, raid_device->handle, (unsigned long long)raid_device->wwid)); @@ -2002,7 +2002,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, ioc_state = mpt2sas_base_get_iocstate(ioc, 0); if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell " + dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " "active!\n", ioc->name)); mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); @@ -2806,7 +2806,7 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { if (le16_to_cpu(local_event_data->ExpanderDevHandle) == expander_handle) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting ignoring flag\n", ioc->name)); fw_event->ignore = 1; } @@ -4347,9 +4347,9 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, status_str = "unknown status"; break; } - printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n", + printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n", ioc->name, status_str); - printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) " + printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) " "start_phy(%02d), count(%d)\n", le16_to_cpu(event_data->ExpanderDevHandle), le16_to_cpu(event_data->EnclosureHandle), @@ -4383,7 +4383,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, } link_rate = event_data->PHY[i].LinkRate >> 4; prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:" + printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:" " link rate: new(0x%02x), old(0x%02x)\n", phy_number, handle, status_str, link_rate, prev_link_rate); @@ -4427,7 +4427,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, _scsih_sas_host_refresh(ioc); if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander " "event\n", ioc->name)); return; } @@ -4453,7 +4453,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, /* handle siblings events */ for (i = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring " "expander event\n", ioc->name)); return; } @@ -4573,12 +4573,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, reason_str = "unknown reason"; break; } - printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n" + printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" "\thandle(0x%04x), sas address(0x%016llx)", ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), (unsigned long long)le64_to_cpu(event_data->SASAddress)); if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, + printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, event_data->ASC, event_data->ASCQ); printk(KERN_INFO "\n"); } @@ -4662,7 +4662,7 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, break; } - printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n" + printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n" "\thandle(0x%04x), enclosure logical id(0x%016llx)" " number slots(%d)\n", ioc->name, reason_str, le16_to_cpu(event_data->EnclosureHandle), @@ -4713,10 +4713,10 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; #endif u16 ioc_status; - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: " "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, event_data->PortWidth)); - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name, + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); termination_count = 0; @@ -4760,7 +4760,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, } ioc->broadcast_aen_busy = 0; - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - exit, query_count = %d termination_count = %d\n", ioc->name, __func__, query_count, termination_count)); } @@ -4781,7 +4781,7 @@ _scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, #ifdef CONFIG_SCSI_MPT2SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name, + printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name, (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? "start" : "stop"); if (event_data->DiscoveryStatus) @@ -5075,7 +5075,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n", + printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n", ioc->name, (le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? "foreign" : "native", event_data->NumElements); @@ -5128,7 +5128,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, element_str = "unknown element"; break; } - printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), " + printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), " "pd handle(0x%04x), pd num(0x%02x)\n", element_str, reason_str, le16_to_cpu(element->VolDevHandle), le16_to_cpu(element->PhysDiskDevHandle), @@ -5218,7 +5218,7 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); @@ -5306,7 +5306,7 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); @@ -5494,7 +5494,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work } if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL) - starget_printk(KERN_DEBUG, sas_device->starget, "task set " + starget_printk(KERN_INFO, sas_device->starget, "task set " "full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n", handle, (unsigned long long)sas_address, current_depth); @@ -5885,11 +5885,11 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) { switch (reset_phase) { case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); break; case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { ioc->scsih_cmds.status |= MPT2_CMD_RESET; @@ -5906,7 +5906,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) _scsih_queue_rescan(ioc); break; case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: " + dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); _scsih_sas_host_refresh(ioc); _scsih_prep_device_scan(ioc); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 6c94deeb7be..f29ea5e78bb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -397,7 +397,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, sizeof(struct rep_manu_reply), data_out_dma + sizeof(struct rep_manu_request)); - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " "send to sas_addr(0x%016llx)\n", ioc->name, (unsigned long long)sas_address)); mpt2sas_base_put_smid_default(ioc, smid); @@ -415,7 +415,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, goto issue_host_reset; } - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " "complete\n", ioc->name)); if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { @@ -423,7 +423,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - reply data transfer size(%d)\n", ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); @@ -449,7 +449,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, manufacture_reply->component_revision_id; } } else - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - no reply\n", ioc->name)); issue_host_reset: @@ -1861,7 +1861,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), dma_addr_in); - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " "sending smp request\n", ioc->name, __func__)); mpt2sas_base_put_smid_default(ioc, smid); @@ -1879,14 +1879,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, goto issue_host_reset; } - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - " + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " "complete\n", ioc->name, __func__)); if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { mpi_reply = ioc->transport_cmds.reply; - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - reply data transfer size(%d)\n", ioc->name, __func__, le16_to_cpu(mpi_reply->ResponseDataLength))); @@ -1897,7 +1897,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, rsp->resid_len -= le16_to_cpu(mpi_reply->ResponseDataLength); } else { - dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT + dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - no reply\n", ioc->name, __func__)); rc = -ENXIO; } -- cgit v1.2.3-70-g09d2 From 7fbae67a3faa90abcbe949f1494769c84e51e189 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:45:17 +0530 Subject: [SCSI] mpt2sas: Tie a log info message to a specific PHY. Add support to display additional debug info for SCSI_IO and RAID_SCSI_IO_PASSTHROUGH sent from the normal entry queued entry point, as well as internal generated commands, and IOCTLS. The additional debug info included the phy number, as well as the sas address, enclosure logical id, and slot number. This debug info has to be enabled thru the logging_level command line option, by default this will not be displayed. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 ++ drivers/scsi/mpt2sas/mpt2sas_ctl.c | 42 ++++++++++++++++++++++++++++++++++++ drivers/scsi/mpt2sas/mpt2sas_scsih.c | 19 +++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 08404b331f7..e2c5cee6450 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -275,6 +275,7 @@ struct _internal_cmd { * @id: target id * @channel: target channel * @slot: number number + * @phy: phy identifier provided in sas device page 0 * @hidden_raid_component: set to 1 when this is a raid member * @responding: used in _scsih_sas_device_mark_responding */ @@ -293,6 +294,7 @@ struct _sas_device { int id; int channel; u16 slot; + u8 phy; u8 hidden_raid_component; u8 responding; }; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 55fbd5b69b8..ce63a4a6670 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -80,6 +80,32 @@ enum block_state { BLOCKING, }; +/** + * _ctl_sas_device_find_by_handle - sas device search + * @ioc: per adapter object + * @handle: sas device handle (assigned by firmware) + * Context: Calling function should acquire ioc->sas_device_lock + * + * This searches for sas_device based on sas_address, then return sas_device + * object. + */ +static struct _sas_device * +_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _sas_device *sas_device, *r; + + r = NULL; + list_for_each_entry(sas_device, &ioc->sas_device_list, list) { + if (sas_device->handle != handle) + continue; + r = sas_device; + goto out; + } + + out: + return r; +} + #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** * _ctl_display_some_debug - debug routine @@ -205,6 +231,22 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { Mpi2SCSIIOReply_t *scsi_reply = (Mpi2SCSIIOReply_t *)mpi_reply; + struct _sas_device *sas_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _ctl_sas_device_find_by_handle(ioc, + le16_to_cpu(scsi_reply->DevHandle)); + if (sas_device) { + printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " + "phy(%d)\n", ioc->name, (unsigned long long) + sas_device->sas_address, sas_device->phy); + printk(MPT2SAS_WARN_FMT + "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + ioc->name, sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) printk(MPT2SAS_INFO_FMT "\tscsi_state(0x%02x), scsi_status" diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 82c2d4c5ece..db12e184d1d 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1749,9 +1749,10 @@ _scsih_slave_configure(struct scsi_device *sdev) } sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "sas_addr(0x%016llx), device_name(0x%016llx)\n", + "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", ds, sas_device->handle, (unsigned long long)sas_device->sas_address, + sas_device->phy, (unsigned long long)sas_device->device_name); sdev_printk(KERN_INFO, sdev, "%s: " "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, @@ -3128,6 +3129,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_scsi_status = NULL; char *desc_scsi_state = ioc->tmp_string; u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); + struct _sas_device *sas_device = NULL; + unsigned long flags; if (log_info == 0x31170000) return; @@ -3243,6 +3246,19 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, strcat(desc_scsi_state, "autosense valid "); scsi_print_command(scmd); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, + le16_to_cpu(mpi_reply->DevHandle)); + if (sas_device) { + printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), phy(%d)\n", + ioc->name, sas_device->sas_address, sas_device->phy); + printk(MPT2SAS_WARN_FMT "\tenclosure_logical_id(0x%016llx), " + "slot(%d)\n", ioc->name, sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), " "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state, @@ -4187,6 +4203,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) le16_to_cpu(sas_device_pg0.Slot); sas_device->device_info = device_info; sas_device->sas_address = sas_address; + sas_device->phy = sas_device_pg0.PhyNum; sas_device->hidden_raid_component = is_pd; /* get enclosure_logical_id */ -- cgit v1.2.3-70-g09d2 From f3eedd698ebafd0fe8a292672604a2db61c2c00a Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:46:13 +0530 Subject: [SCSI] mpt2sas: Redesign Raid devices event handling using pd_handles per HBA Actual problem : Driver may receiving the top level expander removal event prior to all the individual PD removal events, hence the driver is breaking down all the PDs in advanced to the actaul PD UNHIDE event. Driver sends multiple Target Resets to the same volume handle for each individual PD removal. FIX DESCRIPTION: To fix this issue, the entire PD device handshake protocal has to be moved to interrupt context so the breakdown occurs immediately after the actual UNHIDE event arrives. The driver will only issue one Target Reset to the volume handle, occurring after the FAILED or MISSING volume status event arrives from interrupt context. For the PD UNHIDE event, the driver will issue target resets to the PD handles, followed by OP_REMOVE. The driver will set the "deteleted" flag during interrupt context. A "pd_handle" bitmask was introduced so the driver has a list of known pds during entire life of the PD; this replaces the "hidden_raid_component" flag handle in the sas_device object. Each bit in the bitmask represents a device handle. The bit in the bitmask would be toggled ON/OFF when the HIDE/UNHIDE events arrive; also this pd_handle bitmask would bould be refreshed across host resets. Here we kept older behavior of sending target reset to volume when there is a single drive pull, wait for the reply, then send target resets to the PDs. We kept this behavior so the driver will behave the same for older versions of firmware. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 17 ++ drivers/scsi/mpt2sas/mpt2sas_base.h | 14 +- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 463 +++++++++++++++++++++++++++-------- 3 files changed, 391 insertions(+), 103 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 3774b0742b2..bb8acf78169 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3468,6 +3468,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) kfree(delayed_tr); } + list_for_each_entry_safe(delayed_tr, delayed_tr_next, + &ioc->delayed_tr_volume_list, list) { + list_del(&delayed_tr->list); + kfree(delayed_tr); + } + /* initialize the scsi lookup free list */ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); INIT_LIST_HEAD(&ioc->free_list); @@ -3622,6 +3628,15 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) init_waitqueue_head(&ioc->reset_wq); + /* allocate memory pd handle bitmask list */ + ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); + if (ioc->facts.MaxDevHandle % 8) + ioc->pd_handles_sz++; + ioc->pd_handles = kzalloc(ioc->pd_handles_sz, + GFP_KERNEL); + if (!ioc->pd_handles) + goto out_free_resources; + ioc->fwfault_debug = mpt2sas_fwfault_debug; /* base internal command bits */ @@ -3691,6 +3706,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) mpt2sas_base_free_resources(ioc); _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); + kfree(ioc->pd_handles); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); kfree(ioc->scsih_cmds.reply); @@ -3726,6 +3742,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) mpt2sas_base_free_resources(ioc); _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); + kfree(ioc->pd_handles); kfree(ioc->pfacts); kfree(ioc->ctl_cmds.reply); kfree(ioc->base_cmds.reply); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index e2c5cee6450..6fdee1680a6 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -276,7 +276,6 @@ struct _internal_cmd { * @channel: target channel * @slot: number number * @phy: phy identifier provided in sas device page 0 - * @hidden_raid_component: set to 1 when this is a raid member * @responding: used in _scsih_sas_device_mark_responding */ struct _sas_device { @@ -295,7 +294,6 @@ struct _sas_device { int channel; u16 slot; u8 phy; - u8 hidden_raid_component; u8 responding; }; @@ -489,6 +487,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @ctl_cb_idx: clt internal commands * @base_cb_idx: base internal commands * @config_cb_idx: base internal commands + * @tm_tr_cb_idx : device removal target reset handshake + * @tm_tr_volume_cb_idx : volume removal target reset * @base_cmds: * @transport_cmds: * @scsih_cmds: @@ -517,6 +517,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @sas_device_lock: * @io_missing_delay: time for IO completed by fw when PDR enabled * @device_missing_delay: time for device missing by fw when PDR enabled + * @sas_id : used for setting volume target IDs + * @pd_handles : bitmask for PD handles + * @pd_handles_sz : size of pd_handle bitmask * @config_page_sz: config page size * @config_page: reserve memory for config page payload * @config_page_dma: @@ -569,6 +572,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @reply_post_free_dma: * @reply_post_free_dma_pool: * @reply_post_host_index: head index in the pool where FW completes IO + * @delayed_tr_list: target reset link list + * @delayed_tr_volume_list: volume target reset link list */ struct MPT2SAS_ADAPTER { struct list_head list; @@ -627,6 +632,7 @@ struct MPT2SAS_ADAPTER { u8 base_cb_idx; u8 config_cb_idx; u8 tm_tr_cb_idx; + u8 tm_tr_volume_cb_idx; u8 tm_sas_control_cb_idx; struct _internal_cmd base_cmds; struct _internal_cmd transport_cmds; @@ -670,6 +676,9 @@ struct MPT2SAS_ADAPTER { u16 device_missing_delay; int sas_id; + void *pd_handles; + u16 pd_handles_sz; + /* config page */ u16 config_page_sz; void *config_page; @@ -741,6 +750,7 @@ struct MPT2SAS_ADAPTER { u32 reply_post_host_index; struct list_head delayed_tr_list; + struct list_head delayed_tr_volume_list; /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index db12e184d1d..b327d60fad1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -70,6 +70,8 @@ static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_expander); static void _firmware_event_work(struct work_struct *work); +static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); + /* global parameters */ LIST_HEAD(mpt2sas_ioc_list); @@ -84,6 +86,7 @@ static u8 config_cb_idx = -1; static int mpt_ids; static u8 tm_tr_cb_idx = -1 ; +static u8 tm_tr_volume_cb_idx = -1 ; static u8 tm_sas_control_cb_idx = -1; /* command line options */ @@ -1226,7 +1229,7 @@ _scsih_target_alloc(struct scsi_target *starget) sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; - if (sas_device->hidden_raid_component) + if (test_bit(sas_device->handle, ioc->pd_handles)) sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; } @@ -2583,6 +2586,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; struct _sas_device *sas_device; + struct MPT2SAS_TARGET *sas_target_priv_data; unsigned long flags; struct _tr_list *delayed_tr; @@ -2592,11 +2596,20 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) return; } + /* if PD, then return */ + if (test_bit(handle, ioc->pd_handles)) + return; + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device && sas_device->hidden_raid_component) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + if (sas_device && sas_device->starget && + sas_device->starget->hostdata) { + sas_target_priv_data = sas_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "setting delete flag: handle(0x%04x), " + "sas_addr(0x%016llx)\n", ioc->name, handle, + (unsigned long long) sas_device->sas_address)); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -2658,6 +2671,99 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, return 1; } +/** + * _scsih_tm_tr_volume_send - send target reset request for volumes + * @ioc: per adapter object + * @handle: device handle + * Context: interrupt time. + * + * This is designed to send muliple task management request at the same + * time to the fifo. If the fifo is full, we will append the request, + * and process it in a future completion. + */ +static void +_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + Mpi2SCSITaskManagementRequest_t *mpi_request; + u16 smid; + struct _tr_list *delayed_tr; + + if (ioc->shost_recovery || ioc->remove_host) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return; + } + + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); + if (!smid) { + delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + if (!delayed_tr) + return; + INIT_LIST_HEAD(&delayed_tr->list); + delayed_tr->handle = handle; + list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", + ioc->name, handle)); + return; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " + "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, + ioc->tm_tr_volume_cb_idx)); + mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); + memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); + mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; + mpi_request->DevHandle = cpu_to_le16(handle); + mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; + mpt2sas_base_put_smid_hi_priority(ioc, smid); +} + +/** + * _scsih_tm_volume_tr_complete - target reset completion + * @ioc: per adapter object + * @smid: system request message index + * @msix_index: MSIX table index supplied by the OS + * @reply: reply message frame(lower 32bit addr) + * Context: interrupt time. + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, + u8 msix_index, u32 reply) +{ + u16 handle; + Mpi2SCSITaskManagementRequest_t *mpi_request_tm; + Mpi2SCSITaskManagementReply_t *mpi_reply = + mpt2sas_base_get_reply_virt_addr(ioc, reply); + + if (ioc->shost_recovery || ioc->remove_host) { + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " + "progress!\n", __func__, ioc->name)); + return 1; + } + + mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); + handle = le16_to_cpu(mpi_request_tm->DevHandle); + if (handle != le16_to_cpu(mpi_reply->DevHandle)) { + dewtprintk(ioc, printk("spurious interrupt: " + "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle, + le16_to_cpu(mpi_reply->DevHandle), smid)); + return 0; + } + + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " + "loginfo(0x%08x), completed(%d)\n", ioc->name, + handle, smid, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo), + le32_to_cpu(mpi_reply->TerminationCount))); + + return _scsih_check_for_pending_tm(ioc, smid); +} + /** * _scsih_tm_tr_complete - * @ioc: per adapter object @@ -2684,7 +2790,6 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpt2sas_base_get_reply_virt_addr(ioc, reply); Mpi2SasIoUnitControlRequest_t *mpi_request; u16 smid_sas_ctrl; - struct _tr_list *delayed_tr; if (ioc->shost_recovery || ioc->remove_host) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " @@ -2725,6 +2830,35 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_request->DevHandle = mpi_request_tm->DevHandle; mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); + return _scsih_check_for_pending_tm(ioc, smid); +} + +/** + * _scsih_check_for_pending_tm - check for pending task management + * @ioc: per adapter object + * @smid: system request message index + * + * This will check delayed target reset list, and feed the + * next reqeust. + * + * Return 1 meaning mf should be freed from _base_interrupt + * 0 means the mf is freed from this function. + */ +static u8 +_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) +{ + struct _tr_list *delayed_tr; + + if (!list_empty(&ioc->delayed_tr_volume_list)) { + delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, + struct _tr_list, list); + mpt2sas_base_free_smid(ioc, smid); + _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); + list_del(&delayed_tr->list); + kfree(delayed_tr); + return 0; + } + if (!list_empty(&ioc->delayed_tr_list)) { delayed_tr = list_entry(ioc->delayed_tr_list.next, struct _tr_list, list); @@ -2732,8 +2866,9 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, _scsih_tm_tr_send(ioc, delayed_tr->handle); list_del(&delayed_tr->list); kfree(delayed_tr); - return 0; /* tells base_interrupt not to free mf */ + return 0; } + return 1; } @@ -2816,6 +2951,165 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } +/** + * _scsih_set_volume_delete_flag - setting volume delete flag + * @ioc: per adapter object + * @handle: device handle + * + * This + * Return nothing. + */ +static void +_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) +{ + struct _raid_device *raid_device; + struct MPT2SAS_TARGET *sas_target_priv_data; + unsigned long flags; + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + if (raid_device && raid_device->starget && + raid_device->starget->hostdata) { + sas_target_priv_data = + raid_device->starget->hostdata; + sas_target_priv_data->deleted = 1; + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "setting delete flag: handle(0x%04x), " + "wwid(0x%016llx)\n", ioc->name, handle, + (unsigned long long) raid_device->wwid)); + } + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); +} + +/** + * _scsih_set_volume_handle_for_tr - set handle for target reset to volume + * @handle: input handle + * @a: handle for volume a + * @b: handle for volume b + * + * IR firmware only supports two raid volumes. The purpose of this + * routine is to set the volume handle in either a or b. When the given + * input handle is non-zero, or when a and b have not been set before. + */ +static void +_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) +{ + if (!handle || handle == *a || handle == *b) + return; + if (!*a) + *a = handle; + else if (!*b) + *b = handle; +} + +/** + * _scsih_check_ir_config_unhide_events - check for UNHIDE events + * @ioc: per adapter object + * @event_data: the event data payload + * Context: interrupt time. + * + * This routine will send target reset to volume, followed by target + * resets to the PDs. This is called when a PD has been removed, or + * volume has been deleted or removed. When the target reset is sent + * to volume, the PD target resets need to be queued to start upon + * completion of the volume target reset. + * + * Return nothing. + */ +static void +_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrConfigChangeList_t *event_data) +{ + Mpi2EventIrConfigElement_t *element; + int i; + u16 handle, volume_handle, a, b; + struct _tr_list *delayed_tr; + + a = 0; + b = 0; + + /* Volume Resets for Deleted or Removed */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || + element->ReasonCode == + MPI2_EVENT_IR_CHANGE_RC_REMOVED) { + volume_handle = le16_to_cpu(element->VolDevHandle); + _scsih_set_volume_delete_flag(ioc, volume_handle); + _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); + } + } + + /* Volume Resets for UNHIDE events */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (le32_to_cpu(event_data->Flags) & + MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) + continue; + if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { + volume_handle = le16_to_cpu(element->VolDevHandle); + _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); + } + } + + if (a) + _scsih_tm_tr_volume_send(ioc, a); + if (b) + _scsih_tm_tr_volume_send(ioc, b); + + /* PD target resets */ + element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; + for (i = 0; i < event_data->NumElements; i++, element++) { + if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) + continue; + handle = le16_to_cpu(element->PhysDiskDevHandle); + volume_handle = le16_to_cpu(element->VolDevHandle); + clear_bit(handle, ioc->pd_handles); + if (!volume_handle) + _scsih_tm_tr_send(ioc, handle); + else if (volume_handle == a || volume_handle == b) { + delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); + BUG_ON(!delayed_tr); + INIT_LIST_HEAD(&delayed_tr->list); + delayed_tr->handle = handle; + list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT + "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, + handle)); + } else + _scsih_tm_tr_send(ioc, handle); + } +} + + +/** + * _scsih_check_volume_delete_events - set delete flag for volumes + * @ioc: per adapter object + * @event_data: the event data payload + * Context: interrupt time. + * + * This will handle the case when the cable connected to entire volume is + * pulled. We will take care of setting the deleted flag so normal IO will + * not be sent. + * + * Return nothing. + */ +static void +_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, + Mpi2EventDataIrVolume_t *event_data) +{ + u32 state; + + if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) + return; + state = le32_to_cpu(event_data->NewValue); + if (state == MPI2_RAID_VOL_STATE_MISSING || state == + MPI2_RAID_VOL_STATE_FAILED) + _scsih_set_volume_delete_flag(ioc, + le16_to_cpu(event_data->VolDevHandle)); +} + /** * _scsih_flush_running_cmds - completing outstanding commands. * @ioc: per adapter object @@ -4204,7 +4498,6 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) sas_device->device_info = device_info; sas_device->sas_address = sas_address; sas_device->phy = sas_device_pg0.PhyNum; - sas_device->hidden_raid_component = is_pd; /* get enclosure_logical_id */ if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( @@ -4224,62 +4517,6 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return 0; } -/** - * _scsih_remove_pd_device - removing sas device pd object - * @ioc: per adapter object - * @sas_device_delete: the sas_device object - * - * For hidden raid components, we do driver-fw handshake from - * hotplug work threads. - * Return nothing. - */ -static void -_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device - sas_device) -{ - Mpi2SasIoUnitControlReply_t mpi_reply; - Mpi2SasIoUnitControlRequest_t mpi_request; - u16 vol_handle, handle; - - handle = sas_device.handle; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x)," - " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, - (unsigned long long) sas_device.sas_address)); - - vol_handle = sas_device.volume_handle; - if (!vol_handle) - return; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: " - "handle(0x%04x)\n", ioc->name, vol_handle)); - mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0, - MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset " - "done: handle(0x%04x)\n", ioc->name, vol_handle)); - if (ioc->shost_recovery) - return; - - /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */ - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle" - "(0x%04x)\n", ioc->name, handle)); - memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); - mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE; - mpi_request.DevHandle = cpu_to_le16(handle); - if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, - &mpi_request)) != 0) - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x)," - " sas_addr(0x%016llx)\n", ioc->name, __func__, handle, - (unsigned long long) sas_device.sas_address)); -} - /** * _scsih_remove_device - removing sas device object * @ioc: per adapter object @@ -4310,9 +4547,6 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, sas_target_priv_data->deleted = 1; } - if (sas_device_backup.hidden_raid_component) - _scsih_remove_pd_device(ioc, sas_device_backup); - _scsih_ublock_io_device(ioc, sas_device_backup.handle); mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address, @@ -4909,17 +5143,15 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, /** * _scsih_sas_volume_delete - delete volume * @ioc: per adapter object - * @element: IR config element data + * @handle: volume device handle * Context: user. * * Return nothing. */ static void -_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) +_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) { struct _raid_device *raid_device; - u16 handle = le16_to_cpu(element->VolDevHandle); unsigned long flags; struct MPT2SAS_TARGET *sas_target_priv_data; @@ -4933,6 +5165,9 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, sas_target_priv_data->deleted = 1; scsi_remove_target(&raid_device->starget->dev); } + printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" + "(0x%016llx)\n", ioc->name, raid_device->handle, + (unsigned long long) raid_device->wwid); _scsih_raid_device_remove(ioc, raid_device); } @@ -4961,7 +5196,7 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, /* exposing raid component */ sas_device->volume_handle = 0; sas_device->volume_wwid = 0; - sas_device->hidden_raid_component = 0; + clear_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 0); } @@ -4992,7 +5227,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, &sas_device->volume_handle); mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, &sas_device->volume_wwid); - sas_device->hidden_raid_component = 1; + set_bit(handle, ioc->pd_handles); _scsih_reprobe_target(sas_device->starget, 1); } @@ -5041,13 +5276,13 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, u64 sas_address; u16 parent_handle; + set_bit(handle, ioc->pd_handles); + spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_device = _scsih_sas_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) { - sas_device->hidden_raid_component = 1; + if (sas_device) return; - } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -5191,7 +5426,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: case MPI2_EVENT_IR_CHANGE_RC_REMOVED: if (!foreign_config) - _scsih_sas_volume_delete(ioc, element); + _scsih_sas_volume_delete(ioc, + le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: _scsih_sas_pd_hide(ioc, element); @@ -5227,7 +5463,6 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u16 handle; u32 state; int rc; - struct MPT2SAS_TARGET *sas_target_priv_data; Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) @@ -5239,26 +5474,20 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - switch (state) { case MPI2_RAID_VOL_STATE_MISSING: case MPI2_RAID_VOL_STATE_FAILED: - if (!raid_device) - break; - if (raid_device->starget) { - sas_target_priv_data = raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); - } - _scsih_raid_device_remove(ioc, raid_device); + _scsih_sas_volume_delete(ioc, handle); break; case MPI2_RAID_VOL_STATE_ONLINE: case MPI2_RAID_VOL_STATE_DEGRADED: case MPI2_RAID_VOL_STATE_OPTIMAL: + + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + if (raid_device) break; @@ -5327,19 +5556,21 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - switch (state) { case MPI2_RAID_PD_STATE_ONLINE: case MPI2_RAID_PD_STATE_DEGRADED: case MPI2_RAID_PD_STATE_REBUILDING: case MPI2_RAID_PD_STATE_OPTIMAL: - if (sas_device) { - sas_device->hidden_raid_component = 1; + case MPI2_RAID_PD_STATE_HOT_SPARE: + + set_bit(handle, ioc->pd_handles); + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + if (sas_device) return; - } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, @@ -5369,7 +5600,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, case MPI2_RAID_PD_STATE_OFFLINE: case MPI2_RAID_PD_STATE_NOT_CONFIGURED: case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: - case MPI2_RAID_PD_STATE_HOT_SPARE: default: break; } @@ -5497,7 +5727,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work sas_address = sas_device->sas_address; /* if hidden raid component, then change to volume characteristics */ - if (sas_device->hidden_raid_component && sas_device->volume_handle) { + if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) { spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_handle( ioc, sas_device->volume_handle); @@ -5722,9 +5952,11 @@ static void _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) { Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; u16 handle; + u8 phys_disk_num; printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__); @@ -5742,6 +5974,21 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) _scsih_mark_responding_raid_device(ioc, le64_to_cpu(volume_pg1.WWID), handle); } + + /* refresh the pd_handles */ + phys_disk_num = 0xFF; + memset(ioc->pd_handles, 0, ioc->pd_handles_sz); + while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, + phys_disk_num))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + phys_disk_num = pd_pg0.PhysDiskNum; + handle = le16_to_cpu(pd_pg0.DevHandle); + set_bit(handle, ioc->pd_handles); + } } /** @@ -6060,14 +6307,21 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataSasTopologyChangeList_t *) mpi_reply->EventData); break; - + case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: + _scsih_check_ir_config_unhide_events(ioc, + (Mpi2EventDataIrConfigChangeList_t *) + mpi_reply->EventData); + break; + case MPI2_EVENT_IR_VOLUME: + _scsih_check_volume_delete_events(ioc, + (Mpi2EventDataIrVolume_t *) + mpi_reply->EventData); + break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_VOLUME: case MPI2_EVENT_IR_PHYSICAL_DISK: - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: case MPI2_EVENT_TASK_SET_FULL: break; @@ -6574,6 +6828,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->scsih_cb_idx = scsih_cb_idx; ioc->config_cb_idx = config_cb_idx; ioc->tm_tr_cb_idx = tm_tr_cb_idx; + ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; ioc->logging_level = logging_level; /* misc semaphores and spin locks */ @@ -6592,6 +6847,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->raid_device_list); INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); INIT_LIST_HEAD(&ioc->delayed_tr_list); + INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); /* init shost parameters */ shost->max_cmd_len = 32; @@ -6894,6 +7150,10 @@ _scsih_init(void) tm_tr_cb_idx = mpt2sas_base_register_callback_handler( _scsih_tm_tr_complete); + + tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( + _scsih_tm_volume_tr_complete); + tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( _scsih_sas_control_complete); @@ -6933,6 +7193,7 @@ _scsih_exit(void) mpt2sas_base_release_callback_handler(ctl_cb_idx); mpt2sas_base_release_callback_handler(tm_tr_cb_idx); + mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); /* raid transport support */ -- cgit v1.2.3-70-g09d2 From 3e2e833a547cbd0cb3fbe85a5f6ee71a93931fde Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:47:29 +0530 Subject: [SCSI] mpt2sas: Added -ENOMEM return type when allocation fails In the driver mpt2sas_base_attach subroutine, we need to add support to return the proper error code when there are memory allocation failures, e.g. returning -ENOMEM. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index bb8acf78169..d84874492cb 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3634,8 +3634,10 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) ioc->pd_handles_sz++; ioc->pd_handles = kzalloc(ioc->pd_handles_sz, GFP_KERNEL); - if (!ioc->pd_handles) + if (!ioc->pd_handles) { + r = -ENOMEM; goto out_free_resources; + } ioc->fwfault_debug = mpt2sas_fwfault_debug; @@ -3676,6 +3678,13 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) goto out_free_resources; } + if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || + !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || + !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { + r = -ENOMEM; + goto out_free_resources; + } + init_completion(&ioc->shost_recovery_done); for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) -- cgit v1.2.3-70-g09d2 From d417d1c3a3c3b4d89a285f82a4e7710372e40a24 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:48:10 +0530 Subject: [SCSI] mpt2sas: Add additional check for responding volumes after Host Reset ISSUE DESCRIPTION: This test case involves creating two RAID1 volumes, then simultaneiously issue host reset and pull all the drives associated to the 1st raid volume. The observed behavour is the physical drives are removed, however the volume remains. The expected behavour is the volume as well as physical drives should be removed from OS. FIX: Add support in the post host reset device scan logic for raid volumes where the driver will have an additional check for responding raid volume where the status should be either online, optimal, or degraded. So for voluemes that have a status of missing or failed, the driver will mark them for deletion. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index b327d60fad1..228961b94a6 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -5952,6 +5952,7 @@ static void _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) { Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidVolPage0_t volume_pg0; Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2ConfigReply_t mpi_reply; u16 ioc_status; @@ -5971,8 +5972,17 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) break; handle = le16_to_cpu(volume_pg1.DevHandle); - _scsih_mark_responding_raid_device(ioc, - le64_to_cpu(volume_pg1.WWID), handle); + + if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, + &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, + sizeof(Mpi2RaidVolPage0_t))) + continue; + + if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) + _scsih_mark_responding_raid_device(ioc, + le64_to_cpu(volume_pg1.WWID), handle); } /* refresh the pd_handles */ -- cgit v1.2.3-70-g09d2 From 8e864a81e30ab996d3245ebd16a741b3614e6581 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:48:46 +0530 Subject: [SCSI] mpt2sas: Adding additional message to error escalation callback Adding additional messages to the error escallation callbacks which displays the wwid, sas address, handle, phy number, enclosure logical id, and slot. In the same eh callbacks, routines, the printks were converted to sdev_printks, which displays the bus target mapping. These additional modifications help better identify the device which is in recovery. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 143 +++++++++++++++++++++++++---------- 1 file changed, 104 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 228961b94a6..854cc91e7aa 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2122,9 +2122,60 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, return rc; } +/** + * _scsih_tm_display_info - displays info about the device + * @ioc: per adapter struct + * @scmd: pointer to scsi command object + * + * Called by task management callback handlers. + */ +static void +_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) +{ + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *priv_target = starget->hostdata; + struct _sas_device *sas_device = NULL; + unsigned long flags; + + if (!priv_target) + return; + + scsi_print_command(scmd); + if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { + starget_printk(KERN_INFO, starget, "volume handle(0x%04x), " + "volume wwid(0x%016llx)\n", + priv_target->handle, + (unsigned long long)priv_target->sas_address); + } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + priv_target->sas_address); + if (sas_device) { + if (priv_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT) { + starget_printk(KERN_INFO, starget, + "volume handle(0x%04x), " + "volume wwid(0x%016llx)\n", + sas_device->volume_handle, + (unsigned long long)sas_device->volume_wwid); + } + starget_printk(KERN_INFO, starget, + "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", + sas_device->handle, + (unsigned long long)sas_device->sas_address, + sas_device->phy); + starget_printk(KERN_INFO, starget, + "enclosure_logical_id(0x%016llx), slot(%d)\n", + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } +} + /** * _scsih_abort - eh threads main abort routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -2137,14 +2188,14 @@ _scsih_abort(struct scsi_cmnd *scmd) u16 handle; int r; - printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + sdev_printk(KERN_INFO, scmd->device, "attempting task abort! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", - ioc->name, scmd); + sdev_printk(KERN_INFO, scmd->device, "device been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -2176,14 +2227,14 @@ _scsih_abort(struct scsi_cmnd *scmd) MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd); out: - printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** * _scsih_dev_reset - eh threads main device reset routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -2197,14 +2248,16 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) u16 handle; int r; - printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + struct scsi_target *starget = scmd->device->sdev_target; + + starget_printk(KERN_INFO, starget, "attempting target reset! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n", - ioc->name, scmd); + starget_printk(KERN_INFO, starget, "target been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -2235,14 +2288,14 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd); out: - printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** * _scsih_target_reset - eh threads main target reset routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -2255,15 +2308,16 @@ _scsih_target_reset(struct scsi_cmnd *scmd) unsigned long flags; u16 handle; int r; + struct scsi_target *starget = scmd->device->sdev_target; - printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); + starget_printk(KERN_INFO, starget, "attempting target reset! " + "scmd(%p)\n", scmd); + _scsih_tm_display_info(ioc, scmd); sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n", - ioc->name, scmd); + starget_printk(KERN_INFO, starget, "target been deleted! " + "scmd(%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; scmd->scsi_done(scmd); r = SUCCESS; @@ -2294,14 +2348,14 @@ _scsih_target_reset(struct scsi_cmnd *scmd) 30, scmd); out: - printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", + ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); return r; } /** * _scsih_host_reset - eh threads main host reset routine - * @sdev: scsi device struct + * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ @@ -3425,6 +3479,11 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); struct _sas_device *sas_device = NULL; unsigned long flags; + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *priv_target = starget->hostdata; + + if (!priv_target) + return; if (log_info == 0x31170000) return; @@ -3541,22 +3600,28 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, scsi_print_command(scmd); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - le16_to_cpu(mpi_reply->DevHandle)); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), phy(%d)\n", - ioc->name, sas_device->sas_address, sas_device->phy); - printk(MPT2SAS_WARN_FMT "\tenclosure_logical_id(0x%016llx), " - "slot(%d)\n", ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); + if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { + printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name, + (unsigned long long)priv_target->sas_address); + } else { + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + priv_target->sas_address); + if (sas_device) { + printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " + "phy(%d)\n", ioc->name, sas_device->sas_address, + sas_device->phy); + printk(MPT2SAS_WARN_FMT + "\tenclosure_logical_id(0x%016llx), slot(%d)\n", + ioc->name, sas_device->enclosure_logical_id, + sas_device->slot); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), " - "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name, - le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state, - ioc_status, smid); + printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " + "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), + desc_ioc_state, ioc_status, smid); printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, scsi_get_resid(scmd)); -- cgit v1.2.3-70-g09d2 From 769578ff811e43ccddd96b15640fa7c9df65c374 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:49:28 +0530 Subject: [SCSI] mpt2sas: Copy sense buffer instead of working on direct memory location (1) driver was not setting the sense data size prior to sending SCSI_IO, resulting in the 0x31190000 loginfo (2) The driver needs to copy the sense data to local buffer prior to releasing the request message frame. If not, the sense buffer gets overwritten by the next SCSI_IO request. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 6 +++++- drivers/scsi/mpt2sas/mpt2sas_base.h | 2 ++ drivers/scsi/mpt2sas/mpt2sas_ctl.c | 25 +++++++++++++++++++++---- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index d84874492cb..1f22a764927 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -3668,12 +3668,14 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) /* ctl module internal command bits */ ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); + ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; mutex_init(&ioc->ctl_cmds.mutex); if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { + !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || + !ioc->ctl_cmds.sense) { r = -ENOMEM; goto out_free_resources; } @@ -3722,6 +3724,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) kfree(ioc->config_cmds.reply); kfree(ioc->base_cmds.reply); kfree(ioc->ctl_cmds.reply); + kfree(ioc->ctl_cmds.sense); kfree(ioc->pfacts); ioc->ctl_cmds.reply = NULL; ioc->base_cmds.reply = NULL; @@ -3754,6 +3757,7 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) kfree(ioc->pd_handles); kfree(ioc->pfacts); kfree(ioc->ctl_cmds.reply); + kfree(ioc->ctl_cmds.sense); kfree(ioc->base_cmds.reply); kfree(ioc->tm_cmds.reply); kfree(ioc->transport_cmds.reply); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 6fdee1680a6..2bbb870a199 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -247,6 +247,7 @@ struct MPT2SAS_DEVICE { * @mutex: mutex * @done: completion * @reply: reply message pointer + * @sense: sense data * @status: MPT2_CMD_XXX status * @smid: system message id */ @@ -254,6 +255,7 @@ struct _internal_cmd { struct mutex mutex; struct completion done; void *reply; + void *sense; u16 status; u16 smid; }; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index ce63a4a6670..c3f34a76913 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -275,6 +275,9 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) { MPI2DefaultReply_t *mpi_reply; + Mpi2SCSIIOReply_t *scsiio_reply; + const void *sense_data; + u32 sz; if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) return 1; @@ -285,6 +288,20 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, if (mpi_reply) { memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; + /* get sense data */ + if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || + mpi_reply->Function == + MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { + scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; + if (scsiio_reply->SCSIState & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, + le32_to_cpu(scsiio_reply->SenseCount)); + sense_data = mpt2sas_base_get_sense_buffer(ioc, + smid); + memcpy(ioc->ctl_cmds.sense, sense_data, sz); + } + } } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); @@ -618,7 +635,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, u8 issue_reset; u32 sz; void *psge; - void *priv_sense = NULL; void *data_out = NULL; dma_addr_t data_out_dma; size_t data_out_sz = 0; @@ -782,10 +798,10 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, { Mpi2SCSIIORequest_t *scsiio_request = (Mpi2SCSIIORequest_t *)mpi_request; + scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; scsiio_request->SenseBufferLowAddress = mpt2sas_base_get_sense_buffer_dma(ioc, smid); - priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid); - memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE); + memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) mpt2sas_base_put_smid_scsi_io(ioc, smid, le16_to_cpu(mpi_request->FunctionDependent1)); @@ -929,7 +945,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); - if (copy_to_user(karg.sense_data_ptr, priv_sense, sz)) { + if (copy_to_user(karg.sense_data_ptr, + ioc->ctl_cmds.sense, sz)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); ret = -ENODATA; -- cgit v1.2.3-70-g09d2 From 1bbfa378afbf8a8bfa6f6523e4965398a578ad10 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:50:11 +0530 Subject: [SCSI] mpt2sas: Copy message frame before releasing to free pool to have a local reference. Current driver is not clearing the per device tm_busy flag following the Task Mangement request completion from the IOCTL path. When this flag is set, the IO queues are frozen. The reason the flag didn't get cleared is becuase the driver is referencing memory associated to the mpi request following the completion, when the memory had been reallocated for a new request. When the memory was reallocated, the driver didn't clear the flag becuase it was expecting a task managment reqeust, and the reallocated request was for SCSI_IO. To fix the problem the driver needs to have a cached backup copy of the original reqeust. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 56 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index c3f34a76913..55ac1cb3477 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -626,7 +626,7 @@ static long _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) { - MPI2RequestHeader_t *mpi_request; + MPI2RequestHeader_t *mpi_request = NULL, *request; MPI2DefaultReply_t *mpi_reply; u32 ioc_state; u16 ioc_status; @@ -679,31 +679,50 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", ioc->name, __func__); - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; + mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); + if (!mpi_request) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " + "mpi_request\n", ioc->name, __func__); + ret = -ENOMEM; goto out; } - ret = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - data_out_sz = karg.data_out_size; - data_in_sz = karg.data_in_size; - /* copy in request message frame from user */ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); ret = -EFAULT; - mpt2sas_base_free_smid(ioc, smid); goto out; } + if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { + smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ret = -EAGAIN; + goto out; + } + } else { + + smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); + if (!smid) { + printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", + ioc->name, __func__); + ret = -EAGAIN; + goto out; + } + } + + ret = 0; + ioc->ctl_cmds.status = MPT2_CMD_PENDING; + memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); + request = mpt2sas_base_get_msg_frame(ioc, smid); + memcpy(request, mpi_request, karg.data_sge_offset*4); + ioc->ctl_cmds.smid = smid; + data_out_sz = karg.data_out_size; + data_in_sz = karg.data_in_size; + if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { if (!le16_to_cpu(mpi_request->FunctionDependent1) || @@ -749,7 +768,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, } /* add scatter gather elements */ - psge = (void *)mpi_request + (karg.data_sge_offset*4); + psge = (void *)request + (karg.data_sge_offset*4); if (!data_out_sz && !data_in_sz) { mpt2sas_base_build_zero_len_sge(ioc, psge); @@ -797,7 +816,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: { Mpi2SCSIIORequest_t *scsiio_request = - (Mpi2SCSIIORequest_t *)mpi_request; + (Mpi2SCSIIORequest_t *)request; scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; scsiio_request->SenseBufferLowAddress = mpt2sas_base_get_sense_buffer_dma(ioc, smid); @@ -812,7 +831,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, case MPI2_FUNCTION_SCSI_TASK_MGMT: { Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)mpi_request; + (Mpi2SCSITaskManagementRequest_t *)request; dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " "handle(0x%04x), task_type(0x%02x)\n", ioc->name, @@ -985,6 +1004,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, pci_free_consistent(ioc->pdev, data_out_sz, data_out, data_out_dma); + kfree(mpi_request); ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; mutex_unlock(&ioc->ctl_cmds.mutex); return ret; -- cgit v1.2.3-70-g09d2 From d4572c3dbb00fa47b9e8cd496f12a8ec9e9b66c3 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 13:50:57 +0530 Subject: [SCSI] mpt2sas: Bump version 06.100.00.00 Version upgrade patch Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 2bbb870a199..0b0ef5e7899 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -69,11 +69,11 @@ #define MPT2SAS_DRIVER_NAME "mpt2sas" #define MPT2SAS_AUTHOR "LSI Corporation " #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "05.100.00.03" -#define MPT2SAS_MAJOR_VERSION 05 +#define MPT2SAS_DRIVER_VERSION "06.100.00.00" +#define MPT2SAS_MAJOR_VERSION 06 #define MPT2SAS_MINOR_VERSION 100 #define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 03 +#define MPT2SAS_RELEASE_VERSION 00 /* * Set MPT2SAS_SG_DEPTH value based on user input. -- cgit v1.2.3-70-g09d2 From 8ce13de2ad0df5239340e885e5513d9ad98439e0 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:35:46 +0530 Subject: [SCSI] mptfusion: Set fw_events_off to 1 at driver load time. fw_events_off is flag checking for driver to do Event handling or not. Normally it should be OFF at the time of initialization. Only enable it at the time of INTR enable of device first time. This will always occur only after resource allocation. ioc->fw_events_off = 1 is set in mpt_attach() Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index a6a57011ba6..49005e15105 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1913,6 +1913,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->msi_enable = 0; break; } + + ioc->fw_events_off = 1; + if (ioc->errata_flag_1064) pci_disable_io_access(pdev); -- cgit v1.2.3-70-g09d2 From 4d0695664ed8e168f97cce86289d0c5fab35b067 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:37:25 +0530 Subject: [SCSI] mptfusion: Use DID_TRANSPORT_DISRUPTED instead of DID_BUS_BUSY Changed the return value for Nexus Loss IOs to be DID_TRANSPORT_DISRUPTED. What this will allow is the multi-path driver to delay the fail over process. They would like the path to keep up as long as the nexus loss Loginfo is return from firmware. With DID_BUS_BUSY the path fails over immediately. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptscsih.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 407cb84822d..5a3c10e72e4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -742,7 +742,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { if ((log_info & SAS_LOGINFO_MASK) == SAS_LOGINFO_NEXUS_LOSS) { - sc->result = (DID_BUS_BUSY << 16); + sc->result = + (DID_TRANSPORT_DISRUPTED + << 16); break; } } -- cgit v1.2.3-70-g09d2 From aca794ddd688f1bbb7551f569b0620255c052d80 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:39:25 +0530 Subject: [SCSI] mptfusion: Corrected declaration of device_missing_delay device missing delay is 8 bit value in io unit pg1. Making correct variable declaration for device_missing_delay. The driver is storing the calculated device missing delay in IOC structure as a u8 instead of a u16. It needs to be a u16 if the delay is > 255. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 2 +- drivers/message/fusion/mptsas.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index b613eb3d470..453bcb7d6b5 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -601,7 +601,7 @@ typedef struct _MPT_ADAPTER u16 nvdata_version_default; int debug_level; u8 io_missing_delay; - u8 device_missing_delay; + u16 device_missing_delay; SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */ SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */ u8 bus_type; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index ac000e83db0..1caf03ea855 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2364,7 +2364,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) SasIOUnitPage1_t *buffer; dma_addr_t dma_handle; int error; - u16 device_missing_delay; + u8 device_missing_delay; memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t)); memset(&cfg, 0, sizeof(CONFIGPARMS)); @@ -2401,7 +2401,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc) ioc->io_missing_delay = le16_to_cpu(buffer->IODeviceMissingDelay); - device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay); + device_missing_delay = buffer->ReportDeviceMissingDelay; ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ? (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 : device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK; -- cgit v1.2.3-70-g09d2 From 51106ab5306b752cd53d40626f78774276bb1368 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:40:10 +0530 Subject: [SCSI] mptfusion: Added sanity to check B_T mapping for device before adding to OS Added sanity check before treating any device is a valid device. It is possible that firmware can have device page0 in its table, but that devicemay not be available in topology. Device will be available in topology only if there is Bus Target mapping is done in firmware. Driver will always check B_T mapping of firmware before reporting device to upper layer. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/message/fusion/mptsas.h | 1 + 2 files changed, 38 insertions(+) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 1caf03ea855..8963f5c44c2 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2549,6 +2549,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, device_info->sas_address = le64_to_cpu(sas_address); device_info->device_info = le32_to_cpu(buffer->DeviceInfo); + device_info->flags = le16_to_cpu(buffer->Flags); out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, @@ -3840,6 +3841,13 @@ mptsas_probe_devices(MPT_ADAPTER *ioc) MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) continue; + /* If there is no FW B_T mapping for this device then continue + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + continue; + phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); if (!phy_info) continue; @@ -4149,6 +4157,14 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) phys_disk.PhysDiskID)) continue; + /* If there is no FW B_T mapping for this device then continue + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + continue; + + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_device.sas_address); mptsas_add_end_device(ioc, phy_info); @@ -4199,6 +4215,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, (hot_plug_info->channel << 8) + hot_plug_info->id); + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + break; + if (!sas_device.handle) return; @@ -4241,6 +4264,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, break; } + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + break; + phy_info = mptsas_find_phyinfo_by_sas_address( ioc, sas_device.sas_address); @@ -4294,6 +4324,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, break; } + /* If there is no FW B_T mapping for this device then break + * */ + if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT) + || !(sas_device.flags & + MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED)) + break; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, sas_device.sas_address); if (!phy_info) { diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h index 7b249edbda7..57e86ab7766 100644 --- a/drivers/message/fusion/mptsas.h +++ b/drivers/message/fusion/mptsas.h @@ -140,6 +140,7 @@ struct mptsas_devinfo { u64 sas_address; /* WWN of this device, SATA is assigned by HBA,expander */ u32 device_info; /* bitfield detailed info about this device */ + u16 flags; /* sas device pg0 flags */ }; /* -- cgit v1.2.3-70-g09d2 From b68bf096d4211bb6490955f86842d8291e8ae218 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:40:56 +0530 Subject: [SCSI] mptfusion: schedule_target_reset from all Reset context Issue: target reset will be queued to driver's internal queue to get schedule later. When driver add target into internal target_reset queue we will block IOs on those target using scsi midlayer API. Now due to some cause driver is not executing those target_reset list and it is always in block state. Changes: now we are clearing target_reset queue from all other Callback context instead of only DeviceReset context.Now wherever driver is clearing taskmgmt_in_progress flag it is considering target_reset queue cleanup also. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 2 ++ drivers/message/fusion/mptctl.c | 14 ++++++++-- drivers/message/fusion/mptsas.c | 59 +++++++++++++++++++++++++++------------ drivers/message/fusion/mptscsih.c | 2 ++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 453bcb7d6b5..a2a620c3e07 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -580,6 +580,7 @@ struct mptfc_rport_info typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr); typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr); +typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc); /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS @@ -738,6 +739,7 @@ typedef struct _MPT_ADAPTER int taskmgmt_in_progress; u8 taskmgmt_quiesce_io; u8 ioc_reset_in_progress; + MPT_SCHEDULE_TARGET_RESET schedule_target_reset; struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index f06b29193b4..9bd89cebb5a 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -261,10 +261,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) /* We are done, issue wake up */ if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) { - if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) + if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) { mpt_clear_taskmgmt_in_progress_flag(ioc); - ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; - complete(&ioc->ioctl_cmds.done); + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); + } else { + ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING; + complete(&ioc->ioctl_cmds.done); + } } out_continuation: @@ -298,6 +304,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) mpt_clear_taskmgmt_in_progress_flag(ioc); ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); return 1; } return 0; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 8963f5c44c2..a9465516234 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -126,6 +126,7 @@ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); +void mptsas_schedule_target_reset(void *ioc); static void mptsas_print_phy_data(MPT_ADAPTER *ioc, MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) @@ -1138,6 +1139,44 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc, } } +/** + * mptsas_schedule_target_reset- send pending target reset + * @iocp: per adapter object + * + * This function will delete scheduled target reset from the list and + * try to send next target reset. This will be called from completion + * context of any Task managment command. + */ + +void +mptsas_schedule_target_reset(void *iocp) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp); + MPT_SCSI_HOST *hd = shost_priv(ioc->sh); + struct list_head *head = &hd->target_reset_list; + struct mptsas_target_reset_event *target_reset_list; + u8 id, channel; + /* + * issue target reset to next device in the queue + */ + + head = &hd->target_reset_list; + if (list_empty(head)) + return; + + target_reset_list = list_entry(head->next, + struct mptsas_target_reset_event, list); + + id = target_reset_list->sas_event_data.TargetID; + channel = target_reset_list->sas_event_data.Bus; + target_reset_list->time_count = jiffies; + + if (mptsas_target_reset(ioc, channel, id)) + target_reset_list->target_reset_issued = 1; + return; +} + + /** * mptsas_taskmgmt_complete - complete SAS task management function * @ioc: Pointer to MPT_ADAPTER structure @@ -1227,23 +1266,7 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) &target_reset_list->sas_event_data); - /* - * issue target reset to next device in the queue - */ - - head = &hd->target_reset_list; - if (list_empty(head)) - return 1; - - target_reset_list = list_entry(head->next, struct mptsas_target_reset_event, - list); - - id = target_reset_list->sas_event_data.TargetID; - channel = target_reset_list->sas_event_data.Bus; - target_reset_list->time_count = jiffies; - - if (mptsas_target_reset(ioc, channel, id)) - target_reset_list->target_reset_issued = 1; + ioc->schedule_target_reset(ioc); return 1; } @@ -4961,7 +4984,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->DoneCtx = mptsasDoneCtx; ioc->TaskCtx = mptsasTaskCtx; ioc->InternalCtx = mptsasInternalCtx; - + ioc->schedule_target_reset = &mptsas_schedule_target_reset; /* Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 5a3c10e72e4..c5c8fb811f5 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -2134,6 +2134,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, mpt_clear_taskmgmt_in_progress_flag(ioc); ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING; complete(&ioc->taskmgmt_cmds.done); + if (ioc->bus_type == SAS) + ioc->schedule_target_reset(ioc); return 1; } return 0; -- cgit v1.2.3-70-g09d2 From cc7e9f5f9999d9c015686ab4a622e1fb529391eb Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:41:48 +0530 Subject: [SCSI] mptfusion: Added code for occationally SATA hotplug failure. Issue: SATA hotplug does not work sometimes. At the time of ADD device/ADD phys disk, drive may fail to add SATA device due to temporary SAS Address for SATA device generated by firmware. Final SAS address for SATA driver will be generated only after disk spinup is done. This may take some times for slow spining SATA drives. At phy link up driver gets attached device sas address and stores into phyinfo. At the time of ADD event driver will read sas device page0 using channel and FW ID provided in ADD Device event. Here in case of SATA drives, driver will see miss match in phyinfo->sas_address and latest sas address read from SAS DEVICE PAGE0 and eventually device won't be added to OS. Fix: When Driver read SAS DEVICE PAGE0, it can identify Device type looking at device_info. If device is SATA drive and sas address mismatch happens, Driver will do same stuffs which happened at the time of LINK UP to get correct piece of information from Pages. ( Find parent device and refresh parent device phys either HBA refresh/Exp refresh) Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index a9465516234..f42781b92bd 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4210,6 +4210,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, struct mptsas_devinfo sas_device; VirtTarget *vtarget; int i; + struct mptsas_portinfo *port_info; switch (hot_plug_info->event_type) { @@ -4249,8 +4250,36 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, return; phy_info = mptsas_refreshing_device_handles(ioc, &sas_device); - if (!phy_info) + /* Only For SATA Device ADD */ + if (!phy_info && (sas_device.device_info & + MPI_SAS_DEVICE_INFO_SATA_DEVICE)) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "%s %d SATA HOT PLUG: " + "parent handle of device %x\n", ioc->name, + __func__, __LINE__, sas_device.handle_parent)); + port_info = mptsas_find_portinfo_by_handle(ioc, + sas_device.handle_parent); + + if (port_info == ioc->hba_port_info) + mptsas_probe_hba_phys(ioc); + else if (port_info) + mptsas_expander_refresh(ioc, port_info); + else { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s %d port info is NULL\n", + ioc->name, __func__, __LINE__)); + break; + } + phy_info = mptsas_refreshing_device_handles + (ioc, &sas_device); + } + + if (!phy_info) { + dfailprintk(ioc, printk(MYIOC_s_ERR_FMT + "%s %d phy info is NULL\n", + ioc->name, __func__, __LINE__)); break; + } if (mptsas_get_rphy(phy_info)) break; -- cgit v1.2.3-70-g09d2 From b9a0f872a9ff3b5074c74da98052b5205929b560 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:42:39 +0530 Subject: [SCSI] mptfusion: Added missing reset for ioc_reset_in_progress in SoftReset Added missing part which will reset ioc_reset_in_progress before returning from SoftResetHandler. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 49005e15105..d0855f278db 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -6974,6 +6974,7 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag) spin_lock_irqsave(&ioc->taskmgmt_lock, flags); if (ioc->taskmgmt_in_progress) { + ioc->ioc_reset_in_progress = 0; spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); return -1; } -- cgit v1.2.3-70-g09d2 From c817ce842a539d2e536b328b9689e836d48b20e9 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Thu, 17 Jun 2010 14:44:00 +0530 Subject: [SCSI] mptfusion: Bump version 03.04.16 Upgrade driver version to 3.4.16 Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index a2a620c3e07..0d149c82e76 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.15" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.15" +#define MPT_LINUX_VERSION_COMMON "3.04.16" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.16" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v1.2.3-70-g09d2 From 15f7fc060a7bf49991c35b23e1e7d73a1535382a Mon Sep 17 00:00:00 2001 From: Bandan Das Date: Wed, 16 Jun 2010 13:39:42 -0400 Subject: [SCSI] mpt fusion: Cleanup some duplicate calls in mptbase.c In mpt_detach, call to pci_set_drvdata is redundant because it has already been called in mpt_adapter_disable. In mpt_attach, ioc->pcidev is set to pdev two times. Signed-off-by: Bandan Das Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index d0855f278db..c36d5b9ff66 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1770,7 +1770,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - ioc->pcidev = pdev; spin_lock_init(&ioc->taskmgmt_lock); mutex_init(&ioc->internal_cmds.mutex); @@ -2054,7 +2053,6 @@ mpt_detach(struct pci_dev *pdev) mpt_adapter_dispose(ioc); - pci_set_drvdata(pdev, NULL); } /************************************************************************** -- cgit v1.2.3-70-g09d2 From 73ee5d8672871bd69077ca71e7208a36bfa6343c Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:55:13 -0500 Subject: [SCSI] ibmvfc: Fix soft lockup on resume This fixes a softlockup seen on resume. During resume, the CRQ must be reenabled. However, the H_ENABLE_CRQ hcall used to do this may return H_BUSY or H_LONG_BUSY. When this happens, the caller is expected to retry later. Normally the H_ENABLE_CRQ succeeds relatively soon. However, we have seen cases where this can take long enough to see softlockup warnings. This patch changes a simple loop, which was causing the softlockup, to a loop at task level which sleeps between retries rather than simply spinning. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 81 ++++++++++++++++++++++++++++-------------- drivers/scsi/ibmvscsi/ibmvfc.h | 2 ++ 2 files changed, 56 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index fef49521cbc..d6fcb3f4396 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -504,12 +504,23 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) vhost->action = action; break; - case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_INIT: case IBMVFC_HOST_ACTION_TGT_DEL: + switch (vhost->action) { + case IBMVFC_HOST_ACTION_RESET: + case IBMVFC_HOST_ACTION_REENABLE: + break; + default: + vhost->action = action; + break; + }; + break; + case IBMVFC_HOST_ACTION_LOGO: case IBMVFC_HOST_ACTION_QUERY_TGTS: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_NONE: + case IBMVFC_HOST_ACTION_RESET: + case IBMVFC_HOST_ACTION_REENABLE: default: vhost->action = action; break; @@ -641,7 +652,7 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) **/ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) { - long rc; + long rc = 0; struct vio_dev *vdev = to_vio_dev(vhost->dev); struct ibmvfc_crq_queue *crq = &vhost->crq; @@ -649,6 +660,8 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) free_irq(vdev->irq, vhost); tasklet_kill(&vhost->tasklet); do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); @@ -667,11 +680,13 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) **/ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) { - int rc; + int rc = 0; struct vio_dev *vdev = to_vio_dev(vhost->dev); /* Re-enable the CRQ */ do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); @@ -690,15 +705,19 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) **/ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) { - int rc; + int rc = 0; + unsigned long flags; struct vio_dev *vdev = to_vio_dev(vhost->dev); struct ibmvfc_crq_queue *crq = &vhost->crq; /* Close the CRQ */ do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); + spin_lock_irqsave(vhost->host->host_lock, flags); vhost->state = IBMVFC_NO_CRQ; vhost->logged_in = 0; ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); @@ -716,6 +735,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) dev_warn(vhost->dev, "Partner adapter not ready\n"); else if (rc != 0) dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); + spin_unlock_irqrestore(vhost->host->host_lock, flags); return rc; } @@ -821,17 +841,9 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) **/ static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost) { - int rc; - - scsi_block_requests(vhost->host); ibmvfc_purge_requests(vhost, DID_ERROR); - if ((rc = ibmvfc_reset_crq(vhost)) || - (rc = ibmvfc_send_crq_init(vhost)) || - (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { - dev_err(vhost->dev, "Error after reset rc=%d\n", rc); - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - } else - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET); } /** @@ -2606,22 +2618,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) dev_info(vhost->dev, "Re-enabling adapter\n"); vhost->client_migrated = 1; ibmvfc_purge_requests(vhost, DID_REQUEUE); - if ((rc = ibmvfc_reenable_crq_queue(vhost)) || - (rc = ibmvfc_send_crq_init(vhost))) { - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc); - } else - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE); } else { dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); - ibmvfc_purge_requests(vhost, DID_ERROR); - if ((rc = ibmvfc_reset_crq(vhost)) || - (rc = ibmvfc_send_crq_init(vhost))) { - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc); - } else - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET); } return; case IBMVFC_CRQ_CMD_RSP: @@ -4123,6 +4126,8 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) case IBMVFC_HOST_ACTION_TGT_DEL: case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: case IBMVFC_HOST_ACTION_QUERY: + case IBMVFC_HOST_ACTION_RESET: + case IBMVFC_HOST_ACTION_REENABLE: default: break; }; @@ -4220,6 +4225,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) struct ibmvfc_target *tgt; unsigned long flags; struct fc_rport *rport; + int rc; ibmvfc_log_ae(vhost, vhost->events_to_log); spin_lock_irqsave(vhost->host->host_lock, flags); @@ -4229,6 +4235,27 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost) case IBMVFC_HOST_ACTION_LOGO_WAIT: case IBMVFC_HOST_ACTION_INIT_WAIT: break; + case IBMVFC_HOST_ACTION_RESET: + vhost->action = IBMVFC_HOST_ACTION_TGT_DEL; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + rc = ibmvfc_reset_crq(vhost); + spin_lock_irqsave(vhost->host->host_lock, flags); + if (rc || (rc = ibmvfc_send_crq_init(vhost)) || + (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc); + } + break; + case IBMVFC_HOST_ACTION_REENABLE: + vhost->action = IBMVFC_HOST_ACTION_TGT_DEL; + spin_unlock_irqrestore(vhost->host->host_lock, flags); + rc = ibmvfc_reenable_crq_queue(vhost); + spin_lock_irqsave(vhost->host->host_lock, flags); + if (rc || (rc = ibmvfc_send_crq_init(vhost))) { + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc); + } + break; case IBMVFC_HOST_ACTION_LOGO: vhost->job_step(vhost); break; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 7e9742764e4..2010d73aca8 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -649,6 +649,8 @@ struct ibmvfc_event_pool { enum ibmvfc_host_action { IBMVFC_HOST_ACTION_NONE = 0, + IBMVFC_HOST_ACTION_RESET, + IBMVFC_HOST_ACTION_REENABLE, IBMVFC_HOST_ACTION_LOGO, IBMVFC_HOST_ACTION_LOGO_WAIT, IBMVFC_HOST_ACTION_INIT, -- cgit v1.2.3-70-g09d2 From 3f01424c8128af7a69c824176bff195be457d6ac Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:55:15 -0500 Subject: [SCSI] ibmvfc: Add support for fc_block_scsi_eh Adds support for fc_block_scsi_eh to block the EH handlers if the target device is in the blocked state to ensure we don't take devices offline. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index d6fcb3f4396..bd96cecaa61 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -2311,6 +2311,7 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) int rc = FAILED; ENTER; + fc_block_scsi_eh(cmd); ibmvfc_wait_while_resetting(vhost); cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); abort_rc = ibmvfc_abort_task_set(sdev); @@ -2337,6 +2338,7 @@ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) int rc = FAILED; ENTER; + fc_block_scsi_eh(cmd); ibmvfc_wait_while_resetting(vhost); cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); @@ -2401,6 +2403,7 @@ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) unsigned long cancel_rc = 0; ENTER; + fc_block_scsi_eh(cmd); ibmvfc_wait_while_resetting(vhost); starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset); reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); @@ -2422,6 +2425,7 @@ static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) int rc; struct ibmvfc_host *vhost = shost_priv(cmd->device->host); + fc_block_scsi_eh(cmd); dev_err(vhost->dev, "Resetting connection due to error recovery\n"); rc = ibmvfc_issue_fc_host_lip(vhost->host); return rc ? FAILED : SUCCESS; -- cgit v1.2.3-70-g09d2 From 06395193b20124663b83b2894da827aec7e9d920 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:55:16 -0500 Subject: [SCSI] ibmvfc: Driver version 1.0.8 Bump driver version. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvfc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 2010d73aca8..d7e8dcd9065 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -29,8 +29,8 @@ #include "viosrp.h" #define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.7" -#define IBMVFC_DRIVER_DATE "(October 16, 2009)" +#define IBMVFC_DRIVER_VERSION "1.0.8" +#define IBMVFC_DRIVER_DATE "(June 17, 2010)" #define IBMVFC_DEFAULT_TIMEOUT 60 #define IBMVFC_ADISC_CANCEL_TIMEOUT 45 -- cgit v1.2.3-70-g09d2 From 0f33ece5bc3d5a9567b65cfbc736e8f206ecfc7b Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:56:00 -0500 Subject: [SCSI] ibmvscsi: Fix softlockup on resume This fixes a softlockup seen on resume. During resume, the CRQ must be reenabled. However, the H_ENABLE_CRQ hcall used to do this may return H_BUSY or H_LONG_BUSY. When this happens, the caller is expected to retry later. This patch changes a simple loop, which was causing the softlockup, to a loop at task level which sleeps between retries rather than simply spinning. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 117 +++++++++++++++++++++++++++++--------- drivers/scsi/ibmvscsi/ibmvscsi.h | 4 ++ drivers/scsi/ibmvscsi/rpa_vscsi.c | 16 +++++- 3 files changed, 106 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index aad35cc41e4..e50fad96329 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include @@ -504,14 +505,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) atomic_set(&hostdata->request_limit, 0); purge_requests(hostdata, DID_ERROR); - if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) || - (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) || - (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) { - atomic_set(&hostdata->request_limit, -1); - dev_err(hostdata->dev, "error after reset\n"); - } - - scsi_unblock_requests(hostdata->host); + hostdata->reset_crq = 1; + wake_up(&hostdata->work_wait_q); } /** @@ -1462,30 +1457,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); hostdata->client_migrated = 1; + hostdata->reenable_crq = 1; purge_requests(hostdata, DID_REQUEUE); - if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, - hostdata)) || - (ibmvscsi_ops->send_crq(hostdata, - 0xC001000000000000LL, 0))) { - atomic_set(&hostdata->request_limit, - -1); - dev_err(hostdata->dev, "error after enable\n"); - } + wake_up(&hostdata->work_wait_q); } else { dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n", crq->format); - - purge_requests(hostdata, DID_ERROR); - if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, - hostdata)) || - (ibmvscsi_ops->send_crq(hostdata, - 0xC001000000000000LL, 0))) { - atomic_set(&hostdata->request_limit, - -1); - dev_err(hostdata->dev, "error after reset\n"); - } + ibmvscsi_reset_host(hostdata); } - scsi_unblock_requests(hostdata->host); return; case 0x80: /* real payload */ break; @@ -1850,6 +1829,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) return desired_io; } +static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) +{ + int rc; + char *action = "reset"; + + if (hostdata->reset_crq) { + smp_rmb(); + hostdata->reset_crq = 0; + + rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata); + if (!rc) + rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); + if (!rc) + rc = vio_enable_interrupts(to_vio_dev(hostdata->dev)); + } else if (hostdata->reenable_crq) { + smp_rmb(); + action = "enable"; + rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata); + hostdata->reenable_crq = 0; + if (!rc) + rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); + } else + return; + + if (rc) { + atomic_set(&hostdata->request_limit, -1); + dev_err(hostdata->dev, "error after %s\n", action); + } + + scsi_unblock_requests(hostdata->host); +} + +static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +{ + if (kthread_should_stop()) + return 1; + else if (hostdata->reset_crq) { + smp_rmb(); + return 1; + } else if (hostdata->reenable_crq) { + smp_rmb(); + return 1; + } + + return 0; +} + +static int ibmvscsi_work(void *data) +{ + struct ibmvscsi_host_data *hostdata = data; + int rc; + + set_user_nice(current, -20); + + while (1) { + rc = wait_event_interruptible(hostdata->work_wait_q, + ibmvscsi_work_to_do(hostdata)); + + BUG_ON(rc); + + if (kthread_should_stop()) + break; + + ibmvscsi_do_work(hostdata); + } + + return 0; +} + /** * Called by bus code for each adapter */ @@ -1875,6 +1923,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) hostdata = shost_priv(host); memset(hostdata, 0x00, sizeof(*hostdata)); INIT_LIST_HEAD(&hostdata->sent); + init_waitqueue_head(&hostdata->work_wait_q); hostdata->host = host; hostdata->dev = dev; atomic_set(&hostdata->request_limit, -1); @@ -1885,10 +1934,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto persist_bufs_failed; } + hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d", + "ibmvscsi", host->host_no); + + if (IS_ERR(hostdata->work_thread)) { + dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n", + PTR_ERR(hostdata->work_thread)); + goto init_crq_failed; + } + rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); if (rc != 0 && rc != H_RESOURCE) { dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); - goto init_crq_failed; + goto kill_kthread; } if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) { dev_err(&vdev->dev, "couldn't initialize event pool\n"); @@ -1944,6 +2002,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) release_event_pool(&hostdata->pool, hostdata); init_pool_failed: ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); + kill_kthread: + kthread_stop(hostdata->work_thread); init_crq_failed: unmap_persist_bufs(hostdata); persist_bufs_failed: @@ -1960,6 +2020,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev) ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); + kthread_stop(hostdata->work_thread); srp_remove_host(hostdata->host); scsi_remove_host(hostdata->host); scsi_host_put(hostdata->host); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 9cb7c6a773e..02197a2b22b 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -91,12 +91,16 @@ struct event_pool { struct ibmvscsi_host_data { atomic_t request_limit; int client_migrated; + int reset_crq; + int reenable_crq; struct device *dev; struct event_pool pool; struct crq_queue queue; struct tasklet_struct srp_task; struct list_head sent; struct Scsi_Host *host; + struct task_struct *work_thread; + wait_queue_head_t work_wait_q; struct mad_adapter_info_data madapter_info; struct capabilities caps; dma_addr_t caps_addr; diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 989b9a8ba72..f48ae0190d9 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -71,11 +72,13 @@ static void rpavscsi_release_crq_queue(struct crq_queue *queue, struct ibmvscsi_host_data *hostdata, int max_requests) { - long rc; + long rc = 0; struct vio_dev *vdev = to_vio_dev(hostdata->dev); free_irq(vdev->irq, (void *)hostdata); tasklet_kill(&hostdata->srp_task); do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); dma_unmap_single(hostdata->dev, @@ -200,11 +203,13 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) static int rpavscsi_reset_crq_queue(struct crq_queue *queue, struct ibmvscsi_host_data *hostdata) { - int rc; + int rc = 0; struct vio_dev *vdev = to_vio_dev(hostdata->dev); /* Close the CRQ */ do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); @@ -301,7 +306,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, req_irq_failed: tasklet_kill(&hostdata->srp_task); + rc = 0; do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); reg_crq_failed: @@ -323,11 +331,13 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue, static int rpavscsi_reenable_crq_queue(struct crq_queue *queue, struct ibmvscsi_host_data *hostdata) { - int rc; + int rc = 0; struct vio_dev *vdev = to_vio_dev(hostdata->dev); /* Re-enable the CRQ */ do { + if (rc) + msleep(100); rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); } while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); -- cgit v1.2.3-70-g09d2 From 1117ef8aed95521f46dae3052c7120baae48c2bb Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:56:02 -0500 Subject: [SCSI] ibmvscsi: Fix error path deadlock Fixes a deadlock that can occur if we hit a command timeout during the virtual adapter initialization. The event done functions are written with the assumption that no locks are held, however, when purging requests this is not true. Fix up the purge function to drop the lock so that the done function is not called with the lock held, which can cause a deadlock. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e50fad96329..83b5a174164 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -474,23 +474,26 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, */ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code) { - struct srp_event_struct *tmp_evt, *pos; + struct srp_event_struct *evt; unsigned long flags; spin_lock_irqsave(hostdata->host->host_lock, flags); - list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { - list_del(&tmp_evt->list); - del_timer(&tmp_evt->timer); - if (tmp_evt->cmnd) { - tmp_evt->cmnd->result = (error_code << 16); - unmap_cmd_data(&tmp_evt->iu.srp.cmd, - tmp_evt, - tmp_evt->hostdata->dev); - if (tmp_evt->cmnd_done) - tmp_evt->cmnd_done(tmp_evt->cmnd); - } else if (tmp_evt->done) - tmp_evt->done(tmp_evt); - free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); + while (!list_empty(&hostdata->sent)) { + evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list); + list_del(&evt->list); + del_timer(&evt->timer); + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (evt->cmnd) { + evt->cmnd->result = (error_code << 16); + unmap_cmd_data(&evt->iu.srp.cmd, evt, + evt->hostdata->dev); + if (evt->cmnd_done) + evt->cmnd_done(evt->cmnd); + } else if (evt->done) + evt->done(evt); + free_event_struct(&evt->hostdata->pool, evt); + spin_lock_irqsave(hostdata->host->host_lock, flags); } spin_unlock_irqrestore(hostdata->host->host_lock, flags); } -- cgit v1.2.3-70-g09d2 From f3a9c4d76a955e331e88992cd3b1e1498c231d52 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:56:03 -0500 Subject: [SCSI] ibmvscsi: Fix possible request_limit issue If we encounter an error when sending a management datagram (i.e. non SCSI command, such as virtual adapter initialization command), we end up incrementing the request_limit, even though we don't decrement it for these commands. Fix this up by doing this increment in the error path for SRP commands only. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 83b5a174164..4f906efb151 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -548,6 +548,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, u64 *crq_as_u64 = (u64 *) &evt_struct->crq; int request_status = 0; int rc; + int srp_req = 0; /* If we have exhausted our request limit, just fail this request, * unless it is for a reset or abort. @@ -556,6 +557,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, * can handle more requests (can_queue) when we actually can't */ if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) { + srp_req = 1; request_status = atomic_dec_if_positive(&hostdata->request_limit); /* If request limit was -1 when we started, it is now even @@ -630,7 +632,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, goto send_busy; } dev_err(hostdata->dev, "send error %d\n", rc); - atomic_inc(&hostdata->request_limit); + if (srp_req) + atomic_inc(&hostdata->request_limit); goto send_error; } @@ -640,7 +643,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); - if (request_status != -1) + if (srp_req && request_status != -1) atomic_inc(&hostdata->request_limit); return SCSI_MLQUEUE_HOST_BUSY; -- cgit v1.2.3-70-g09d2 From aac3118d33e275a7b1134cb19227c982f4d43877 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 17 Jun 2010 13:56:04 -0500 Subject: [SCSI] ibmvscsi: Driver version 1.5.9 Bump driver version Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 4f906efb151..67f78a470f5 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -102,7 +102,7 @@ static int client_reserve = 1; static struct scsi_transport_template *ibmvscsi_transport_template; -#define IBMVSCSI_VERSION "1.5.8" +#define IBMVSCSI_VERSION "1.5.9" static struct ibmvscsi_ops *ibmvscsi_ops; -- cgit v1.2.3-70-g09d2 From a91c1be21704113b023919826c6d531da46656ef Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 12 Mar 2010 16:14:42 -0600 Subject: [SCSI] enclosure: fix error path - actually return ERR_PTR() on error we also need to clean up and free the cdev. Reported-by: Jani Nikula Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/misc/enclosure.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 48c84a58163..00e5fcac8fd 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -285,8 +285,11 @@ enclosure_component_register(struct enclosure_device *edev, cdev->groups = enclosure_groups; err = device_register(cdev); - if (err) - ERR_PTR(err); + if (err) { + ecomp->number = -1; + put_device(cdev); + return ERR_PTR(err); + } return ecomp; } -- cgit v1.2.3-70-g09d2 From cdd3cb156f190edb37d7066ddbf879354da2b634 Mon Sep 17 00:00:00 2001 From: Nick Cheng Date: Tue, 13 Jul 2010 20:03:04 +0800 Subject: [SCSI] SCSI: Support Type C RAID controller 1. To support Type C RAID controller, ACB_ADAPTER_TYPE_C, i.e. PCI device ID: 0x1880. Signed-off-by: Nick Cheng< nick.cheng@areca.com.tw > Signed-off-by: James Bottomley --- drivers/scsi/arcmsr/arcmsr.h | 208 ++++- drivers/scsi/arcmsr/arcmsr_attr.c | 9 +- drivers/scsi/arcmsr/arcmsr_hba.c | 1538 ++++++++++++++++++++++++------------- 3 files changed, 1182 insertions(+), 573 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index c0861c05cd4..475c31ae985 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -43,12 +43,11 @@ ******************************************************************************* */ #include - struct device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -60,7 +59,8 @@ struct device_attribute; #define ARCMSR_DEFAULT_SG_ENTRIES 38 #define ARCMSR_MAX_HBB_POSTQUEUE 264 #define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ -#define ARCMSR_CDB_SG_PAGE_LENGTH 256 +#define ARCMSR_CDB_SG_PAGE_LENGTH 256 +#define SCSI_CMD_ARECA_SPECIFIC 0xE1 #ifndef PCI_DEVICE_ID_ARECA_1880 #define PCI_DEVICE_ID_ARECA_1880 0x1880 #endif @@ -138,9 +138,9 @@ struct CMD_MESSAGE_FIELD #define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \ ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE /* ARECA IOCTL ReturnCode */ -#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 -#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 -#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F +#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 +#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 +#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F #define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON 0x00000088 /* ************************************************************* @@ -153,13 +153,13 @@ struct SG32ENTRY { __le32 length; __le32 address; -} __attribute__ ((packed)); +}__attribute__ ((packed)); struct SG64ENTRY { __le32 length; __le32 address; __le32 addresshigh; -} __attribute__ ((packed)); +}__attribute__ ((packed)); /* ******************************************************************** ** Q Buffer of IOP Message Transfer @@ -186,9 +186,9 @@ struct FIRMWARE_INFO char model[8]; /*15, 60-67*/ char firmware_ver[16]; /*17, 68-83*/ char device_map[16]; /*21, 84-99*/ - uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/ - uint8_t cfgSerial[16]; /*26,104-119*/ - uint32_t cfgPicStatus; /*30,120-123*/ + uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/ + uint8_t cfgSerial[16]; /*26,104-119*/ + uint32_t cfgPicStatus; /*30,120-123*/ }; /* signature of set and get firmware config */ #define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 @@ -212,11 +212,15 @@ struct FIRMWARE_INFO #define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000 #define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000 #define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000 -#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 +#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0 0x10000000 +#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1 0x00000001 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 /* ARC-1680 Bus Reset*/ #define ARCMSR_ARC1680_BUS_RESET 0x00000003 +/* ARC-1880 Bus Reset*/ +#define ARCMSR_ARC1880_RESET_ADAPTER 0x00000024 +#define ARCMSR_ARC1880_DiagWrite_ENABLE 0x00000080 /* ************************************************************************ @@ -273,6 +277,61 @@ struct FIRMWARE_INFO #define ARCMSR_MESSAGE_RBUFFER 0x0000ff00 /* iop message_rwbuffer for message command */ #define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00 +/* +************************************************************************ +** SPEC. for Areca HBC adapter +************************************************************************ +*/ +#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12 +#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20 +/* Host Interrupt Mask */ +#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/ +#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/ +#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/ +#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */ +/* Host Interrupt Status */ +#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001 + /* + ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register. + ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled). + */ +#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004 + /* + ** Set if Outbound Doorbell register bits 30:1 have a non-zero + ** value. This bit clears only when Outbound Doorbell bits + ** 30:1 are ALL clear. Only a write to the Outbound Doorbell + ** Clear register clears bits in the Outbound Doorbell register. + */ +#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008 + /* + ** Set whenever the Outbound Post List Producer/Consumer + ** Register (FIFO) is not empty. It clears when the Outbound + ** Post List FIFO is empty. + */ +#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010 + /* + ** This bit indicates a SAS interrupt from a source external to + ** the PCIe core. This bit is not maskable. + */ + /* DoorBell*/ +#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002 +#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004 + /*inbound message 0 ready*/ +#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008 + /*more than 12 request completed in a time*/ +#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010 +#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002 + /*outbound DATA WRITE isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002 +#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004 + /*outbound DATA READ isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004 + /*outbound message 0 ready*/ +#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 + /*outbound message cmd isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008 + /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/ +#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -310,7 +369,7 @@ struct ARCMSR_CDB struct SG32ENTRY sg32entry[1]; struct SG64ENTRY sg64entry[1]; } u; -} __attribute__ ((packed)); +}; /* ******************************************************************************* ** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor @@ -356,7 +415,81 @@ struct MessageUnit_B uint32_t __iomem *message_wbuffer; uint32_t __iomem *message_rbuffer; }; - +/* +********************************************************************* +** LSI +********************************************************************* +*/ +struct MessageUnit_C{ + uint32_t message_unit_status; /*0000 0003*/ + uint32_t slave_error_attribute; /*0004 0007*/ + uint32_t slave_error_address; /*0008 000B*/ + uint32_t posted_outbound_doorbell; /*000C 000F*/ + uint32_t master_error_attribute; /*0010 0013*/ + uint32_t master_error_address_low; /*0014 0017*/ + uint32_t master_error_address_high; /*0018 001B*/ + uint32_t hcb_size; /*001C 001F*/ + uint32_t inbound_doorbell; /*0020 0023*/ + uint32_t diagnostic_rw_data; /*0024 0027*/ + uint32_t diagnostic_rw_address_low; /*0028 002B*/ + uint32_t diagnostic_rw_address_high; /*002C 002F*/ + uint32_t host_int_status; /*0030 0033*/ + uint32_t host_int_mask; /*0034 0037*/ + uint32_t dcr_data; /*0038 003B*/ + uint32_t dcr_address; /*003C 003F*/ + uint32_t inbound_queueport; /*0040 0043*/ + uint32_t outbound_queueport; /*0044 0047*/ + uint32_t hcb_pci_address_low; /*0048 004B*/ + uint32_t hcb_pci_address_high; /*004C 004F*/ + uint32_t iop_int_status; /*0050 0053*/ + uint32_t iop_int_mask; /*0054 0057*/ + uint32_t iop_inbound_queue_port; /*0058 005B*/ + uint32_t iop_outbound_queue_port; /*005C 005F*/ + uint32_t inbound_free_list_index; /*0060 0063*/ + uint32_t inbound_post_list_index; /*0064 0067*/ + uint32_t outbound_free_list_index; /*0068 006B*/ + uint32_t outbound_post_list_index; /*006C 006F*/ + uint32_t inbound_doorbell_clear; /*0070 0073*/ + uint32_t i2o_message_unit_control; /*0074 0077*/ + uint32_t last_used_message_source_address_low; /*0078 007B*/ + uint32_t last_used_message_source_address_high; /*007C 007F*/ + uint32_t pull_mode_data_byte_count[4]; /*0080 008F*/ + uint32_t message_dest_address_index; /*0090 0093*/ + uint32_t done_queue_not_empty_int_counter_timer; /*0094 0097*/ + uint32_t utility_A_int_counter_timer; /*0098 009B*/ + uint32_t outbound_doorbell; /*009C 009F*/ + uint32_t outbound_doorbell_clear; /*00A0 00A3*/ + uint32_t message_source_address_index; /*00A4 00A7*/ + uint32_t message_done_queue_index; /*00A8 00AB*/ + uint32_t reserved0; /*00AC 00AF*/ + uint32_t inbound_msgaddr0; /*00B0 00B3*/ + uint32_t inbound_msgaddr1; /*00B4 00B7*/ + uint32_t outbound_msgaddr0; /*00B8 00BB*/ + uint32_t outbound_msgaddr1; /*00BC 00BF*/ + uint32_t inbound_queueport_low; /*00C0 00C3*/ + uint32_t inbound_queueport_high; /*00C4 00C7*/ + uint32_t outbound_queueport_low; /*00C8 00CB*/ + uint32_t outbound_queueport_high; /*00CC 00CF*/ + uint32_t iop_inbound_queue_port_low; /*00D0 00D3*/ + uint32_t iop_inbound_queue_port_high; /*00D4 00D7*/ + uint32_t iop_outbound_queue_port_low; /*00D8 00DB*/ + uint32_t iop_outbound_queue_port_high; /*00DC 00DF*/ + uint32_t message_dest_queue_port_low; /*00E0 00E3*/ + uint32_t message_dest_queue_port_high; /*00E4 00E7*/ + uint32_t last_used_message_dest_address_low; /*00E8 00EB*/ + uint32_t last_used_message_dest_address_high; /*00EC 00EF*/ + uint32_t message_done_queue_base_address_low; /*00F0 00F3*/ + uint32_t message_done_queue_base_address_high; /*00F4 00F7*/ + uint32_t host_diagnostic; /*00F8 00FB*/ + uint32_t write_sequence; /*00FC 00FF*/ + uint32_t reserved1[34]; /*0100 0187*/ + uint32_t reserved2[1950]; /*0188 1FFF*/ + uint32_t message_wbuffer[32]; /*2000 207F*/ + uint32_t reserved3[32]; /*2080 20FF*/ + uint32_t message_rbuffer[32]; /*2100 217F*/ + uint32_t reserved4[32]; /*2180 21FF*/ + uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/ +}; /* ******************************************************************************* ** Adapter Control Block @@ -374,11 +507,14 @@ struct AdapterControlBlock unsigned long vir2phy_offset; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; + uint32_t cdb_phyaddr_hi32; + uint32_t reg_mu_acc_handle0; spinlock_t eh_lock; spinlock_t ccblist_lock; union { - struct MessageUnit_A __iomem * pmuA; - struct MessageUnit_B * pmuB; + struct MessageUnit_A __iomem *pmuA; + struct MessageUnit_B *pmuB; + struct MessageUnit_C __iomem *pmuC; }; /* message unit ATU inbound base address0 */ void __iomem *mem_base0; @@ -399,6 +535,8 @@ struct AdapterControlBlock /* message clear rqbuffer */ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 #define ACB_F_BUS_RESET 0x0080 + #define ACB_F_BUS_HANG_ON 0x0800/* need hardware reset bus */ + #define ACB_F_IOP_INITED 0x0100 /* iop init */ #define ACB_F_ABORT 0x0200 @@ -441,9 +579,9 @@ struct AdapterControlBlock uint32_t firm_numbers_queue; uint32_t firm_sdram_size; uint32_t firm_hd_channels; - uint32_t firm_cfg_version; - char firm_model[12]; - char firm_version[20]; + uint32_t firm_cfg_version; + char firm_model[12]; + char firm_version[20]; char device_map[20]; /*21,84-99*/ struct work_struct arcmsr_do_message_isr_bh; struct timer_list eternal_timer; @@ -460,31 +598,31 @@ struct AdapterControlBlock ** this CCB length must be 32 bytes boundary ******************************************************************************* */ -struct CommandControlBlock -{ +struct CommandControlBlock{ /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ struct list_head list; /*x32: 8byte, x64: 16byte*/ struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */ struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/ - uint32_t shifted_cdb_phyaddr; /*x32: 4byte, x64: 4byte*/ + uint32_t cdb_phyaddr_pattern; /*x32: 4byte, x64: 4byte*/ + uint32_t arc_cdb_size; /*x32:4byte,x64:4byte*/ uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ - #define CCB_FLAG_READ 0x0000 - #define CCB_FLAG_WRITE 0x0001 - #define CCB_FLAG_ERROR 0x0002 - #define CCB_FLAG_FLUSHCACHE 0x0004 - #define CCB_FLAG_MASTER_ABORTED 0x0008 + #define CCB_FLAG_READ 0x0000 + #define CCB_FLAG_WRITE 0x0001 + #define CCB_FLAG_ERROR 0x0002 + #define CCB_FLAG_FLUSHCACHE 0x0004 + #define CCB_FLAG_MASTER_ABORTED 0x0008 uint16_t startdone; /*x32:2byte,x32:2byte*/ - #define ARCMSR_CCB_DONE 0x0000 - #define ARCMSR_CCB_START 0x55AA - #define ARCMSR_CCB_ABORTED 0xAA55 - #define ARCMSR_CCB_ILLEGAL 0xFFFF + #define ARCMSR_CCB_DONE 0x0000 + #define ARCMSR_CCB_START 0x55AA + #define ARCMSR_CCB_ABORTED 0xAA55 + #define ARCMSR_CCB_ILLEGAL 0xFFFF #if BITS_PER_LONG == 64 /* ======================512+64 bytes======================== */ - uint32_t reserved[6]; /*24 byte*/ -#else + uint32_t reserved[5]; /*24 byte*/ + #else /* ======================512+32 bytes======================== */ - uint32_t reserved[2]; /*8 byte*/ -#endif + uint32_t reserved; /*8 byte*/ + #endif /* ======================================================= */ struct ARCMSR_CDB arcmsr_cdb; }; diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 07fdfe57e38..69f8346aa28 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -59,8 +59,7 @@ struct device_attribute *arcmsr_host_attrs[]; -static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -106,8 +105,7 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, return (allxfer_len); } -static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -155,8 +153,7 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, } } -static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index ba33473b27a..95a895dd4f1 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -71,11 +71,11 @@ #include #include "arcmsr.h" MODULE_AUTHOR("Nick Cheng "); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter"); +MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int sleeptime = 20; -static int retrycount = 12; +static int sleeptime = 10; +static int retrycount = 30; wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); @@ -99,10 +99,12 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); static void arcmsr_request_device_map(unsigned long pacb); static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb); static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb); +static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb); static void arcmsr_message_isr_bh_fn(struct work_struct *work); static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); - +static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB); +static void arcmsr_hardware_reset(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, @@ -119,18 +121,18 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, static struct scsi_host_template arcmsr_scsi_host_template = { .module = THIS_MODULE, - .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter" - ARCMSR_DRIVER_VERSION, + .name = "ARCMSR ARECA SATA/SAS RAID Controller" + ARCMSR_DRIVER_VERSION, .info = arcmsr_info, .queuecommand = arcmsr_queue_command, - .eh_abort_handler = arcmsr_abort, + .eh_abort_handler = arcmsr_abort, .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, .change_queue_depth = arcmsr_adjust_disk_queue_depth, .can_queue = ARCMSR_MAX_FREECCB_NUM, - .this_id = ARCMSR_SCSI_INITIATOR_ID, - .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, - .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, + .this_id = ARCMSR_SCSI_INITIATOR_ID, + .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, + .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = arcmsr_host_attrs, @@ -160,22 +162,45 @@ static struct pci_device_id arcmsr_device_id_table[] = { MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); static struct pci_driver arcmsr_pci_driver = { .name = "arcmsr", - .id_table = arcmsr_device_id_table, + .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, .shutdown = arcmsr_shutdown, }; +/* +**************************************************************************** +**************************************************************************** +*/ +int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *shost = NULL; + int i, isleep; + shost = cmd->device->host; + isleep = sleeptime / 10; + if (isleep > 0) { + for (i = 0; i < isleep; i++) { + msleep(10000); + } + } + + isleep = sleeptime % 10; + if (isleep > 0) { + msleep(isleep*1000); + } + printk(KERN_NOTICE "wake-up\n"); + return 0; +} -static void arcmsr_free_mu(struct AdapterControlBlock *acb) +static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: + case ACB_ADAPTER_TYPE_C: break; case ACB_ADAPTER_TYPE_B:{ - struct MessageUnit_B *reg = acb->pmuB; - dma_free_coherent(&acb->pdev->dev, - sizeof(struct MessageUnit_B), - reg, acb->dma_coherent_handle_hbb_mu); + dma_free_coherent(&acb->pdev->dev, + sizeof(struct MessageUnit_B), + acb->pmuB, acb->dma_coherent_handle_hbb_mu); } } } @@ -183,10 +208,9 @@ static void arcmsr_free_mu(struct AdapterControlBlock *acb) static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; - - switch (acb->adapter_type) { + switch (acb->adapter_type){ case ACB_ADAPTER_TYPE_A:{ - acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0)); if (!acb->pmuA) { printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); return false; @@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) } acb->mem_base0 = mem_base0; acb->mem_base1 = mem_base1; + break; + } + case ACB_ADAPTER_TYPE_C:{ + acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + if (!acb->pmuC) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/ + return true; + } + break; } } return true; @@ -216,13 +253,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A:{ - iounmap(acb->pmuA); - } - case ACB_ADAPTER_TYPE_B:{ - iounmap(acb->mem_base0); - iounmap(acb->mem_base1); - } + case ACB_ADAPTER_TYPE_A:{ + iounmap(acb->pmuA); + } + break; + case ACB_ADAPTER_TYPE_B:{ + iounmap(acb->mem_base0); + iounmap(acb->mem_base1); + } + + break; + case ACB_ADAPTER_TYPE_C:{ + iounmap(acb->pmuC); + } } } @@ -270,34 +313,37 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); acb->dev_id = dev_id; switch (dev_id) { - case 0x1201 : { + case 0x1880: { + acb->adapter_type = ACB_ADAPTER_TYPE_C; + } + break; + case 0x1201: { acb->adapter_type = ACB_ADAPTER_TYPE_B; } break; - default : acb->adapter_type = ACB_ADAPTER_TYPE_A; + default: acb->adapter_type = ACB_ADAPTER_TYPE_A; } -} +} static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; uint32_t Index; uint8_t Retries = 0x00; - do { for (Index = 0; Index < 100; Index++) { if (readl(®->outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); - return 0x00; + return true; } msleep(10); - } /*max 1 seconds*/ + }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return false; } static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) @@ -305,7 +351,6 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) struct MessageUnit_B *reg = acb->pmuB; uint32_t Index; uint8_t Retries = 0x00; - do { for (Index = 0; Index < 100; Index++) { if (readl(reg->iop2drv_doorbell) @@ -313,23 +358,39 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell); writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - return 0x00; + return true; } msleep(10); - } /*max 1 seconds*/ + }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return false; } +static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + unsigned char Retries = 0x00; + uint32_t Index; + do { + for (Index = 0; Index < 100; Index++) { + if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/ + return true; + } + /* one us delay */ + msleep(10); + } /*max 1 seconds*/ + } while (Retries++ < 20); /*max 20 sec*/ + return false; +} static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; int retry_count = 30; - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); do { - if (!arcmsr_hba_wait_msgint_ready(acb)) + if (arcmsr_hba_wait_msgint_ready(acb)) break; else { retry_count--; @@ -343,10 +404,9 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; int retry_count = 30; - writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); do { - if (!arcmsr_hbb_wait_msgint_ready(acb)) + if (arcmsr_hbb_wait_msgint_ready(acb)) break; else { retry_count--; @@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) } while (retry_count != 0); } +static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */ + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + do { + if (arcmsr_hbc_wait_msgint_ready(pACB)) { + break; + } else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", pACB->host->host_no, retry_count); + } + } while (retry_count != 0); + return; +} static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -368,151 +445,94 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { arcmsr_flush_hbb_cache(acb); } + break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_flush_hbc_cache(acb); + } } } static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) { - struct pci_dev *pdev = acb->pdev; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - - void *dma_coherent; - dma_addr_t dma_coherent_handle; - struct CommandControlBlock *ccb_tmp; - int i = 0, j = 0; - dma_addr_t cdb_phyaddr; - unsigned long roundup_ccbsize = 0; - unsigned long max_xfer_len; - unsigned long max_sg_entrys; - uint32_t firm_config_version; - - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; - - max_xfer_len = ARCMSR_MAX_XFER_LEN; - max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; - firm_config_version = acb->firm_cfg_version; - if ((firm_config_version & 0xFF) >= 3) { - max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ - max_sg_entrys = (max_xfer_len/4096); - } - acb->host->max_sectors = max_xfer_len/512; - acb->host->sg_tablesize = max_sg_entrys; - roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32); - acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; - dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) { - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); - return -ENOMEM; - } - memset(dma_coherent, 0, acb->uncache_size); - acb->dma_coherent = dma_coherent; - acb->dma_coherent_handle = dma_coherent_handle; - ccb_tmp = (struct CommandControlBlock *)dma_coherent; - acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); - ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; - acb->pccb_pool[i] = ccb_tmp; - ccb_tmp->acb = acb; - INIT_LIST_HEAD(&ccb_tmp->list); - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; - } - break; - } - case ACB_ADAPTER_TYPE_B: { - - void *dma_coherent; - dma_addr_t dma_coherent_handle; - struct CommandControlBlock *ccb_tmp; - uint32_t cdb_phyaddr; - unsigned int roundup_ccbsize = 0; - unsigned long max_xfer_len; - unsigned long max_sg_entrys; - unsigned long firm_config_version; - unsigned long max_freeccb_num = 0; - int i = 0, j = 0; - - max_freeccb_num = ARCMSR_MAX_FREECCB_NUM; - max_xfer_len = ARCMSR_MAX_XFER_LEN; - max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; - firm_config_version = acb->firm_cfg_version; - if ((firm_config_version & 0xFF) >= 3) { - max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << - ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ - max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/ - } - acb->host->max_sectors = max_xfer_len / 512; - acb->host->sg_tablesize = max_sg_entrys; - roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+ - (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); - acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; - dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, - &dma_coherent_handle, GFP_KERNEL); - - if (!dma_coherent) { - printk(KERN_NOTICE "DMA allocation failed...........................\n"); - return -ENOMEM; - } - memset(dma_coherent, 0, acb->uncache_size); - acb->dma_coherent = dma_coherent; - acb->dma_coherent_handle = dma_coherent_handle; - ccb_tmp = (struct CommandControlBlock *)dma_coherent; - acb->vir2phy_offset = (unsigned long)dma_coherent - - (unsigned long)dma_coherent_handle; - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - cdb_phyaddr = dma_coherent_handle + - offsetof(struct CommandControlBlock, arcmsr_cdb); - ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; - acb->pccb_pool[i] = ccb_tmp; - ccb_tmp->acb = acb; - INIT_LIST_HEAD(&ccb_tmp->list); - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + - roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; - } - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; - } - break; + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle; + struct CommandControlBlock *ccb_tmp; + int i = 0, j = 0; + dma_addr_t cdb_phyaddr; + unsigned long roundup_ccbsize = 0, offset; + unsigned long max_xfer_len; + unsigned long max_sg_entrys; + uint32_t firm_config_version; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; + + max_xfer_len = ARCMSR_MAX_XFER_LEN; + max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; + firm_config_version = acb->firm_cfg_version; + if((firm_config_version & 0xFF) >= 3){ + max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ + max_sg_entrys = (max_xfer_len/4096); + } + acb->host->max_sectors = max_xfer_len/512; + acb->host->sg_tablesize = max_sg_entrys; + roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); + if(!dma_coherent){ + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); + return -ENOMEM; + } + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; + memset(dma_coherent, 0, acb->uncache_size); + offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent; + dma_coherent_handle = dma_coherent_handle + offset; + dma_coherent = (struct CommandControlBlock *)dma_coherent + offset; + ccb_tmp = dma_coherent; + acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; + for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ + cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); + ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5)); + acb->pccb_pool[i] = ccb_tmp; + ccb_tmp->acb = acb; + INIT_LIST_HEAD(&ccb_tmp->list); + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } return 0; } -static void arcmsr_message_isr_bh_fn(struct work_struct *work) -{ - struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh); +static void arcmsr_message_isr_bh_fn(struct work_struct *work) +{ + struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh); switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem *) (®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem *) (®->message_rwbuffer[21]); + uint32_t __iomem *signature = (uint32_t __iomem*) (®->message_rwbuffer[0]); + char __iomem *devicemap = (char __iomem*) (®->message_rwbuffer[21]); int target, lun; struct scsi_device *psdev; char diff; atomic_inc(&acb->rq_map_token); if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) { + for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { diff = (*acb_dev_map)^readb(devicemap); if (diff != 0) { char temp; *acb_dev_map = readb(devicemap); - temp = *acb_dev_map; - for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if ((temp & 0x01) == 1 && (diff & 0x01) == 1) { + temp =*acb_dev_map; + for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { + if((temp & 0x01)==1 && (diff & 0x01) == 1) { scsi_add_device(acb->host, 0, target, lun); - } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) { + }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL) { + if (psdev != NULL ) { scsi_remove_device(psdev); scsi_device_put(psdev); } @@ -531,8 +551,45 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem *)(®->message_rwbuffer[21]); + uint32_t __iomem *signature = (uint32_t __iomem*)(®->message_rwbuffer[0]); + char __iomem *devicemap = (char __iomem*)(®->message_rwbuffer[21]); + int target, lun; + struct scsi_device *psdev; + char diff; + + atomic_inc(&acb->rq_map_token); + if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { + for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { + diff = (*acb_dev_map)^readb(devicemap); + if (diff != 0) { + char temp; + *acb_dev_map = readb(devicemap); + temp =*acb_dev_map; + for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { + if((temp & 0x01)==1 && (diff & 0x01) == 1) { + scsi_add_device(acb->host, 0, target, lun); + }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { + psdev = scsi_device_lookup(acb->host, 0, target, lun); + if (psdev != NULL ) { + scsi_remove_device(psdev); + scsi_device_put(psdev); + } + } + temp >>= 1; + diff >>= 1; + } + } + devicemap++; + acb_dev_map++; + } + } + } + break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = acb->pmuC; + char *acb_dev_map = (char *)acb->device_map; + uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); + char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); int target, lun; struct scsi_device *psdev; char diff; @@ -571,21 +628,20 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *host; struct AdapterControlBlock *acb; - uint8_t bus, dev_fun; + uint8_t bus,dev_fun; int error; - error = pci_enable_device(pdev); - if (error) { + if(error){ return -ENODEV; } host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); - if (!host) { - goto pci_disable_dev; + if(!host){ + goto pci_disable_dev; } error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (error) { + if(error){ error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (error) { + if(error){ printk(KERN_WARNING "scsi%d: No suitable DMA mask available\n", host->host_no); @@ -596,53 +652,53 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus = pdev->bus->number; dev_fun = pdev->devfn; acb = (struct AdapterControlBlock *) host->hostdata; - memset(acb, 0, sizeof(struct AdapterControlBlock)); + memset(acb,0,sizeof(struct AdapterControlBlock)); acb->pdev = pdev; acb->host = host; host->max_lun = ARCMSR_MAX_TARGETLUN; - host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ - host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ - host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ - host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; + host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/ + host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/ + host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ + host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; pci_set_drvdata(pdev, host); pci_set_master(pdev); error = pci_request_regions(pdev, "arcmsr"); - if (error) { + if(error){ goto scsi_host_release; } spin_lock_init(&acb->eh_lock); spin_lock_init(&acb->ccblist_lock); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_RQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); + ACB_F_MESSAGE_RQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; INIT_LIST_HEAD(&acb->ccb_free_list); arcmsr_define_adapter_type(acb); error = arcmsr_remap_pciregion(acb); - if (!error) { + if(!error){ goto pci_release_regs; } error = arcmsr_get_firmware_spec(acb); - if (!error) { + if(!error){ goto unmap_pci_region; } error = arcmsr_alloc_ccb_pool(acb); - if (error) { + if(error){ goto free_hbb_mu; } arcmsr_iop_init(acb); error = scsi_add_host(host, &pdev->dev); - if (error) { + if(error){ goto RAID_controller_stop; } error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); - if (error) { + if(error){ goto scsi_host_remove; } host->irq = pdev->irq; - scsi_scan_host(host); + scsi_scan_host(host); INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); @@ -652,10 +708,10 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) acb->eternal_timer.data = (unsigned long) acb; acb->eternal_timer.function = &arcmsr_request_device_map; add_timer(&acb->eternal_timer); - if (arcmsr_alloc_sysfs_attr(acb)) + if(arcmsr_alloc_sysfs_attr(acb)) goto out_free_sysfs; return 0; - out_free_sysfs: +out_free_sysfs: scsi_host_remove: scsi_remove_host(host); RAID_controller_stop: @@ -663,7 +719,7 @@ RAID_controller_stop: arcmsr_flush_adapter_cache(acb); arcmsr_free_ccb_pool(acb); free_hbb_mu: - arcmsr_free_mu(acb); + arcmsr_free_hbb_mu(acb); unmap_pci_region: arcmsr_unmap_pciregion(acb); pci_release_regs: @@ -678,15 +734,14 @@ pci_disable_dev: static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; - writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - if (arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no); - return 0xff; + return false; } - return 0x00; + return true; } static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) @@ -694,15 +749,27 @@ static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no); - return 0xff; + return false; } - return 0x00; + return true; +} +static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + printk(KERN_NOTICE + "arcmsr%d: wait 'abort all outstanding command' timeout \n" + , pACB->host->host_no); + return false; + } + return true; } - static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) { uint8_t rtnval = 0; @@ -715,6 +782,11 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { rtnval = arcmsr_abort_hbb_allcmd(acb); } + break; + + case ACB_ADAPTER_TYPE_C: { + rtnval = arcmsr_abort_hbc_allcmd(acb); + } } return rtnval; } @@ -722,13 +794,12 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb) { struct MessageUnit_B *reg = pacb->pmuB; - writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(pacb)) { + if (!arcmsr_hbb_wait_msgint_ready(pacb)) { printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no); return false; -} - return true; + } + return true; } static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) @@ -736,18 +807,16 @@ static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) struct scsi_cmnd *pcmd = ccb->pcmd; scsi_dma_unmap(pcmd); - } +} static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) { struct AdapterControlBlock *acb = ccb->acb; struct scsi_cmnd *pcmd = ccb->pcmd; unsigned long flags; - atomic_dec(&acb->ccboutstandingcount); arcmsr_pci_unmap_dma(ccb); ccb->startdone = ARCMSR_CCB_DONE; - ccb->ccb_flags = 0; spin_lock_irqsave(&acb->ccblist_lock, flags); list_add_tail(&ccb->list, &acb->ccb_free_list); spin_unlock_irqrestore(&acb->ccblist_lock, flags); @@ -759,7 +828,6 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) struct scsi_cmnd *pcmd = ccb->pcmd; struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; - pcmd->result = DID_OK << 16; if (sensebuffer) { int sense_data_length = @@ -775,8 +843,7 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) { u32 orig_mask = 0; - switch (acb->adapter_type) { - + switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A : { struct MessageUnit_A __iomem *reg = acb->pmuA; orig_mask = readl(®->outbound_intmask); @@ -784,30 +851,35 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) ®->outbound_intmask); } break; - case ACB_ADAPTER_TYPE_B : { struct MessageUnit_B *reg = acb->pmuB; orig_mask = readl(reg->iop2drv_doorbell_mask); writel(0, reg->iop2drv_doorbell_mask); } break; + case ACB_ADAPTER_TYPE_C:{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + /* disable all outbound interrupt */ + orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */ + writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); + } + break; } return orig_mask; } -static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, - struct CommandControlBlock *ccb, uint32_t flag_ccb) +static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, + struct CommandControlBlock *ccb, bool error) { - uint8_t id, lun; id = ccb->pcmd->device->id; lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { + if (!error) { if (acb->devstate[id][lun] == ARECA_RAID_GONE) acb->devstate[id][lun] = ARECA_RAID_GOOD; ccb->pcmd->result = DID_OK << 16; arcmsr_ccb_complete(ccb); - } else { + }else{ switch (ccb->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: { acb->devstate[id][lun] = ARECA_RAID_GONE; @@ -833,42 +905,37 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, break; default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d" - " isr get command error done, " - "but got unknown DeviceStatus = 0x%x \n" - , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb); + printk(KERN_NOTICE + "arcmsr%d: scsi id = %d lun = %d isr get command error done, \ + but got unknown DeviceStatus = 0x%x \n" + , acb->host->host_no + , id + , lun + , ccb->arcmsr_cdb.DeviceStatus); + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(ccb); break; } } } -static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb) +static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) { - struct CommandControlBlock *ccb; - struct ARCMSR_CDB *arcmsr_cdb; int id, lun; - - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); - ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if (ccb->startdone == ARCMSR_CCB_ABORTED) { - struct scsi_cmnd *abortcmd = ccb->pcmd; + if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { + if (pCCB->startdone == ARCMSR_CCB_ABORTED) { + struct scsi_cmnd *abortcmd = pCCB->pcmd; if (abortcmd) { id = abortcmd->device->id; - lun = abortcmd->device->lun; + lun = abortcmd->device->lun; abortcmd->result |= DID_ABORT << 16; - arcmsr_ccb_complete(ccb); - printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \ - isr got aborted command \n", acb->host->host_no, ccb); + arcmsr_ccb_complete(pCCB); + printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n", + acb->host->host_no, pCCB); } + return; } printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ done acb = '0x%p'" @@ -876,20 +943,22 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla " ccboutstandingcount = %d \n" , acb->host->host_no , acb - , ccb - , ccb->acb - , ccb->startdone + , pCCB + , pCCB->acb + , pCCB->startdone , atomic_read(&acb->ccboutstandingcount)); + return; } - else - arcmsr_report_ccb_state(acb, ccb, flag_ccb); + arcmsr_report_ccb_state(acb, pCCB, error); } static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) { int i = 0; uint32_t flag_ccb; - + struct ARCMSR_CDB *pARCMSR_CDB; + bool error; + struct CommandControlBlock *pCCB; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -899,9 +968,12 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) acb->outbound_int_enable; /*clear and abort all outbound posted Q*/ writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) + while(((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { - arcmsr_drain_donequeue(acb, flag_ccb); + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_drain_donequeue(acb, pCCB, error); } } break; @@ -909,17 +981,37 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; /*clear all outbound posted Q*/ + writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { writel(0, ®->done_qbuffer[i]); - arcmsr_drain_donequeue(acb, flag_ccb); + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ + pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_drain_donequeue(acb, pCCB, error); } - writel(0, ®->post_qbuffer[i]); + reg->post_qbuffer[i] = 0; } reg->doneq_index = 0; reg->postq_index = 0; } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = acb->pmuC; + struct ARCMSR_CDB *pARCMSR_CDB; + uint32_t flag_ccb, ccb_cdb_phy; + bool error; + struct CommandControlBlock *pCCB; + while ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { + /*need to do*/ + flag_ccb = readl(®->outbound_queueport_low); + ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/ + pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; + arcmsr_drain_donequeue(acb, pCCB, error); + } + } } } static void arcmsr_remove(struct pci_dev *pdev) @@ -930,16 +1022,15 @@ static void arcmsr_remove(struct pci_dev *pdev) int poll_count = 0; arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); - scsi_host_put(host); flush_scheduled_work(); del_timer_sync(&acb->eternal_timer); arcmsr_disable_outbound_ints(acb); arcmsr_stop_adapter_bgrb(acb); - arcmsr_flush_adapter_cache(acb); + arcmsr_flush_adapter_cache(acb); acb->acb_flags |= ACB_F_SCSISTOPADAPTER; acb->acb_flags &= ~ACB_F_IOP_INITED; - for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) { + for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){ if (!atomic_read(&acb->ccboutstandingcount)) break; arcmsr_interrupt(acb);/* FIXME: need spinlock */ @@ -962,8 +1053,10 @@ static void arcmsr_remove(struct pci_dev *pdev) } free_irq(pdev->irq, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_mu(acb); + arcmsr_free_hbb_mu(acb); + arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); + scsi_host_put(host); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -983,7 +1076,6 @@ static void arcmsr_shutdown(struct pci_dev *pdev) static int arcmsr_module_init(void) { int error = 0; - error = pci_register_driver(&arcmsr_pci_driver); return error; } @@ -999,10 +1091,9 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, u32 intmask_org) { u32 mask; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A : { + case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE| @@ -1012,7 +1103,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, } break; - case ACB_ADAPTER_TYPE_B : { + case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | ARCMSR_IOP2DRV_DATA_READ_OK | @@ -1021,6 +1112,13 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, writel(mask, reg->iop2drv_doorbell_mask); acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; } + break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = acb->pmuC; + mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); + writel(intmask_org & mask, ®->host_int_mask); + acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f; + } } } @@ -1032,75 +1130,69 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, __le32 address_lo, address_hi; int arccdbsize = 0x30; __le32 length = 0; - int i, cdb_sgcount = 0; + int i; struct scatterlist *sg; int nseg; - ccb->pcmd = pcmd; memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); - arcmsr_cdb->Bus = 0; arcmsr_cdb->TargetID = pcmd->device->id; arcmsr_cdb->LUN = pcmd->device->lun; arcmsr_cdb->Function = 1; - arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len; arcmsr_cdb->Context = 0; memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); - if (nseg > acb->host->sg_tablesize || nseg < 0) + if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0)) return FAILED; - /* map stor port SG list to our iop SG List. */ - scsi_for_each_sg(pcmd, sg, nseg, i) { - /* Get the physical address of the current data pointer */ - length = cpu_to_le32(sg_dma_len(sg)); - address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); - address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); - if (address_hi == 0) { - struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; - - pdma_sg->address = address_lo; - pdma_sg->length = length; - psge += sizeof (struct SG32ENTRY); - arccdbsize += sizeof (struct SG32ENTRY); - } else { - struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; + scsi_for_each_sg(pcmd, sg, nseg, i) { + /* Get the physical address of the current data pointer */ + length = cpu_to_le32(sg_dma_len(sg)); + address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); + address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); + if (address_hi == 0) { + struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; + + pdma_sg->address = address_lo; + pdma_sg->length = length; + psge += sizeof (struct SG32ENTRY); + arccdbsize += sizeof (struct SG32ENTRY); + } else { + struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; - pdma_sg->addresshigh = address_hi; - pdma_sg->address = address_lo; - pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); - psge += sizeof (struct SG64ENTRY); - arccdbsize += sizeof (struct SG64ENTRY); - } - cdb_sgcount++; + pdma_sg->addresshigh = address_hi; + pdma_sg->address = address_lo; + pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); + psge += sizeof (struct SG64ENTRY); + arccdbsize += sizeof (struct SG64ENTRY); } - arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount; - arcmsr_cdb->DataLength = scsi_bufflen(pcmd); + } + arcmsr_cdb->sgcount = (uint8_t)nseg; + arcmsr_cdb->DataLength = scsi_bufflen(pcmd); arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0); - if ( arccdbsize > 256) - arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; - if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) { + if ( arccdbsize > 256) + arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; + if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 || pcmd->cmnd[0]|WRITE_12 ){ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; - ccb->ccb_flags |= CCB_FLAG_WRITE; } + ccb->arc_cdb_size = arccdbsize; return SUCCESS; } static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr; + uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; - switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); else { - writel(shifted_cdb_phyaddr, ®->inbound_queueport); + writel(cdb_phyaddr_pattern, ®->inbound_queueport); } } break; @@ -1112,11 +1204,10 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); writel(0, ®->post_qbuffer[ending_index]); if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ + writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ ®->post_qbuffer[index]); - } - else { - writel(shifted_cdb_phyaddr, ®->post_qbuffer[index]); + } else { + writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]); } index++; index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ @@ -1124,6 +1215,19 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell); } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; + uint32_t ccb_post_stamp, arc_cdb_size; + + arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; + ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1); + if (acb->cdb_phyaddr_hi32) { + writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); + writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); + } else { + writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); + } + } } } @@ -1132,8 +1236,7 @@ static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) struct MessageUnit_A __iomem *reg = acb->pmuA; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - - if (arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); @@ -1146,13 +1249,26 @@ static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); } } +static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + printk(KERN_NOTICE + "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + , pACB->host->host_no); + } + return; +} static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -1165,21 +1281,15 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) arcmsr_stop_hbb_bgrb(acb); } break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_stop_hbc_bgrb(acb); + } } } static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) { - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); - iounmap(acb->pmuA); - } - break; - case ACB_ADAPTER_TYPE_B: { - dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); - } - } + dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); } void arcmsr_iop_message_read(struct AdapterControlBlock *acb) @@ -1196,6 +1306,10 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb) writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C __iomem *reg = acb->pmuC; + writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + } } } @@ -1221,13 +1335,21 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell); } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C __iomem *reg = acb->pmuC; + /* + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post + */ + writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell); + } + break; } } struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) { struct QBUFFER __iomem *qbuffer = NULL; - switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -1241,6 +1363,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; + qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer; + } } return qbuffer; } @@ -1248,7 +1374,6 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) { struct QBUFFER __iomem *pqbuffer = NULL; - switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -1262,6 +1387,11 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer; + } + } return pqbuffer; } @@ -1272,19 +1402,18 @@ static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) struct QBUFFER *pQbuffer; uint8_t __iomem *iop_data; int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - rqbuf_lastindex = acb->rqbuf_lastindex; rqbuf_firstindex = acb->rqbuf_firstindex; prbuffer = arcmsr_get_iop_rqbuffer(acb); iop_data = (uint8_t __iomem *)prbuffer->data; iop_len = prbuffer->data_len; - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1); + my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1); if (my_empty_len >= iop_len) { while (iop_len > 0) { pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; - memcpy(pQbuffer, iop_data,1); + memcpy(pQbuffer, iop_data, 1); rqbuf_lastindex++; rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; iop_data++; @@ -1335,25 +1464,52 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) { uint32_t outbound_doorbell; struct MessageUnit_A __iomem *reg = acb->pmuA; - outbound_doorbell = readl(®->outbound_doorbell); writel(outbound_doorbell, ®->outbound_doorbell); if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { arcmsr_iop2drv_data_read_handle(acb); } } - +static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) +{ + uint32_t outbound_doorbell; + struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + /* + ******************************************************************* + ** Maybe here we need to check wrqbuffer_lock is lock or not + ** DOORBELL: din! don! + ** check if there are any mail need to pack from firmware + ******************************************************************* + */ + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell_clear);/*clear interrupt*/ + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(pACB); + } + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(pACB); + } + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */ + } + return; +} static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) { uint32_t flag_ccb; struct MessageUnit_A __iomem *reg = acb->pmuA; - + struct ARCMSR_CDB *pARCMSR_CDB; + struct CommandControlBlock *pCCB; + bool error; while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { - arcmsr_drain_donequeue(acb, flag_ccb); + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_drain_donequeue(acb, pCCB, error); } } @@ -1362,29 +1518,62 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) uint32_t index; uint32_t flag_ccb; struct MessageUnit_B *reg = acb->pmuB; - + struct ARCMSR_CDB *pARCMSR_CDB; + struct CommandControlBlock *pCCB; + bool error; index = reg->doneq_index; - while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { writel(0, ®->done_qbuffer[index]); - arcmsr_drain_donequeue(acb, flag_ccb); + pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ + pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_drain_donequeue(acb, pCCB, error); index++; index %= ARCMSR_MAX_HBB_POSTQUEUE; reg->doneq_index = index; } } + +static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) +{ + struct MessageUnit_C *phbcmu; + struct ARCMSR_CDB *arcmsr_cdb; + struct CommandControlBlock *ccb; + uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; + int error; + + phbcmu = (struct MessageUnit_C *)acb->pmuC; + /* areca cdb command done */ + /* Use correct offset and size for syncing */ + + while (readl(&phbcmu->host_int_status) & + ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ + /* check if command done with no error*/ + flag_ccb = readl(&phbcmu->outbound_queueport_low); + ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); + ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; + /* check if command done with no error */ + arcmsr_drain_donequeue(acb, ccb, error); + if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { + writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); + break; + } + throttling++; + } +} /* ********************************************************************************** ** Handle a message interrupt ** -** The only message interrupt we expect is in response to a query for the current adapter config. +** The only message interrupt we expect is in response to a query for the current adapter config. ** We want this in order to compare the drivemap so that we can detect newly-attached drives. ********************************************************************************** */ static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) { struct MessageUnit_A *reg = acb->pmuA; - /*clear interrupt and message state*/ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); schedule_work(&acb->arcmsr_do_message_isr_bh); @@ -1397,13 +1586,29 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); schedule_work(&acb->arcmsr_do_message_isr_bh); } +/* +********************************************************************************** +** Handle a message interrupt +** +** The only message interrupt we expect is in response to a query for the +** current adapter config. +** We want this in order to compare the drivemap so that we can detect newly-attached drives. +********************************************************************************** +*/ +static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) +{ + struct MessageUnit_C *reg = acb->pmuC; + /*clear interrupt and message state*/ + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear); + schedule_work(&acb->arcmsr_do_message_isr_bh); +} + static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) { uint32_t outbound_intstatus; struct MessageUnit_A __iomem *reg = acb->pmuA; - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; + acb->outbound_int_enable; if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { return 1; } @@ -1414,7 +1619,7 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { arcmsr_hba_postqueue_isr(acb); } - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { /* messenger of "driver to iop commands" */ arcmsr_hba_message_isr(acb); } @@ -1425,9 +1630,8 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) { uint32_t outbound_doorbell; struct MessageUnit_B *reg = acb->pmuB; - outbound_doorbell = readl(reg->iop2drv_doorbell) & - acb->outbound_int_enable; + acb->outbound_int_enable; if (!outbound_doorbell) return 1; @@ -1436,7 +1640,7 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) this action can push HW to write down the clear bit*/ readl(reg->iop2drv_doorbell); writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { @@ -1445,14 +1649,37 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { arcmsr_hbb_postqueue_isr(acb); } - if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { /* messenger of "driver to iop commands" */ arcmsr_hbb_message_isr(acb); } - return 0; } +static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) +{ + uint32_t host_interrupt_status; + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + /* + ********************************************* + ** check outbound intstatus + ********************************************* + */ + host_interrupt_status = readl(&phbcmu->host_int_status); + if (!host_interrupt_status) { + /*it must be share irq*/ + return 1; + } + /* MU ioctl transfer doorbell interrupts*/ + if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { + arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */ + } + /* MU post queue interrupts*/ + if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { + arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */ + } + return 0; +} static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -1469,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) } } break; + case ACB_ADAPTER_TYPE_C: { + if (arcmsr_handle_hbc_isr(acb)) { + return IRQ_NONE; + } + } } return IRQ_HANDLED; } @@ -1495,7 +1727,6 @@ void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) struct QBUFFER __iomem *pwbuffer; uint8_t __iomem *iop_data; int32_t allxfer_len = 0; - pwbuffer = arcmsr_get_iop_wqbuffer(acb); iop_data = (uint8_t __iomem *)pwbuffer->data; if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { @@ -1528,7 +1759,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, (uint32_t ) cmd->cmnd[7] << 8 | (uint32_t ) cmd->cmnd[8]; /* 4 bytes: Areca io control code */ - sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; if (scsi_sg_count(cmd) > 1) { @@ -1554,7 +1784,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - + ptmpQbuffer = ver_addr; while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) && (allxfer_len < 1031)) { @@ -1586,10 +1816,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, } memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + }else{ + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } kfree(ver_addr); } @@ -1605,11 +1835,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - if (acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = + if(acb->fw_flag == FW_DEADLOCK) { + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { - pcmdmessagefld->cmdmessage.ReturnCode = + }else{ + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } ptmpuserbuffer = ver_addr; @@ -1672,10 +1902,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { + }else{ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } @@ -1684,10 +1914,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { uint8_t *pQbuffer = acb->wqbuffer; - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { + }else{ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } @@ -1724,10 +1954,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, memset(pQbuffer, 0, sizeof(struct QBUFFER)); pQbuffer = acb->wqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { + }else{ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } @@ -1735,10 +1965,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, break; case ARCMSR_MESSAGE_RETURN_CODE_3F: { - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { + }else{ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; } @@ -1746,10 +1976,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, } case ARCMSR_MESSAGE_SAY_HELLO: { int8_t *hello_string = "Hello! I am ARCMSR"; - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } else { + }else{ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } @@ -1759,7 +1989,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, break; case ARCMSR_MESSAGE_SAY_GOODBYE: - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; } @@ -1767,7 +1997,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, break; case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: - if (acb->fw_flag == FW_DEADLOCK) { + if(acb->fw_flag == FW_DEADLOCK) { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; } @@ -1792,7 +2022,7 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock if (!list_empty(head)) { ccb = list_entry(head->next, struct CommandControlBlock, list); list_del_init(&ccb->list); - } else { + }else{ spin_unlock_irqrestore(&acb->ccblist_lock, flags); return 0; } @@ -1862,29 +2092,29 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, cmd->scsi_done = done; cmd->host_scribble = NULL; cmd->result = 0; - - if ((scsicmd == SYNCHRONIZE_CACHE) || (scsicmd == SEND_DIAGNOSTIC)) { - if (acb->devstate[target][lun] == ARECA_RAID_GONE) { - cmd->result = (DID_NO_CONNECT << 16); + if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){ + if(acb->devstate[target][lun] == ARECA_RAID_GONE) { + cmd->result = (DID_NO_CONNECT << 16); } cmd->scsi_done(cmd); return 0; } - if (target == 16) { /* virtual device for iop message transfer */ arcmsr_handle_virtual_command(acb, cmd); return 0; } - if (atomic_read(&acb->ccboutstandingcount) >= ARCMSR_MAX_OUTSTANDING_CMD) return SCSI_MLQUEUE_HOST_BUSY; - + if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) { + printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n"); + return 0; + } ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; - if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) { + if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) { cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); cmd->scsi_done(cmd); return 0; @@ -1901,17 +2131,16 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) char *acb_device_map = acb->device_map; char __iomem *iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); - char __iomem *iop_device_map = (char __iomem *) (®->message_rwbuffer[21]); + char __iomem *iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); int count; - writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - if (arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); return false; } count = 8; - while (count) { + while (count){ *acb_firm_model = readb(iop_firm_model); acb_firm_model++; iop_firm_model++; @@ -1919,25 +2148,25 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) } count = 16; - while (count) { + while (count){ *acb_firm_version = readb(iop_firm_version); acb_firm_version++; iop_firm_version++; count--; } - count = 16; - while (count) { - *acb_device_map = readb(iop_device_map); - acb_device_map++; - iop_device_map++; - count--; - } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + count=16; + while(count){ + *acb_device_map = readb(iop_device_map); + acb_device_map++; + iop_device_map++; + count--; + } + printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", acb->host->host_no, acb->firm_version, acb->firm_model); - acb->signature = readl(®->message_rwbuffer[0]); + acb->signature = readl(®->message_rwbuffer[0]); acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); acb->firm_sdram_size = readl(®->message_rwbuffer[3]); @@ -1962,14 +2191,14 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) /*firm_version,21,84-99*/ int count; dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) { + if (!dma_coherent){ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no); return false; } acb->dma_coherent_handle_hbb_mu = dma_coherent_handle; reg = (struct MessageUnit_B *)dma_coherent; acb->pmuB = reg; - reg->drv2iop_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); + reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK); reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL); reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK); @@ -1981,41 +2210,41 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); /*firm_version,21,84-99*/ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); return false; } count = 8; - while (count) { + while (count){ *acb_firm_model = readb(iop_firm_model); acb_firm_model++; iop_firm_model++; count--; } count = 16; - while (count) { + while (count){ *acb_firm_version = readb(iop_firm_version); acb_firm_version++; iop_firm_version++; count--; } - count = 16; - while (count) { - *acb_device_map = readb(iop_device_map); - acb_device_map++; - iop_device_map++; - count--; - } - + count = 16; + while(count){ + *acb_device_map = readb(iop_device_map); + acb_device_map++; + iop_device_map++; + count--; + } + printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", - acb->host->host_no, + acb->host->host_no, acb->firm_version, acb->firm_model); acb->signature = readl(®->message_rwbuffer[1]); - /*firm_signature,1,00-03*/ + /*firm_signature,1,00-03*/ acb->firm_request_len = readl(®->message_rwbuffer[2]); /*firm_request_len,1,04-07*/ acb->firm_numbers_queue = readl(®->message_rwbuffer[3]); @@ -2028,12 +2257,73 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) /*firm_ide_channels,4,16-19*/ return true; } + +static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) +{ + uint32_t intmask_org, Index, firmware_state = 0; + struct MessageUnit_C *reg = pACB->pmuC; + char *acb_firm_model = pACB->firm_model; + char *acb_firm_version = pACB->firm_version; + char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ + char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ + int count; + /* disable all outbound interrupt */ + intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */ + writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); + /* wait firmware ready */ + do { + firmware_state = readl(®->outbound_msgaddr1); + } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); + /* post "get config" instruction */ + writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + /* wait message ready */ + for (Index = 0; Index < 2000; Index++) { + if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);/*clear interrupt*/ + break; + } + udelay(10); + } /*max 1 seconds*/ + if (Index >= 2000) { + printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ + miscellaneous data' timeout \n", pACB->host->host_no); + return false; + } + count = 8; + while (count) { + *acb_firm_model = readb(iop_firm_model); + acb_firm_model++; + iop_firm_model++; + count--; + } + count = 16; + while (count) { + *acb_firm_version = readb(iop_firm_version); + acb_firm_version++; + iop_firm_version++; + count--; + } + printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + pACB->host->host_no, + pACB->firm_version, + pACB->firm_model); + pACB->firm_request_len = readl(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/ + pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/ + pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/ + pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/ + pACB->firm_cfg_version = readl(®->msgcode_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ + /*all interrupt service will be enable at arcmsr_iop_init*/ + return true; +} static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) { if (acb->adapter_type == ACB_ADAPTER_TYPE_A) return arcmsr_get_hba_config(acb); - else + else if (acb->adapter_type == ACB_ADAPTER_TYPE_B) return arcmsr_get_hbb_config(acb); + else + return arcmsr_get_hbc_config(acb); } static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, @@ -2044,18 +2334,19 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, struct ARCMSR_CDB *arcmsr_cdb; uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; int rtn; - + bool error; polling_hba_ccb_retry: poll_count++; outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (1) { if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { - if (poll_ccb_done) { + if (poll_ccb_done){ rtn = SUCCESS; break; - } else { - if (poll_count > 100) { + }else { + msleep(25); + if (poll_count > 100){ rtn = FAILED; break; } @@ -2084,76 +2375,132 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, , ccb , atomic_read(&acb->ccboutstandingcount)); continue; - } else { - arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_report_ccb_state(acb, ccb, error); } -} return rtn; } static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { - struct MessageUnit_B *reg = acb->pmuB; + struct MessageUnit_B *reg = acb->pmuB; struct ARCMSR_CDB *arcmsr_cdb; - struct CommandControlBlock *ccb; - uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; + struct CommandControlBlock *ccb; + uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; int index, rtn; - + bool error; polling_hbb_ccb_retry: - poll_count++; - /* clear doorbell interrupt */ + poll_count++; + /* clear doorbell interrupt */ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); - while (1) { - index = reg->doneq_index; - if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { - if (poll_ccb_done) { + while(1){ + index = reg->doneq_index; + if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { + if (poll_ccb_done){ rtn = SUCCESS; - break; - } else { - msleep(25); - if (poll_count > 100) { + break; + }else { + msleep(25); + if (poll_count > 100){ rtn = FAILED; - break; - } - goto polling_hbb_ccb_retry; + break; } + goto polling_hbb_ccb_retry; } - writel(0, ®->done_qbuffer[index]); - index++; - /*if last index number set it to 0 */ - index %= ARCMSR_MAX_HBB_POSTQUEUE; - reg->doneq_index = index; - /* check ifcommand done with no error*/ + } + writel(0, ®->done_qbuffer[index]); + index++; + /*if last index number set it to 0 */ + index %= ARCMSR_MAX_HBB_POSTQUEUE; + reg->doneq_index = index; + /* check if command done with no error*/ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (ccb == poll_ccb) ? 1:0; - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { + poll_ccb_done = (ccb == poll_ccb) ? 1:0; + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" " poll command abort successfully \n" - ,acb->host->host_no - ,ccb->pcmd->device->id - ,ccb->pcmd->device->lun - ,ccb); - ccb->pcmd->result = DID_ABORT << 16; + ,acb->host->host_no + ,ccb->pcmd->device->id + ,ccb->pcmd->device->lun + ,ccb); + ccb->pcmd->result = DID_ABORT << 16; arcmsr_ccb_complete(ccb); - continue; + continue; + } + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" + "ccboutstandingcount = %d \n" + , acb->host->host_no + , ccb + , atomic_read(&acb->ccboutstandingcount)); + continue; + } + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; + arcmsr_report_ccb_state(acb, ccb, error); + } + return rtn; +} + +static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) +{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + uint32_t flag_ccb, ccb_cdb_phy; + struct ARCMSR_CDB *arcmsr_cdb; + bool error; + struct CommandControlBlock *pCCB; + uint32_t poll_ccb_done = 0, poll_count = 0; + int rtn; +polling_hbc_ccb_retry: + poll_count++; + while (1) { + if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) { + if (poll_ccb_done) { + rtn = SUCCESS; + break; + } else { + msleep(25); + if (poll_count > 100) { + rtn = FAILED; + break; } - printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n" + goto polling_hbc_ccb_retry; + } + } + flag_ccb = readl(®->outbound_queueport_low); + ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ + pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); + poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0; + /* check ifcommand done with no error*/ + if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { + if (pCCB->startdone == ARCMSR_CCB_ABORTED) { + printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" + " poll command abort successfully \n" , acb->host->host_no - , ccb - , atomic_read(&acb->ccboutstandingcount)); + , pCCB->pcmd->device->id + , pCCB->pcmd->device->lun + , pCCB); + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB); continue; - } else { - arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" + "ccboutstandingcount = %d \n" + , acb->host->host_no + , pCCB + , atomic_read(&acb->ccboutstandingcount)); + continue; } - } /*drain reply FIFO*/ + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; + arcmsr_report_ccb_state(acb, pCCB, error); + } return rtn; } - static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { @@ -2168,6 +2515,10 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, case ACB_ADAPTER_TYPE_B: { rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb); } + break; + case ACB_ADAPTER_TYPE_C: { + rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb); + } } return rtn; } @@ -2185,6 +2536,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) dma_coherent_handle = acb->dma_coherent_handle; cdb_phyaddr = (uint32_t)(dma_coherent_handle); cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); + acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; /* *********************************************************************** ** if adapter type B, set window of "post command Q" @@ -2202,7 +2554,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ ®->inbound_msgaddr0); - if (arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ part physical address timeout\n", acb->host->host_no); @@ -2223,7 +2575,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) reg->postq_index = 0; reg->doneq_index = 0; writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ acb->host->host_no); return 1; @@ -2242,7 +2594,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) writel(1056, rwbuffer); writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ timeout \n",acb->host->host_no); return 1; @@ -2251,6 +2603,27 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) arcmsr_enable_outbound_ints(acb, intmask_org); } break; + case ACB_ADAPTER_TYPE_C: { + if (cdb_phyaddr_hi32 != 0) { + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + + if (cdb_phyaddr_hi32 != 0) { + unsigned char Retries = 0x00; + do { + printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32); + } while (Retries++ < 100); + } + writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); + writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); + writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + if (!arcmsr_hbc_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ + timeout \n", acb->host->host_no); + return 1; + } + } + } } return 0; } @@ -2258,7 +2631,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) { uint32_t firmware_state = 0; - switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -2277,24 +2649,30 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + do { + firmware_state = readl(®->outbound_msgaddr1); + } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); + } } } static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; - if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { + if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ return; } else { acb->fw_flag = FW_NORMAL; - if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { + if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){ atomic_set(&acb->rq_map_token, 16); } atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); if (atomic_dec_and_test(&acb->rq_map_token)) return; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } return; } @@ -2302,7 +2680,25 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_B __iomem *reg = acb->pmuB; + if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ + return; + } else { + acb->fw_flag = FW_NORMAL; + if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { + atomic_set(&acb->rq_map_token,16); + } + atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); + if(atomic_dec_and_test(&acb->rq_map_token)) + return; + writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); + } + return; +} +static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) +{ + struct MessageUnit_C __iomem *reg = acb->pmuC; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { return; } else { @@ -2313,8 +2709,9 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); if (atomic_dec_and_test(&acb->rq_map_token)) return; - writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); + writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); } return; } @@ -2322,7 +2719,6 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) static void arcmsr_request_device_map(unsigned long pacb) { struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb; - switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { arcmsr_request_hba_device_map(acb); @@ -2332,6 +2728,9 @@ static void arcmsr_request_device_map(unsigned long pacb) arcmsr_request_hbb_device_map(acb); } break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_request_hbc_device_map(acb); + } } } @@ -2340,7 +2739,7 @@ static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) struct MessageUnit_A __iomem *reg = acb->pmuA; acb->acb_flags |= ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); - if (arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n", acb->host->host_no); } @@ -2351,12 +2750,24 @@ static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags |= ACB_F_MSG_START_BGRB; writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); - if (arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n",acb->host->host_no); } } +static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + pACB->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0); + writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); + if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ + rebulid' timeout \n", pACB->host->host_no); + } + return; +} static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -2366,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: arcmsr_start_hbb_bgrb(acb); break; + case ACB_ADAPTER_TYPE_C: + arcmsr_start_hbc_bgrb(acb); } } @@ -2391,6 +2804,14 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) /* let IOP know data has been read */ } break; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + uint32_t outbound_doorbell; + /* empty doorbell Qbuffer if door bell ringed */ + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell_clear); + writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + } } } @@ -2403,12 +2824,14 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); - if(arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); return; } } break; + case ACB_ADAPTER_TYPE_C: + return; } return; } @@ -2416,21 +2839,33 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) { uint8_t value[64]; - int i; - struct MessageUnit_A __iomem *reg = acb->pmuA; - + int i, count = 0; + struct MessageUnit_A __iomem *pmuA = acb->pmuA; + struct MessageUnit_C __iomem *pmuC = acb->pmuC; + u32 temp = 0; /* backup pci config data */ - printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); + printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); for (i = 0; i < 64; i++) { pci_read_config_byte(acb->pdev, i, &value[i]); } /* hardware reset signal */ if ((acb->dev_id == 0x1680)) { - writel(ARCMSR_ARC1680_BUS_RESET, ®->reserved1[0]); + writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]); + } else if ((acb->dev_id == 0x1880)) { + do { + count++; + writel(0xF, &pmuC->write_sequence); + writel(0x4, &pmuC->write_sequence); + writel(0xB, &pmuC->write_sequence); + writel(0x2, &pmuC->write_sequence); + writel(0x7, &pmuC->write_sequence); + writel(0xD, &pmuC->write_sequence); + } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5)); + writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic); } else { - pci_write_config_byte(acb->pdev, 0x84, 0x20); + pci_write_config_byte(acb->pdev, 0x84, 0x20); } - msleep(1000); + msleep(2000); /* write back pci config data */ for (i = 0; i < 64; i++) { pci_write_config_byte(acb->pdev, i, value[i]); @@ -2438,35 +2873,11 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) msleep(1000); return; } -/* -**************************************************************************** -**************************************************************************** -*/ - int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) - { - struct Scsi_Host *shost = NULL; - int i, isleep; - - shost = cmd->device->host; - isleep = sleeptime / 10; - if (isleep > 0) { - for (i = 0; i < isleep; i++) { - msleep(10000); - } - } - - isleep = sleeptime % 10; - if (isleep > 0) { - msleep(isleep * 1000); - } - return 0; - } static void arcmsr_iop_init(struct AdapterControlBlock *acb) { uint32_t intmask_org; - - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_wait_firmware_ready(acb); arcmsr_iop_confirm(acb); /*start background rebuild*/ @@ -2485,7 +2896,6 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) uint32_t intmask_org; uint8_t rtnval = 0x00; int i = 0; - if (atomic_read(&acb->ccboutstandingcount) != 0) { /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); @@ -2514,54 +2924,50 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) uint32_t intmask_org, outbound_doorbell; int retry_count = 0; int rtn = FAILED; - acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; - printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \ - num_aborts = %d \n", acb->num_resets, acb->num_aborts); + printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts); acb->num_resets++; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - if (acb->acb_flags & ACB_F_BUS_RESET) { + switch(acb->adapter_type){ + case ACB_ADAPTER_TYPE_A:{ + if (acb->acb_flags & ACB_F_BUS_RESET){ long timeout; - timeout = wait_event_timeout(wait_q, - (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); + printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); + timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); if (timeout) { return SUCCESS; } } acb->acb_flags |= ACB_F_BUS_RESET; - if (arcmsr_iop_reset(acb)) { + if (!arcmsr_iop_reset(acb)) { struct MessageUnit_A __iomem *reg; reg = acb->pmuA; - arcmsr_hardware_reset(acb); - acb->acb_flags &= ~ACB_F_IOP_INITED; + arcmsr_hardware_reset(acb); + acb->acb_flags &= ~ACB_F_IOP_INITED; sleep_again: - arcmsr_sleep_for_bus_reset(cmd); + arcmsr_sleep_for_bus_reset(cmd); if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \ - retry=%d \n", acb->host->host_no, retry_count); - if (retry_count > retrycount) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); + if (retry_count > retrycount) { acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \ - RETRY TERMINATED!! \n", acb->host->host_no); + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); return FAILED; - } - retry_count++; - goto sleep_again; - } - acb->acb_flags |= ACB_F_IOP_INITED; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); + } + retry_count++; + goto sleep_again; + } + acb->acb_flags |= ACB_F_IOP_INITED; + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_get_firmware_spec(acb); - arcmsr_start_adapter_bgrb(acb); - /* clear Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); /*clear interrupt */ - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - /* enable outbound Post Queue,outbound doorbell Interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - atomic_set(&acb->rq_map_token, 16); + arcmsr_start_adapter_bgrb(acb); + /* clear Qbuffer if door bell ringed */ + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell); /*clear interrupt */ + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); acb->fw_flag = FW_NORMAL; init_timer(&acb->eternal_timer); @@ -2571,35 +2977,35 @@ sleep_again: add_timer(&acb->eternal_timer); acb->acb_flags &= ~ACB_F_BUS_RESET; rtn = SUCCESS; - printk(KERN_ERR "arcmsr: scsi eh bus reset succeeds\n"); + printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); } else { acb->acb_flags &= ~ACB_F_BUS_RESET; if (atomic_read(&acb->rq_map_token) == 0) { atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); + init_timer(&acb->eternal_timer); acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); } else { atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); acb->fw_flag = FW_NORMAL; mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - } + } rtn = SUCCESS; - } + } break; } case ACB_ADAPTER_TYPE_B:{ acb->acb_flags |= ACB_F_BUS_RESET; - if (arcmsr_iop_reset(acb)) { + if (!arcmsr_iop_reset(acb)) { acb->acb_flags &= ~ACB_F_BUS_RESET; rtn = FAILED; - } else { - acb->acb_flags &= ~ACB_F_BUS_RESET; + } else { + acb->acb_flags &= ~ACB_F_BUS_RESET; if (atomic_read(&acb->rq_map_token) == 0) { atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); @@ -2616,7 +3022,78 @@ sleep_again: mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); } rtn = SUCCESS; - } + } + break; + } + case ACB_ADAPTER_TYPE_C:{ + if (acb->acb_flags & ACB_F_BUS_RESET) { + long timeout; + printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); + timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); + if (timeout) { + return SUCCESS; + } + } + acb->acb_flags |= ACB_F_BUS_RESET; + if (!arcmsr_iop_reset(acb)) { + struct MessageUnit_C __iomem *reg; + reg = acb->pmuC; + arcmsr_hardware_reset(acb); + acb->acb_flags &= ~ACB_F_IOP_INITED; +sleep: + arcmsr_sleep_for_bus_reset(cmd); + if ((readl(®->host_diagnostic) & 0x04) != 0) { + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count); + if (retry_count > retrycount) { + acb->fw_flag = FW_DEADLOCK; + printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no); + return FAILED; + } + retry_count++; + goto sleep; + } + acb->acb_flags |= ACB_F_IOP_INITED; + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); + arcmsr_get_firmware_spec(acb); + arcmsr_start_adapter_bgrb(acb); + /* clear Qbuffer if door bell ringed */ + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */ + writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + init_timer(&acb->eternal_timer); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); + acb->acb_flags &= ~ACB_F_BUS_RESET; + rtn = SUCCESS; + printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); + } else { + acb->acb_flags &= ~ACB_F_BUS_RESET; + if (atomic_read(&acb->rq_map_token) == 0) { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + init_timer(&acb->eternal_timer); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); + } else { + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); + } + rtn = SUCCESS; + } + break; } } return rtn; @@ -2626,9 +3103,7 @@ static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { int rtn; - spin_lock_irq(&acb->eh_lock); rtn = arcmsr_polling_ccbdone(acb, ccb); - spin_unlock_irq(&acb->eh_lock); return rtn; } @@ -2638,7 +3113,6 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) (struct AdapterControlBlock *)cmd->device->host->hostdata; int i = 0; int rtn = FAILED; - printk(KERN_NOTICE "arcmsr%d: abort device command of scsi id = %d lun = %d \n", acb->host->host_no, cmd->device->id, cmd->device->lun); @@ -2672,7 +3146,6 @@ static const char *arcmsr_info(struct Scsi_Host *host) static char buf[256]; char *type; int raid6 = 1; - switch (acb->pdev->device) { case PCI_DEVICE_ID_ARECA_1110: case PCI_DEVICE_ID_ARECA_1200: @@ -2696,6 +3169,7 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1381: case PCI_DEVICE_ID_ARECA_1680: case PCI_DEVICE_ID_ARECA_1681: + case PCI_DEVICE_ID_ARECA_1880: type = "SAS"; break; default: -- cgit v1.2.3-70-g09d2 From cb237ef7a45f22373575b2d2ad2d06f7d38d6bce Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 17 Jun 2010 11:51:40 -0700 Subject: [SCSI] ipr: add MMIO write to perform BIST for 64 bit adapters The 64 bit chip used in new adapters does not properly support the BIST register in PCI config space. This patch implements an alternative MMIO write reset method. Signed-off-by: Wayne Boyer Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 37 +++++++++++++++++++++---------------- drivers/scsi/ipr.h | 4 ++++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 37158eab3c8..db205c9d42d 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -174,15 +174,15 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { }; static const struct ipr_chip_t ipr_chip[] = { - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, &ipr_chip_cfg[1] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, &ipr_chip_cfg[2] } + { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } }; static int ipr_max_bus_speeds [] = { @@ -7451,20 +7451,25 @@ static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) { struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - int rc; + int rc = PCIBIOS_SUCCESSFUL; ENTER; pci_block_user_cfg_access(ioa_cfg->pdev); - rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); - if (rc != PCIBIOS_SUCCESSFUL) { - pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); - ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); - rc = IPR_RC_JOB_CONTINUE; - } else { + if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) + writel(IPR_UPROCI_SIS64_START_BIST, + ioa_cfg->regs.set_uproc_interrupt_reg32); + else + rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); + + if (rc == PCIBIOS_SUCCESSFUL) { ipr_cmd->job_step = ipr_reset_bist_done; ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); rc = IPR_RC_JOB_RETURN; + } else { + pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); + ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); + rc = IPR_RC_JOB_CONTINUE; } LEAVE; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 0ef9a67112a..ba63826dd90 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -272,6 +272,7 @@ IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR) #define IPR_UPROCI_RESET_ALERT (0x80000000 >> 7) #define IPR_UPROCI_IO_DEBUG_ALERT (0x80000000 >> 9) +#define IPR_UPROCI_SIS64_START_BIST (0x80000000 >> 23) #define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC 200000 /* 200 ms */ #define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC 200000 /* 200 ms */ @@ -1301,6 +1302,9 @@ struct ipr_chip_t { u16 sis_type; #define IPR_SIS32 0x00 #define IPR_SIS64 0x01 + u16 bist_method; +#define IPR_PCI_CFG 0x00 +#define IPR_MMIO 0x01 const struct ipr_chip_cfg_t *cfg; }; -- cgit v1.2.3-70-g09d2 From 3e84beba608dee5a7c7711a3503eb2f335c78fca Mon Sep 17 00:00:00 2001 From: Kei Tokunaga Date: Wed, 7 Apr 2010 19:17:24 +0900 Subject: [SCSI] mptsas: fixed hot-removal processing This patch fixes mptsas disk hot-removal processing. The hot-removal processing doesn't complete because of this condition. drivers/message/fusion/mptsas.c: mptsas_taskmgmt_complete() if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) mptsas_queue_device_delete(...); mptsas_queue_device_delete(), which must be called for hot-removal, never gets called because mptsas_find_vtarget() always returns 0 here. At that time, the vtarget has already been freed in mptsas_target_destroy(), and also the scsi_device has been marked as SDEV_DEL. As a result of the issue, port deletion functions won't get called and the device ends up being in an incomplete state. (Some data structures and sysfs entries, which should be removed in hot-removal, remain.) One side effect of this is that a hot-addition of the device (bringing the device back on) fails. This patch just removes mptsas_find_vtarget() from the if-state condition. Signed-off-by: Kei Tokunaga Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index f42781b92bd..46cc90c9bfc 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1261,7 +1261,7 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * enable work queue to remove device from upper layers */ list_del(&target_reset_list->list); - if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off) + if (!ioc->fw_events_off) mptsas_queue_device_delete(ioc, &target_reset_list->sas_event_data); -- cgit v1.2.3-70-g09d2 From 6e49949c5e9e04d64e16df3723dd3f5bd25a29e2 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Sun, 25 Apr 2010 07:03:57 -0500 Subject: [SCSI] Log msg when getting Unit Attention If the user accidentally changes LUN mappings or it occurs due to a bug, then it can cause data corruption that can take months and months to track down. This patch adds a log message when getting REPORT_LUNS_DATA_CHANGED and it adds a generic message for other Unit Attentions with asc == 0x3f. We are working on adding support for handling of these errors, but I think until then we should at least log a message so tracking down problems as a result of one of these changes is a little easier. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index a5d630f5f51..c60cffbefa3 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -307,6 +307,19 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) return FAILED; + if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e) + scmd_printk(KERN_WARNING, scmd, + "Warning! Received an indication that the " + "LUN assignments on this target have " + "changed. The Linux SCSI layer does not " + "automatically remap LUN assignments.\n"); + else if (sshdr.asc == 0x3f) + scmd_printk(KERN_WARNING, scmd, + "Warning! Received an indication that the " + "operating parameters on this target have " + "changed. The Linux SCSI layer does not " + "automatically adjust these parameters.\n"); + if (blk_barrier_rq(scmd->request)) /* * barrier requests should always retry on UA -- cgit v1.2.3-70-g09d2 From e4bf25fbcc64a87d7dc1d3318ca56c28382757e2 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Fri, 18 Jun 2010 13:16:07 -0700 Subject: [SCSI] scsi:hosts.c Fix warning: variable 'rval' set but not used The below patch fixes a warning message generated by gcc 4.6.0 CC drivers/scsi/hosts.o drivers/scsi/hosts.c: In function 'scsi_host_alloc': drivers/scsi/hosts.c:328:6: warning: variable 'rval' set but not used Fix this by removing the rval but placing a printk warning where it would have been set. Signed-off-by: Justin P. Mattock Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 6660fa92ffa..a2b1414da28 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -325,7 +325,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; gfp_t gfp_mask = GFP_KERNEL; - int rval; if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; @@ -420,7 +419,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->ehandler = kthread_run(scsi_error_handler, shost, "scsi_eh_%d", shost->host_no); if (IS_ERR(shost->ehandler)) { - rval = PTR_ERR(shost->ehandler); + printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n", + shost->host_no, PTR_ERR(shost->ehandler)); goto fail_kfree; } -- cgit v1.2.3-70-g09d2 From 97009a29e8c999def2d1e9ef253c226daf9541af Mon Sep 17 00:00:00 2001 From: Kei Tokunaga Date: Tue, 22 Jun 2010 19:01:51 +0900 Subject: [SCSI] mptfusion: print Doorbell register in a case of hard reset and timeout Printing Doorbell register in a case of hard reset and timeout should be useful for figuring out the state of the system. Signed-off-by: Kei Tokunaga Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 13 ++++++++----- drivers/message/fusion/mptctl.c | 18 ++++++++++++++---- drivers/message/fusion/mptsas.c | 5 +++-- drivers/message/fusion/mptscsih.c | 12 ++++++++---- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index c36d5b9ff66..e319abcd849 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -5063,8 +5063,9 @@ mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) goto out; if (!timeleft) { - printk(KERN_DEBUG "%s: Issuing Reset from %s!!\n", - ioc->name, __func__); + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!!, doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } @@ -6455,8 +6456,9 @@ out: mutex_unlock(&ioc->mptbase_cmds.mutex); if (issue_hard_reset) { issue_hard_reset = 0; - printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", - ioc->name, __func__); + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!!, doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); if (retry_count == 0) { if (mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP) != 0) retry_count++; @@ -7146,7 +7148,8 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag); if (rc != 0) { printk(KERN_WARNING MYNAM - ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); + ": WARNING - (%d) Cannot recover %s, doorbell=0x%08x\n", + rc, ioc->name, mpt_GetIocState(ioc, 0)); } else { if (ioc->hard_resets < -1) ioc->hard_resets++; diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 9bd89cebb5a..40046f595f1 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -954,9 +954,12 @@ retry_wait: mpt_free_msg_frame(iocp, mf); goto fwdl_out; } - if (!timeleft) + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "FW download timeout, doorbell=0x%08x\n", + iocp->name, mpt_GetIocState(iocp, 0)); mptctl_timeout_expired(iocp, mf); - else + } else goto retry_wait; goto fwdl_out; } @@ -2301,6 +2304,10 @@ retry_wait: goto done_free_mem; } if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "mpt cmd timeout, doorbell=0x%08x" + " function=0x%x\n", + ioc->name, mpt_GetIocState(ioc, 0), function); if (function == MPI_FUNCTION_SCSI_TASK_MGMT) mutex_unlock(&ioc->taskmgmt_cmds.mutex); mptctl_timeout_expired(ioc, mf); @@ -2608,9 +2615,12 @@ retry_wait: mpt_free_msg_frame(ioc, mf); goto out; } - if (!timeleft) + if (!timeleft) { + printk(MYIOC_s_WARN_FMT + "HOST INFO command timeout, doorbell=0x%08x\n", + ioc->name, mpt_GetIocState(ioc, 0)); mptctl_timeout_expired(ioc, mf); - else + } else goto retry_wait; goto out; } diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 46cc90c9bfc..f705a235300 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -4816,8 +4816,9 @@ mptsas_broadcast_primative_work(struct fw_event_work *fw_event) mutex_unlock(&ioc->taskmgmt_cmds.mutex); if (issue_reset) { - printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", - ioc->name, __func__); + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); } mptsas_free_fw_event(ioc, fw_event); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index c5c8fb811f5..dceb67a2182 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1706,8 +1706,9 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) if (issue_hard_reset) { - printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", - ioc->name, __func__); + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0)); retval = mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } @@ -3051,8 +3052,11 @@ mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *io) goto out; } if (!timeleft) { - printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", - ioc->name, __func__); + printk(MYIOC_s_WARN_FMT + "Issuing Reset from %s!! doorbell=0x%08xh" + " cmd=0x%02x\n", + ioc->name, __func__, mpt_GetIocState(ioc, 0), + cmd); mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP); mpt_free_msg_frame(ioc, mf); } -- cgit v1.2.3-70-g09d2 From 24ae163ed33d2b8a70d2f0b1947b401d0a8e8719 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 22 Jun 2010 13:42:02 +0200 Subject: [SCSI] mvsas: fix potential NULL dereference Stanse found that in mvs_abort_task, mvi_dev is dereferenced earlier than tested for being NULL. Move the assignment below the test. Signed-off-by: Jiri Slaby Signed-off-by: James Bottomley --- drivers/scsi/mvsas/mv_sas.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index f5e32179190..cab92423986 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1640,7 +1640,7 @@ int mvs_abort_task(struct sas_task *task) struct mvs_tmf_task tmf_task; struct domain_device *dev = task->dev; struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; + struct mvs_info *mvi; int rc = TMF_RESP_FUNC_FAILED; unsigned long flags; u32 tag; @@ -1650,6 +1650,8 @@ int mvs_abort_task(struct sas_task *task) rc = TMF_RESP_FUNC_FAILED; } + mvi = mvi_dev->mvi_info; + spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { spin_unlock_irqrestore(&task->task_state_lock, flags); -- cgit v1.2.3-70-g09d2 From b0f56d3d6becfb338a41615d6ce43d41547502c3 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 24 Jun 2010 13:34:14 -0700 Subject: [SCSI] ipr: add support for new Obsidian-E embedded adapter This patch allows the driver to recognize a new Obsidian-E based adapter that uses a new subsystem ID. This patch also fixes a few tab/space problems. Signed-off-by: Wayne Boyer Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 2 ++ drivers/scsi/ipr.h | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index db205c9d42d..ce839c8eeea 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -8891,6 +8891,8 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { IPR_USE_LONG_TRANSOP_TIMEOUT }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 }, + { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CC, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET }, diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index ba63826dd90..d2ee20dcd88 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -62,12 +62,12 @@ #define IPR_SUBS_DEV_ID_2780 0x0264 #define IPR_SUBS_DEV_ID_5702 0x0266 #define IPR_SUBS_DEV_ID_5703 0x0278 -#define IPR_SUBS_DEV_ID_572E 0x028D -#define IPR_SUBS_DEV_ID_573E 0x02D3 -#define IPR_SUBS_DEV_ID_573D 0x02D4 +#define IPR_SUBS_DEV_ID_572E 0x028D +#define IPR_SUBS_DEV_ID_573E 0x02D3 +#define IPR_SUBS_DEV_ID_573D 0x02D4 #define IPR_SUBS_DEV_ID_571A 0x02C0 #define IPR_SUBS_DEV_ID_571B 0x02BE -#define IPR_SUBS_DEV_ID_571E 0x02BF +#define IPR_SUBS_DEV_ID_571E 0x02BF #define IPR_SUBS_DEV_ID_571F 0x02D5 #define IPR_SUBS_DEV_ID_572A 0x02C1 #define IPR_SUBS_DEV_ID_572B 0x02C2 @@ -82,6 +82,7 @@ #define IPR_SUBS_DEV_ID_57B4 0x033B #define IPR_SUBS_DEV_ID_57B2 0x035F #define IPR_SUBS_DEV_ID_57C6 0x0357 +#define IPR_SUBS_DEV_ID_57CC 0x035C #define IPR_SUBS_DEV_ID_57B5 0x033C #define IPR_SUBS_DEV_ID_57CE 0x035E -- cgit v1.2.3-70-g09d2 From 4289a08680d646dcc18e291cb437a292738e504f Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Thu, 24 Jun 2010 17:00:59 -0700 Subject: [SCSI] ipr: change endian swap key to match hardware spec change The value used to change the endian representation on the new adapters has changed. This patch updates that value. Signed-off-by: Wayne Boyer Signed-off-by: James Bottomley --- drivers/scsi/ipr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index d2ee20dcd88..4d31625ab9c 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1257,7 +1257,7 @@ struct ipr_interrupt_offsets { unsigned long dump_addr_reg; unsigned long dump_data_reg; -#define IPR_ENDIAN_SWAP_KEY 0x000C0C00 +#define IPR_ENDIAN_SWAP_KEY 0x00080800 unsigned long endian_swap_reg; }; -- cgit v1.2.3-70-g09d2 From 9ab98f57b3e1d73cd0720d29c21b687ba609cde9 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 28 Jun 2010 01:04:45 +0900 Subject: [SCSI] scsi_debug: fix map_region and unmap_region oops map_region and unmap_region could access to invalid memory area since they don't check the size boundary. Signed-off-by: FUJITA Tomonori Acked-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 136329b4027..b02bdc6c2cd 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1991,7 +1991,8 @@ static void map_region(sector_t lba, unsigned int len) block = lba + alignment; rem = do_div(block, granularity); - set_bit(block, map_storep); + if (block < map_size) + set_bit(block, map_storep); lba += granularity - rem; } @@ -2011,7 +2012,8 @@ static void unmap_region(sector_t lba, unsigned int len) block = lba + alignment; rem = do_div(block, granularity); - if (rem == 0 && lba + granularity <= end) + if (rem == 0 && lba + granularity <= end && + block < map_size) clear_bit(block, map_storep); lba += granularity - rem; -- cgit v1.2.3-70-g09d2 From 6447f286326690a936c35f9f913499307f869934 Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:50 -0700 Subject: [SCSI] bnx2i: Separated the hardware's cleanup procedure from ep_disconnect This patch introduces a new bnx2i_hw_ep_disconnect routine which contains all chip related disconnect and clean up procedure of iSCSI offload connections. This separation is intended as a preparation for the subsequent bnx2i_stop patch. Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Reviewed-by: Mike Christie Acked-by: Anil Veerabhadrappa Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 119 +++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 43 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index fa68ab34b99..6edfde5f2e0 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1866,54 +1866,35 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) } -/** - * bnx2i_ep_disconnect - executes TCP connection teardown process - * @ep: TCP connection (endpoint) handle +/* + * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw + * @ep: TCP connection (bnx2i endpoint) handle * * executes TCP connection teardown process */ -static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) +int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) { - struct bnx2i_endpoint *bnx2i_ep; - struct bnx2i_conn *bnx2i_conn = NULL; - struct iscsi_session *session = NULL; - struct iscsi_conn *conn; + struct bnx2i_hba *hba = bnx2i_ep->hba; struct cnic_dev *cnic; - struct bnx2i_hba *hba; + struct iscsi_session *session = NULL; + struct iscsi_conn *conn = NULL; + int ret = 0; - bnx2i_ep = ep->dd_data; + if (!hba) + return 0; - /* driver should not attempt connection cleanup until TCP_CONNECT - * completes either successfully or fails. Timeout is 9-secs, so - * wait for it to complete - */ - while ((bnx2i_ep->state == EP_STATE_CONNECT_START) && - !time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ))) - msleep(250); + cnic = hba->cnic; + if (!cnic) + return 0; + + if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) + goto destroy_conn; if (bnx2i_ep->conn) { - bnx2i_conn = bnx2i_ep->conn; - conn = bnx2i_conn->cls_conn->dd_data; + conn = bnx2i_ep->conn->cls_conn->dd_data; session = conn->session; - - iscsi_suspend_queue(conn); } - hba = bnx2i_ep->hba; - if (bnx2i_ep->state == EP_STATE_IDLE) - goto return_bnx2i_ep; - cnic = hba->cnic; - - mutex_lock(&hba->net_dev_lock); - - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) - goto free_resc; - if (bnx2i_ep->hba_age != hba->age) - goto free_resc; - - if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) - goto destory_conn; - bnx2i_ep->state = EP_STATE_DISCONN_START; init_timer(&bnx2i_ep->ofld_timer); @@ -1924,6 +1905,7 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { int close = 0; + int close_ret = 0; if (session) { spin_lock_bh(&session->lock); @@ -1932,11 +1914,13 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) spin_unlock_bh(&session->lock); } if (close) - cnic->cm_close(bnx2i_ep->cm_sk); + close_ret = cnic->cm_close(bnx2i_ep->cm_sk); else - cnic->cm_abort(bnx2i_ep->cm_sk); + close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); + if (close_ret) + bnx2i_ep->state = EP_STATE_DISCONN_COMPL; } else - goto free_resc; + goto out; /* wait for option-2 conn teardown */ wait_event_interruptible(bnx2i_ep->ofld_wait, @@ -1946,20 +1930,69 @@ static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) flush_signals(current); del_timer_sync(&bnx2i_ep->ofld_timer); -destory_conn: - if (bnx2i_tear_down_conn(hba, bnx2i_ep)) { +destroy_conn: + if (bnx2i_tear_down_conn(hba, bnx2i_ep)) + ret = -EINVAL; +out: + bnx2i_ep->state = EP_STATE_IDLE; + return ret; +} + + +/** + * bnx2i_ep_disconnect - executes TCP connection teardown process + * @ep: TCP connection (iscsi endpoint) handle + * + * executes TCP connection teardown process + */ +static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) +{ + struct bnx2i_endpoint *bnx2i_ep; + struct bnx2i_conn *bnx2i_conn = NULL; + struct iscsi_conn *conn = NULL; + struct bnx2i_hba *hba; + + bnx2i_ep = ep->dd_data; + + /* driver should not attempt connection cleanup until TCP_CONNECT + * completes either successfully or fails. Timeout is 9-secs, so + * wait for it to complete + */ + while ((bnx2i_ep->state == EP_STATE_CONNECT_START) && + !time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ))) + msleep(250); + + if (bnx2i_ep->conn) { + bnx2i_conn = bnx2i_ep->conn; + conn = bnx2i_conn->cls_conn->dd_data; + iscsi_suspend_queue(conn); + } + hba = bnx2i_ep->hba; + + mutex_lock(&hba->net_dev_lock); + + if (bnx2i_ep->state == EP_STATE_IDLE) + goto return_bnx2i_ep; + + if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) + goto free_resc; + + if (bnx2i_ep->hba_age != hba->age) + goto free_resc; + + /* Do all chip cleanup here */ + if (bnx2i_hw_ep_disconnect(bnx2i_ep)) { mutex_unlock(&hba->net_dev_lock); return; } free_resc: - mutex_unlock(&hba->net_dev_lock); bnx2i_free_qp_resc(hba, bnx2i_ep); return_bnx2i_ep: if (bnx2i_conn) bnx2i_conn->ep = NULL; bnx2i_free_ep(ep); - + mutex_unlock(&hba->net_dev_lock); if (!hba->ofld_conns_active) bnx2i_unreg_dev_all(); -- cgit v1.2.3-70-g09d2 From 46012e8b8de325472790d154f4cfb1cf2d4fc49a Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:51 -0700 Subject: [SCSI] bnx2i: Created an active linklist which holds bnx2i endpoints This introduces a new active linklist which would link up all active bnx2i_endpoints. This will be used by subsequent patches that follows. Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i.h | 4 ++++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 46 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 6b624e767d3..c17c3a3d52b 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -299,6 +299,7 @@ struct iscsi_cid_queue { * @cid_que: iscsi cid queue * @ep_rdwr_lock: read / write lock to synchronize various ep lists * @ep_ofld_list: connection list for pending offload completion + * @ep_active_list: connection list for active offload endpoints * @ep_destroy_list: connection list for pending offload completion * @mp_bd_tbl: BD table to be used with middle path requests * @mp_bd_dma: DMA address of 'mp_bd_tbl' memory buffer @@ -369,6 +370,7 @@ struct bnx2i_hba { rwlock_t ep_rdwr_lock; struct list_head ep_ofld_list; + struct list_head ep_active_list; struct list_head ep_destroy_list; /* @@ -645,6 +647,7 @@ enum { * @link: list head to link elements * @hba: adapter to which this connection belongs * @conn: iscsi connection this EP is linked to + * @cls_ep: associated iSCSI endpoint pointer * @sess: iscsi session this EP is linked to * @cm_sk: cnic sock struct * @hba_age: age to detect if 'iscsid' issues ep_disconnect() @@ -664,6 +667,7 @@ struct bnx2i_endpoint { struct list_head link; struct bnx2i_hba *hba; struct bnx2i_conn *conn; + struct iscsi_endpoint *cls_ep; struct cnic_sock *cm_sk; u32 hba_age; u32 state; diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 6edfde5f2e0..fb5fe88de90 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -386,6 +386,7 @@ static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) } bnx2i_ep = ep->dd_data; + bnx2i_ep->cls_ep = ep; INIT_LIST_HEAD(&bnx2i_ep->link); bnx2i_ep->state = EP_STATE_IDLE; bnx2i_ep->ep_iscsi_cid = (u16) -1; @@ -678,7 +679,6 @@ bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid) return ep; } - /** * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list * @hba: pointer to adapter instance @@ -708,6 +708,39 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid) return ep; } + +/** + * bnx2i_ep_active_list_add - add an entry to ep active list + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * current active conn queue manager + */ +static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_add_tail(&ep->link, &hba->ep_active_list); + write_unlock_bh(&hba->ep_rdwr_lock); +} + + +/** + * bnx2i_ep_active_list_del - deletes an entry to ep active list + * @hba: pointer to adapter instance + * @ep: pointer to endpoint (transport indentifier) structure + * + * current active conn queue manager + */ +static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba, + struct bnx2i_endpoint *ep) +{ + write_lock_bh(&hba->ep_rdwr_lock); + list_del_init(&ep->link); + write_unlock_bh(&hba->ep_rdwr_lock); +} + + /** * bnx2i_setup_host_queue_size - assigns shost->can_queue param * @hba: pointer to adapter instance @@ -784,6 +817,7 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) goto mp_bdt_mem_err; INIT_LIST_HEAD(&hba->ep_ofld_list); + INIT_LIST_HEAD(&hba->ep_active_list); INIT_LIST_HEAD(&hba->ep_destroy_list); rwlock_init(&hba->ep_rdwr_lock); @@ -857,6 +891,7 @@ void bnx2i_free_hba(struct bnx2i_hba *hba) iscsi_host_remove(shost); INIT_LIST_HEAD(&hba->ep_ofld_list); + INIT_LIST_HEAD(&hba->ep_active_list); INIT_LIST_HEAD(&hba->ep_destroy_list); pci_dev_put(hba->pcidev); @@ -1754,15 +1789,19 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, goto conn_failed; } else rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr); - if (rc) goto release_ep; + bnx2i_ep_active_list_add(hba, bnx2i_ep); + if (bnx2i_map_ep_dbell_regs(bnx2i_ep)) - goto release_ep; + goto del_active_ep; + mutex_unlock(&hba->net_dev_lock); return ep; +del_active_ep: + bnx2i_ep_active_list_del(hba, bnx2i_ep); release_ep: if (bnx2i_tear_down_conn(hba, bnx2i_ep)) { mutex_unlock(&hba->net_dev_lock); @@ -1931,6 +1970,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) del_timer_sync(&bnx2i_ep->ofld_timer); destroy_conn: + bnx2i_ep_active_list_del(hba, bnx2i_ep); if (bnx2i_tear_down_conn(hba, bnx2i_ep)) ret = -EINVAL; out: -- cgit v1.2.3-70-g09d2 From 55e15c975cbf9ef8b765eba9ebadc96f2a2e5752 Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:52 -0700 Subject: [SCSI] bnx2i: Optimized the bnx2i_stop connection clean up procedure For cases where the iSCSI disconnection procedure times out due to the iSCSI daemon being slow or unresponsive, the bnx2i_stop routine will now perform hardware cleanup via bnx2i_hw_ep_disconnect on all active endpoints so that subsequent operations will perform properly. Also moved the mutex locks inside ep_connect and ep_disconnect so that proper exclusivity can resolve simultaneous calls to the ep_disconnect routine. v2: Removed the unnecessary read lock in the bnx2i_stop Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i.h | 4 ++++ drivers/scsi/bnx2i/bnx2i_init.c | 33 ++++++++++++++++++++++++++++++--- drivers/scsi/bnx2i/bnx2i_iscsi.c | 12 ++++++------ 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index c17c3a3d52b..fed1a686da6 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -295,6 +295,7 @@ struct iscsi_cid_queue { * @max_cqes: CQ size * @num_ccell: number of command cells per connection * @ofld_conns_active: active connection list + * @eh_wait: wait queue for the endpoint to shutdown * @max_active_conns: max offload connections supported by this device * @cid_que: iscsi cid queue * @ep_rdwr_lock: read / write lock to synchronize various ep lists @@ -306,6 +307,7 @@ struct iscsi_cid_queue { * @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer * @lock: lock to synchonize access to hba structure + * @hba_shutdown_tmo: Timeout value to shutdown each connection * @pci_did: PCI device ID * @pci_vid: PCI vendor ID * @pci_sdid: PCI subsystem device ID @@ -770,6 +772,8 @@ extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); extern void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); +extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); + /* Debug related function prototypes */ extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn); extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index af6a00a600f..f0f8361af4e 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -176,6 +176,9 @@ void bnx2i_start(void *handle) void bnx2i_stop(void *handle) { struct bnx2i_hba *hba = handle; + struct list_head *pos, *tmp; + struct bnx2i_endpoint *bnx2i_ep; + int conns_active; /* check if cleanup happened in GOING_DOWN context */ if (!test_and_clear_bit(ADAPTER_STATE_GOING_DOWN, @@ -187,9 +190,33 @@ void bnx2i_stop(void *handle) * control returns to network driver. So it is required to cleanup and * release all connection resources before returning from this routine. */ - wait_event_interruptible_timeout(hba->eh_wait, - (hba->ofld_conns_active == 0), - hba->hba_shutdown_tmo); + while (hba->ofld_conns_active) { + conns_active = hba->ofld_conns_active; + wait_event_interruptible_timeout(hba->eh_wait, + (hba->ofld_conns_active != conns_active), + hba->hba_shutdown_tmo); + if (hba->ofld_conns_active == conns_active) + break; + } + if (hba->ofld_conns_active) { + /* Stage to force the disconnection + * This is the case where the daemon is either slow or + * not present + */ + printk(KERN_ALERT "bnx2i: Wait timeout, force all eps " + "to disconnect (%d)\n", hba->ofld_conns_active); + mutex_lock(&hba->net_dev_lock); + list_for_each_safe(pos, tmp, &hba->ep_active_list) { + bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link); + /* Clean up the chip only */ + bnx2i_hw_ep_disconnect(bnx2i_ep); + } + mutex_unlock(&hba->net_dev_lock); + if (hba->ofld_conns_active) + printk(KERN_ERR "bnx2i: EP disconnect timeout (%d)!\n", + hba->ofld_conns_active); + } + /* This flag should be cleared last so that ep_disconnect() gracefully * cleans up connection context */ diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index fb5fe88de90..1600e7cae19 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -708,7 +708,6 @@ bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid) return ep; } - /** * bnx2i_ep_active_list_add - add an entry to ep active list * @hba: pointer to adapter instance @@ -856,9 +855,9 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) mutex_init(&hba->net_dev_lock); init_waitqueue_head(&hba->eh_wait); if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) - hba->hba_shutdown_tmo = 240 * HZ; + hba->hba_shutdown_tmo = 20 * HZ; else /* 5706/5708/5709 */ - hba->hba_shutdown_tmo = 30 * HZ; + hba->hba_shutdown_tmo = 20 * HZ; if (iscsi_host_add(shost, &hba->pcidev->dev)) goto free_dump_mem; @@ -1700,10 +1699,11 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, if (!hba || test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state)) { rc = -EINVAL; - goto check_busy; + goto nohba; } cnic = hba->cnic; + mutex_lock(&hba->net_dev_lock); ep = bnx2i_alloc_ep(hba); if (!ep) { rc = -ENOMEM; @@ -1711,7 +1711,6 @@ static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, } bnx2i_ep = ep->dd_data; - mutex_lock(&hba->net_dev_lock); if (bnx2i_adapter_ready(hba)) { rc = -EPERM; goto net_if_down; @@ -1813,8 +1812,9 @@ iscsi_cid_err: bnx2i_free_qp_resc(hba, bnx2i_ep); qp_resc_err: bnx2i_free_ep(ep); - mutex_unlock(&hba->net_dev_lock); check_busy: + mutex_unlock(&hba->net_dev_lock); +nohba: bnx2i_unreg_dev_all(); return ERR_PTR(rc); } -- cgit v1.2.3-70-g09d2 From e37d2c4791480e27c2e2e4a556e4d2ba1d353ff8 Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:53 -0700 Subject: [SCSI] bnx2i: Fine tuned conn destroy and context destroy timeout values Added variables to separate the fine tuned timeout values for connection destroy and context destroy for both 1g and 10g devices. v2: Extended the 5771X disconnect timeout from 10s to 20s as the firmware has a retransmission timeout of 16s. This fixes one of the iscsi_endpoint leak issues when the target is slow or non-responsive to our TCP FIN. Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i.h | 4 ++++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 13 +++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index fed1a686da6..69febb6f958 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -308,6 +308,8 @@ struct iscsi_cid_queue { * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer * @lock: lock to synchonize access to hba structure * @hba_shutdown_tmo: Timeout value to shutdown each connection + * @conn_teardown_tmo: Timeout value to tear down each connection + * @conn_ctx_destroy_tmo: Timeout value to destroy context of each connection * @pci_did: PCI device ID * @pci_vid: PCI vendor ID * @pci_sdid: PCI subsystem device ID @@ -387,6 +389,8 @@ struct bnx2i_hba { struct mutex net_dev_lock;/* sync net device access */ int hba_shutdown_tmo; + int conn_teardown_tmo; + int conn_ctx_destroy_tmo; /* * PCI related info. */ diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index 1600e7cae19..f6eebb39fe5 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -854,10 +854,15 @@ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) spin_lock_init(&hba->lock); mutex_init(&hba->net_dev_lock); init_waitqueue_head(&hba->eh_wait); - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) + if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { hba->hba_shutdown_tmo = 20 * HZ; - else /* 5706/5708/5709 */ + hba->conn_teardown_tmo = 20 * HZ; + hba->conn_ctx_destroy_tmo = 6 * HZ; + } else { /* 5706/5708/5709 */ hba->hba_shutdown_tmo = 20 * HZ; + hba->conn_teardown_tmo = 10 * HZ; + hba->conn_ctx_destroy_tmo = 2 * HZ; + } if (iscsi_host_add(shost, &hba->pcidev->dev)) goto free_dump_mem; @@ -1633,7 +1638,7 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, ep->state = EP_STATE_CLEANUP_START; init_timer(&ep->ofld_timer); - ep->ofld_timer.expires = 10*HZ + jiffies; + ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies; ep->ofld_timer.function = bnx2i_ep_ofld_timer; ep->ofld_timer.data = (unsigned long) ep; add_timer(&ep->ofld_timer); @@ -1937,7 +1942,7 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) bnx2i_ep->state = EP_STATE_DISCONN_START; init_timer(&bnx2i_ep->ofld_timer); - bnx2i_ep->ofld_timer.expires = 10*HZ + jiffies; + bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies; bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; add_timer(&bnx2i_ep->ofld_timer); -- cgit v1.2.3-70-g09d2 From 2eefb20dbf3032da1ad111c1ce178f899bc4859a Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:54 -0700 Subject: [SCSI] bnx2i: Fixed the TCP graceful termination initiation In compliance to RFC793, a TCP graceful termination will be used instead of an abortive termination for the case where the remote has initiated the close of the connection. Additionally, a TCP abortive termination will be used to close the connection when a logout response is not received in time after a logout request has been initiated. Signed-off-by: Eddie Wai Reviewed-by: Michael Chan Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i.h | 2 ++ drivers/scsi/bnx2i/bnx2i_hwi.c | 4 +++ drivers/scsi/bnx2i/bnx2i_iscsi.c | 53 ++++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h index 69febb6f958..00c033511cb 100644 --- a/drivers/scsi/bnx2i/bnx2i.h +++ b/drivers/scsi/bnx2i/bnx2i.h @@ -639,6 +639,8 @@ enum { EP_STATE_CLEANUP_CMPL = 0x800, EP_STATE_TCP_FIN_RCVD = 0x1000, EP_STATE_TCP_RST_RCVD = 0x2000, + EP_STATE_LOGOUT_SENT = 0x4000, + EP_STATE_LOGOUT_RESP_RCVD = 0x8000, EP_STATE_PG_OFLD_FAILED = 0x1000000, EP_STATE_ULP_UPDATE_FAILED = 0x2000000, EP_STATE_CLEANUP_FAILED = 0x4000000, diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 3a66ca24c7b..d23fc256d58 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -562,6 +562,8 @@ int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn, logout_wqe->num_bds = 1; logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ + bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT; + bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); return 0; } @@ -1482,6 +1484,8 @@ static int bnx2i_process_logout_resp(struct iscsi_session *session, resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain); __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); + + bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD; done: spin_unlock(&session->lock); return 0; diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index f6eebb39fe5..c66c5a45aa2 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1890,6 +1890,8 @@ static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) case EP_STATE_ULP_UPDATE_START: case EP_STATE_ULP_UPDATE_COMPL: case EP_STATE_TCP_FIN_RCVD: + case EP_STATE_LOGOUT_SENT: + case EP_STATE_LOGOUT_RESP_RCVD: case EP_STATE_ULP_UPDATE_FAILED: ret = 1; break; @@ -1923,6 +1925,8 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) struct iscsi_session *session = NULL; struct iscsi_conn *conn = NULL; int ret = 0; + int close = 0; + int close_ret = 0; if (!hba) return 0; @@ -1939,33 +1943,44 @@ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) session = conn->session; } - bnx2i_ep->state = EP_STATE_DISCONN_START; - init_timer(&bnx2i_ep->ofld_timer); bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies; bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; add_timer(&bnx2i_ep->ofld_timer); - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - int close = 0; - int close_ret = 0; - - if (session) { - spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_LOGGING_OUT) - close = 1; - spin_unlock_bh(&session->lock); - } - if (close) - close_ret = cnic->cm_close(bnx2i_ep->cm_sk); - else - close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); - if (close_ret) - bnx2i_ep->state = EP_STATE_DISCONN_COMPL; - } else + if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) goto out; + if (session) { + spin_lock_bh(&session->lock); + if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) { + if (session->state == ISCSI_STATE_LOGGING_OUT) { + if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { + /* Logout sent, but no resp */ + printk(KERN_ALERT "bnx2i - WARNING " + "logout response was not " + "received!\n"); + } else if (bnx2i_ep->state == + EP_STATE_LOGOUT_RESP_RCVD) + close = 1; + } + } else + close = 1; + + spin_unlock_bh(&session->lock); + } + + bnx2i_ep->state = EP_STATE_DISCONN_START; + + if (close) + close_ret = cnic->cm_close(bnx2i_ep->cm_sk); + else + close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); + + if (close_ret) + bnx2i_ep->state = EP_STATE_DISCONN_COMPL; + /* wait for option-2 conn teardown */ wait_event_interruptible(bnx2i_ep->ofld_wait, bnx2i_ep->state != EP_STATE_DISCONN_START); -- cgit v1.2.3-70-g09d2 From 625986c22e5c122b3e2f4e985680393453d8c5ce Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 1 Jul 2010 15:34:55 -0700 Subject: [SCSI] bnx2i: Added host param ISCSI_HOST_PARAM_IPADDRESS This sysfs attribute is proven to be useful during pivot_root. Signed-off-by: Michael Chan Signed-off-by: Eddie Wai Reviewed-by: Benjamin Li Acked-by: Anil Veerabhadrappa Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index c66c5a45aa2..a46ccc380ab 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1500,6 +1500,26 @@ static int bnx2i_host_get_param(struct Scsi_Host *shost, case ISCSI_HOST_PARAM_NETDEV_NAME: len = sprintf(buf, "%s\n", hba->netdev->name); break; + case ISCSI_HOST_PARAM_IPADDRESS: { + struct list_head *active_list = &hba->ep_active_list; + + read_lock_bh(&hba->ep_rdwr_lock); + if (!list_empty(&hba->ep_active_list)) { + struct bnx2i_endpoint *bnx2i_ep; + struct cnic_sock *csk; + + bnx2i_ep = list_first_entry(active_list, + struct bnx2i_endpoint, + link); + csk = bnx2i_ep->cm_sk; + if (test_bit(SK_F_IPV6, &csk->flags)) + len = sprintf(buf, "%pI6\n", csk->src_ip); + else + len = sprintf(buf, "%pI4\n", csk->src_ip); + } + read_unlock_bh(&hba->ep_rdwr_lock); + break; + } default: return iscsi_host_get_param(shost, param, buf); } @@ -2131,7 +2151,8 @@ struct iscsi_transport bnx2i_iscsi_transport = { ISCSI_LU_RESET_TMO | ISCSI_TGT_RESET_TMO | ISCSI_PING_TMO | ISCSI_RECV_TMO | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, - .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME, + .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | + ISCSI_HOST_NETDEV_NAME, .create_session = bnx2i_session_create, .destroy_session = bnx2i_session_destroy, .create_conn = bnx2i_conn_create, -- cgit v1.2.3-70-g09d2 From a2f1d139df42df6f3a2641591dea9e068b68f68c Mon Sep 17 00:00:00 2001 From: Eddie Wai Date: Thu, 1 Jul 2010 15:34:56 -0700 Subject: [SCSI] bnx2i: Updated version from 2.1.1 to 2.1.2 Signed-off-by: Eddie Wai Signed-off-by: James Bottomley --- drivers/scsi/bnx2i/bnx2i_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/bnx2i/bnx2i_init.c b/drivers/scsi/bnx2i/bnx2i_init.c index f0f8361af4e..a796f565f38 100644 --- a/drivers/scsi/bnx2i/bnx2i_init.c +++ b/drivers/scsi/bnx2i/bnx2i_init.c @@ -17,8 +17,8 @@ static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); static u32 adapter_count; #define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.1.1" -#define DRV_MODULE_RELDATE "Mar 24, 2010" +#define DRV_MODULE_VERSION "2.1.2" +#define DRV_MODULE_RELDATE "Jun 28, 2010" static char version[] __devinitdata = "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ -- cgit v1.2.3-70-g09d2 From 3cb5469a2ab4b87a7c63dd218fdc1625bc73eccc Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Thu, 8 Jul 2010 14:44:34 -0600 Subject: [SCSI] mpt2sas: driver fails to recover from injected PCIe bus errors fixes surrounding PCIe enhanced error handling: (1) We need to reject all request generated internaly inside the driver as well as request arriving from the scsi mid layer when PCIe EEH is active. The fix is to add a per adapter flag called pci_error_recovery which is checked thru out the driver when request are generated. (2) We don't need to call the pci_driver->remove directly from the PCIe callbacks becuase its already called from the PCIe EEH code. In its place we are shutting down the watchdog timer, and flushing back all pending IO. (3) We need to save and restore the pci state across PCIe EEH handling. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 13 +++++++++ drivers/scsi/mpt2sas/mpt2sas_base.h | 2 ++ drivers/scsi/mpt2sas/mpt2sas_config.c | 2 +- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 4 +-- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 47 ++++++++++++++++++++++++-------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 8 +++--- 6 files changed, 57 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 1f22a764927..57bcd5c9dcf 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1311,6 +1311,9 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", ioc->name, (unsigned long long)pio_chip, pio_sz); + /* Save PCI configuration state for recovery from PCI AER/EEH errors */ + pci_save_state(pdev); + return 0; out_fail: @@ -3407,6 +3410,9 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); + if (ioc->pci_error_recovery) + return 0; + ioc_state = mpt2sas_base_get_iocstate(ioc, 0); dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", ioc->name, __func__, ioc_state)); @@ -3869,6 +3875,13 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, __func__)); + if (ioc->pci_error_recovery) { + printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", + ioc->name, __func__); + r = 0; + goto out; + } + if (mpt2sas_fwfault_debug) mpt2sas_halt_firmware(ioc); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 0b0ef5e7899..0ebef0c0d94 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -477,6 +477,7 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); * @ioc_link_reset_in_progress: phy/hard reset in progress * @ignore_loginfos: ignore loginfos during task managment * @remove_host: flag for when driver unloads, to avoid sending dev resets + * @pci_error_recovery: flag to prevent ioc access until slot reset completes * @wait_for_port_enable_to_complete: * @msix_enable: flag indicating msix is enabled * @msix_vector_count: number msix vectors @@ -617,6 +618,7 @@ struct MPT2SAS_ADAPTER { u8 ignore_loginfos; u8 remove_host; + u8 pci_error_recovery; u8 wait_for_port_enable_to_complete; u8 msix_enable; diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index e26f9206a52..6afd67b324f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -401,7 +401,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t if (ioc->config_cmds.smid == smid) mpt2sas_base_free_smid(ioc, smid); if ((ioc->shost_recovery) || (ioc->config_cmds.status & - MPT2_CMD_RESET)) + MPT2_CMD_RESET) || ioc->pci_error_recovery) goto retry_config; issue_host_reset = 1; r = -EFAULT; diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 55ac1cb3477..b774973f076 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -2156,7 +2156,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) !ioc) return -ENODEV; - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) return -EAGAIN; if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { @@ -2275,7 +2275,7 @@ _ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) return -EAGAIN; memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 854cc91e7aa..6273abd0535 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1997,7 +1997,8 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, goto err_out; } - if (ioc->shost_recovery || ioc->remove_host) { + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); rc = FAILED; @@ -2644,7 +2645,8 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) unsigned long flags; struct _tr_list *delayed_tr; - if (ioc->shost_recovery || ioc->remove_host) { + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " "progress!\n", __func__, ioc->name)); return; @@ -2742,7 +2744,8 @@ _scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) u16 smid; struct _tr_list *delayed_tr; - if (ioc->shost_recovery || ioc->remove_host) { + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " "progress!\n", __func__, ioc->name)); return; @@ -2793,7 +2796,8 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, Mpi2SCSITaskManagementReply_t *mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->shost_recovery || ioc->remove_host) { + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " "progress!\n", __func__, ioc->name)); return 1; @@ -2845,7 +2849,8 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, Mpi2SasIoUnitControlRequest_t *mpi_request; u16 smid_sas_ctrl; - if (ioc->shost_recovery || ioc->remove_host) { + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) { dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " "progress!\n", __func__, ioc->name)); return 1; @@ -3187,7 +3192,10 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) count++; mpt2sas_base_free_smid(ioc, smid); scsi_dma_unmap(scmd); - scmd->result = DID_RESET << 16; + if (ioc->pci_error_recovery) + scmd->result = DID_NO_CONNECT << 16; + else + scmd->result = DID_RESET << 16; scmd->scsi_done(scmd); } dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", @@ -3324,6 +3332,12 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) return 0; } + if (ioc->pci_error_recovery) { + scmd->result = DID_NO_CONNECT << 16; + scmd->scsi_done(scmd); + return 0; + } + sas_target_priv_data = sas_device_priv_data->sas_target; /* invalid device handle */ if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { @@ -4156,7 +4170,7 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) if (!handle) return -1; - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) return -1; if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, @@ -4734,7 +4748,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, _scsih_sas_topology_change_event_debug(ioc, event_data); #endif - if (ioc->shost_recovery || ioc->remove_host) + if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) return; if (!ioc->sas_hba.num_phys) @@ -4773,7 +4787,8 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, "expander event\n", ioc->name)); return; } - if (ioc->shost_recovery || ioc->remove_host) + if (ioc->shost_recovery || ioc->remove_host || + ioc->pci_error_recovery) return; phy_number = event_data->StartPhyNum + i; reason_code = event_data->PHY[i].PhyStatus & @@ -6273,7 +6288,8 @@ _firmware_event_work(struct work_struct *work) struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || fw_event->cancel_pending_work) { + if (ioc->remove_host || fw_event->cancel_pending_work || + ioc->pci_error_recovery) { _scsih_fw_event_free(ioc, fw_event); return; } @@ -6355,7 +6371,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u16 sz; /* events turned off due to host reset or driver unloading */ - if (ioc->remove_host) + if (ioc->remove_host || ioc->pci_error_recovery) return 1; mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); @@ -7058,12 +7074,17 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) case pci_channel_io_normal: return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: + /* Fatal error, prepare for slot reset */ + ioc->pci_error_recovery = 1; scsi_block_requests(ioc->shost); mpt2sas_base_stop_watchdog(ioc); mpt2sas_base_free_resources(ioc); return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: - _scsih_remove(pdev); + /* Permanent error, prepare for device removal */ + ioc->pci_error_recovery = 1; + mpt2sas_base_stop_watchdog(ioc); + _scsih_flush_running_cmds(ioc); return PCI_ERS_RESULT_DISCONNECT; } return PCI_ERS_RESULT_NEED_RESET; @@ -7087,7 +7108,9 @@ _scsih_pci_slot_reset(struct pci_dev *pdev) printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", ioc->name); + ioc->pci_error_recovery = 0; ioc->pdev = pdev; + pci_restore_state(pdev); rc = mpt2sas_base_map_resources(ioc); if (rc) return PCI_ERS_RESULT_DISCONNECT; diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index f29ea5e78bb..b55c6dc0747 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -140,7 +140,7 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, u32 device_info; u32 ioc_status; - if (ioc->shost_recovery) { + if (ioc->shost_recovery || ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; @@ -302,7 +302,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, u64 *sas_address_le; u16 wait_state_count; - if (ioc->shost_recovery) { + if (ioc->shost_recovery || ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; @@ -894,7 +894,7 @@ mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node; struct _sas_phy *mpt2sas_phy; - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) return; spin_lock_irqsave(&ioc->sas_node_lock, flags); @@ -997,7 +997,7 @@ _transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, u64 *sas_address_le; u16 wait_state_count; - if (ioc->shost_recovery) { + if (ioc->shost_recovery || ioc->pci_error_recovery) { printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", __func__, ioc->name); return -EFAULT; -- cgit v1.2.3-70-g09d2 From 293f82d59ed8b6d61d242e40ee7a6a146fae5eaa Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:45:20 -0700 Subject: [SCSI] bfa: enable new hardware This patch enables support of new mezzanine cards for HP and IBM blade server. - Add new pciids for HP and IBM mezzanine card. - Add a new firmware image for HP mezzanine card, which is running in FC only mode. Rename firmware image to reflect the difference. Change the firmware download code accordingly for the above changes. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_core.c | 1 + drivers/scsi/bfa/bfa_fwimg_priv.h | 25 ++++++--- drivers/scsi/bfa/bfa_ioc.c | 33 ++++++------ drivers/scsi/bfa/bfa_ioc.h | 7 +-- drivers/scsi/bfa/bfa_ioc_cb.c | 36 ++++--------- drivers/scsi/bfa/bfa_ioc_ct.c | 46 +++++++---------- drivers/scsi/bfa/bfa_iocfc.c | 6 +-- drivers/scsi/bfa/bfad.c | 8 +++ drivers/scsi/bfa/bfad_fwimg.c | 76 ++++++++++++++++++++-------- drivers/scsi/bfa/bfad_im_compat.h | 13 +++-- drivers/scsi/bfa/bfad_intr.c | 4 +- drivers/scsi/bfa/include/bfi/bfi_ioc.h | 1 + drivers/scsi/bfa/include/defs/bfa_defs_mfg.h | 3 ++ drivers/scsi/bfa/include/defs/bfa_defs_pci.h | 11 +++- 14 files changed, 155 insertions(+), 115 deletions(-) diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 3a7b3f88932..bef70924d5c 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -333,6 +333,7 @@ bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P}, {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P}, {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT}, + {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC}, }; *npciids = sizeof(__pciids) / sizeof(__pciids[0]); diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h index 1ec1355924d..d33e19e5439 100644 --- a/drivers/scsi/bfa/bfa_fwimg_priv.h +++ b/drivers/scsi/bfa/bfa_fwimg_priv.h @@ -21,11 +21,24 @@ #define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ #define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) -extern u32 *bfi_image_ct_get_chunk(u32 off); -extern u32 bfi_image_ct_size; -extern u32 *bfi_image_cb_get_chunk(u32 off); -extern u32 bfi_image_cb_size; -extern u32 *bfi_image_cb; -extern u32 *bfi_image_ct; +/** + * BFI FW image type + */ +enum { + BFI_IMAGE_CB_FC, + BFI_IMAGE_CT_FC, + BFI_IMAGE_CT_CNA, + BFI_IMAGE_MAX, +}; + +extern u32 *bfi_image_get_chunk(int type, uint32_t off); +extern u32 bfi_image_get_size(int type); +extern u32 bfi_image_ct_fc_size; +extern u32 bfi_image_ct_cna_size; +extern u32 bfi_image_cb_fc_size; +extern u32 *bfi_image_ct_fc; +extern u32 *bfi_image_ct_cna; +extern u32 *bfi_image_cb_fc; + #endif /* __BFA_FWIMG_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index e038bc9769f..ef3b3fefbe7 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -59,14 +59,12 @@ BFA_TRC_FILE(CNA, IOC); ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc)) #define bfa_ioc_firmware_unlock(__ioc) \ ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc)) -#define bfa_ioc_fwimg_get_chunk(__ioc, __off) \ - ((__ioc)->ioc_hwif->ioc_fwimg_get_chunk(__ioc, __off)) -#define bfa_ioc_fwimg_get_size(__ioc) \ - ((__ioc)->ioc_hwif->ioc_fwimg_get_size(__ioc)) #define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc)) #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) #define bfa_ioc_notify_hbfail(__ioc) \ ((__ioc)->ioc_hwif->ioc_notify_hbfail(__ioc)) +#define bfa_ioc_is_optrom(__ioc) \ + (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(__ioc)) < BFA_IOC_FWIMG_MINSZ) bfa_boolean_t bfa_auto_recover = BFA_TRUE; @@ -879,8 +877,8 @@ bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) struct bfi_ioc_image_hdr_s *drv_fwhdr; int i; - drv_fwhdr = - (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0); + drv_fwhdr = (struct bfi_ioc_image_hdr_s *) + bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { @@ -907,12 +905,13 @@ bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc) /** * If bios/efi boot (flash based) -- return true */ - if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) + if (bfa_ioc_is_optrom(ioc)) return BFA_TRUE; bfa_ioc_fwver_get(ioc, &fwhdr); - drv_fwhdr = - (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0); + drv_fwhdr = (struct bfi_ioc_image_hdr_s *) + bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), 0); + if (fwhdr.signature != drv_fwhdr->signature) { bfa_trc(ioc, fwhdr.signature); @@ -1125,21 +1124,22 @@ bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, /** * Flash based firmware boot */ - bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc)); - if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) + bfa_trc(ioc, bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc))); + if (bfa_ioc_is_optrom(ioc)) boot_type = BFI_BOOT_TYPE_FLASH; - fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno); + fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno); + pgnum = bfa_ioc_smem_pgnum(ioc, loff); pgoff = bfa_ioc_smem_pgoff(ioc, loff); bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum); - for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) { + for (i = 0; i < bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)); i++) { if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { chunkno = BFA_IOC_FLASH_CHUNK_NO(i); - fwimg = bfa_ioc_fwimg_get_chunk(ioc, + fwimg = bfi_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); } @@ -1188,6 +1188,7 @@ bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) struct bfi_ioc_attr_s *attr = ioc->attr; attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop); + attr->card_type = bfa_os_ntohl(attr->card_type); attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize); bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); @@ -1416,7 +1417,7 @@ bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, { ioc->ioc_mc = mc; ioc->pcidev = *pcidev; - ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT); + ioc->ctdev = bfa_asic_id_ct(ioc->pcidev.device_id); ioc->cna = ioc->ctdev && !ioc->fcmode; /** @@ -1916,7 +1917,7 @@ bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) { - return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT); + return ioc->fcmode || !bfa_asic_id_ct(ioc->pcidev.device_id); } /** diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index d0804406ea1..2fbb6b2efc7 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -186,9 +186,6 @@ struct bfa_ioc_hwif_s { bfa_status_t (*ioc_pll_init) (struct bfa_ioc_s *ioc); bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc); void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc); - u32 * (*ioc_fwimg_get_chunk) (struct bfa_ioc_s *ioc, - u32 off); - u32 (*ioc_fwimg_get_size) (struct bfa_ioc_s *ioc); void (*ioc_reg_init) (struct bfa_ioc_s *ioc); void (*ioc_map_port) (struct bfa_ioc_s *ioc); void (*ioc_isr_mode_set) (struct bfa_ioc_s *ioc, @@ -214,6 +211,10 @@ struct bfa_ioc_hwif_s { #define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++) #define BFA_IOC_FWIMG_MINSZ (16 * 1024) +#define BFA_IOC_FWIMG_TYPE(__ioc) \ + (((__ioc)->ctdev) ? \ + (((__ioc)->fcmode) ? BFI_IMAGE_CT_FC : BFI_IMAGE_CT_CNA) : \ + BFI_IMAGE_CB_FC) #define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS) #define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS) diff --git a/drivers/scsi/bfa/bfa_ioc_cb.c b/drivers/scsi/bfa/bfa_ioc_cb.c index 3ce85319f73..324bdde7ea2 100644 --- a/drivers/scsi/bfa/bfa_ioc_cb.c +++ b/drivers/scsi/bfa/bfa_ioc_cb.c @@ -33,26 +33,13 @@ BFA_TRC_FILE(CNA, IOC_CB); static bfa_status_t bfa_ioc_cb_pll_init(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc); static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc); -static u32 *bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off); -static u32 bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc); static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); static void bfa_ioc_cb_notify_hbfail(struct bfa_ioc_s *ioc); static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); -struct bfa_ioc_hwif_s hwif_cb = { - bfa_ioc_cb_pll_init, - bfa_ioc_cb_firmware_lock, - bfa_ioc_cb_firmware_unlock, - bfa_ioc_cb_fwimg_get_chunk, - bfa_ioc_cb_fwimg_get_size, - bfa_ioc_cb_reg_init, - bfa_ioc_cb_map_port, - bfa_ioc_cb_isr_mode_set, - bfa_ioc_cb_notify_hbfail, - bfa_ioc_cb_ownership_reset, -}; +struct bfa_ioc_hwif_s hwif_cb; /** * Called from bfa_ioc_attach() to map asic specific calls. @@ -60,19 +47,16 @@ struct bfa_ioc_hwif_s hwif_cb = { void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) { - ioc->ioc_hwif = &hwif_cb; -} - -static u32 * -bfa_ioc_cb_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off) -{ - return bfi_image_cb_get_chunk(off); -} + hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init; + hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock; + hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock; + hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init; + hwif_cb.ioc_map_port = bfa_ioc_cb_map_port; + hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; + hwif_cb.ioc_notify_hbfail = bfa_ioc_cb_notify_hbfail; + hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; -static u32 -bfa_ioc_cb_fwimg_get_size(struct bfa_ioc_s *ioc) -{ - return bfi_image_cb_size; + ioc->ioc_hwif = &hwif_cb; } /** diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 20b58ad5f95..17bd1513b34 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c @@ -33,27 +33,13 @@ BFA_TRC_FILE(CNA, IOC_CT); static bfa_status_t bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc); static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); -static u32* bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, - u32 off); -static u32 bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); static void bfa_ioc_ct_notify_hbfail(struct bfa_ioc_s *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); -struct bfa_ioc_hwif_s hwif_ct = { - bfa_ioc_ct_pll_init, - bfa_ioc_ct_firmware_lock, - bfa_ioc_ct_firmware_unlock, - bfa_ioc_ct_fwimg_get_chunk, - bfa_ioc_ct_fwimg_get_size, - bfa_ioc_ct_reg_init, - bfa_ioc_ct_map_port, - bfa_ioc_ct_isr_mode_set, - bfa_ioc_ct_notify_hbfail, - bfa_ioc_ct_ownership_reset, -}; +struct bfa_ioc_hwif_s hwif_ct; /** * Called from bfa_ioc_attach() to map asic specific calls. @@ -61,19 +47,16 @@ struct bfa_ioc_hwif_s hwif_ct = { void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) { - ioc->ioc_hwif = &hwif_ct; -} + hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; + hwif_ct.ioc_firmware_lock = bfa_ioc_ct_firmware_lock; + hwif_ct.ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; + hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; + hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; + hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; + hwif_ct.ioc_notify_hbfail = bfa_ioc_ct_notify_hbfail; + hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; -static u32* -bfa_ioc_ct_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off) -{ - return bfi_image_ct_get_chunk(off); -} - -static u32 -bfa_ioc_ct_fwimg_get_size(struct bfa_ioc_s *ioc) -{ - return bfi_image_ct_size; + ioc->ioc_hwif = &hwif_ct; } /** @@ -95,7 +78,7 @@ bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) /** * If bios boot (flash based) -- do not increment usage count */ - if (bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) + if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return BFA_TRUE; bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); @@ -146,9 +129,14 @@ bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) /** * Firmware lock is relevant only for CNA. + */ + if (!ioc->cna) + return; + + /** * If bios boot (flash based) -- do not decrement usage count */ - if (!ioc->cna || bfa_ioc_ct_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ) + if (bfi_image_get_size(BFA_IOC_FWIMG_TYPE(ioc)) < BFA_IOC_FWIMG_MINSZ) return; /** diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index a76de2669bf..273ecece79a 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -170,7 +170,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, /** * Initialize chip specific handlers. */ - if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) { + if (bfa_asic_id_ct(bfa_ioc_devid(&bfa->ioc))) { iocfc->hwif.hw_reginit = bfa_hwct_reginit; iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack; iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; @@ -625,9 +625,9 @@ bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa->trcmod, bfa->aen, bfa->logm); /** - * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode. + * Set FC mode for BFA_PCI_DEVICE_ID_CT_FC. */ - if (0) + if (pcidev->device_id == BFA_PCI_DEVICE_ID_CT_FC) bfa_ioc_set_fcmode(&bfa->ioc); bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC); diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index d4fc4287ebd..1b869add20b 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1172,6 +1172,14 @@ static struct pci_device_id bfad_id_table[] = { .class = (PCI_CLASS_SERIAL_FIBER << 8), .class_mask = ~0, }, + { + .vendor = BFA_PCI_VENDOR_ID_BROCADE, + .device = BFA_PCI_DEVICE_ID_CT_FC, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_SERIAL_FIBER << 8), + .class_mask = ~0, + }, {0, 0}, }; diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c index 2ad65f275a9..1baca1a1208 100644 --- a/drivers/scsi/bfa/bfad_fwimg.c +++ b/drivers/scsi/bfa/bfad_fwimg.c @@ -33,16 +33,20 @@ #include #include -u32 bfi_image_ct_size; -u32 bfi_image_cb_size; -u32 *bfi_image_ct; -u32 *bfi_image_cb; +u32 bfi_image_ct_fc_size; +u32 bfi_image_ct_cna_size; +u32 bfi_image_cb_fc_size; +u32 *bfi_image_ct_fc; +u32 *bfi_image_ct_cna; +u32 *bfi_image_cb_fc; -#define BFAD_FW_FILE_CT "ctfw.bin" -#define BFAD_FW_FILE_CB "cbfw.bin" -MODULE_FIRMWARE(BFAD_FW_FILE_CT); -MODULE_FIRMWARE(BFAD_FW_FILE_CB); +#define BFAD_FW_FILE_CT_FC "ctfw_fc.bin" +#define BFAD_FW_FILE_CT_CNA "ctfw_cna.bin" +#define BFAD_FW_FILE_CB_FC "cbfw_fc.bin" +MODULE_FIRMWARE(BFAD_FW_FILE_CT_FC); +MODULE_FIRMWARE(BFAD_FW_FILE_CT_CNA); +MODULE_FIRMWARE(BFAD_FW_FILE_CB_FC); u32 * bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, @@ -74,24 +78,54 @@ error: u32 * bfad_get_firmware_buf(struct pci_dev *pdev) { - if (pdev->device == BFA_PCI_DEVICE_ID_CT) { - if (bfi_image_ct_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct, - &bfi_image_ct_size, BFAD_FW_FILE_CT); - return bfi_image_ct; + if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) { + if (bfi_image_ct_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_fc, + &bfi_image_ct_fc_size, BFAD_FW_FILE_CT_FC); + return bfi_image_ct_fc; + } else if (pdev->device == BFA_PCI_DEVICE_ID_CT) { + if (bfi_image_ct_cna_size == 0) + bfad_read_firmware(pdev, &bfi_image_ct_cna, + &bfi_image_ct_cna_size, BFAD_FW_FILE_CT_CNA); + return bfi_image_ct_cna; } else { - if (bfi_image_cb_size == 0) - bfad_read_firmware(pdev, &bfi_image_cb, - &bfi_image_cb_size, BFAD_FW_FILE_CB); - return bfi_image_cb; + if (bfi_image_cb_fc_size == 0) + bfad_read_firmware(pdev, &bfi_image_cb_fc, + &bfi_image_cb_fc_size, BFAD_FW_FILE_CB_FC); + return bfi_image_cb_fc; } } u32 * -bfi_image_ct_get_chunk(u32 off) -{ return (u32 *)(bfi_image_ct + off); } +bfi_image_ct_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_fc + off); } u32 * -bfi_image_cb_get_chunk(u32 off) -{ return (u32 *)(bfi_image_cb + off); } +bfi_image_ct_cna_get_chunk(u32 off) +{ return (u32 *)(bfi_image_ct_cna + off); } +u32 * +bfi_image_cb_fc_get_chunk(u32 off) +{ return (u32 *)(bfi_image_cb_fc + off); } + +uint32_t * +bfi_image_get_chunk(int type, uint32_t off) +{ + switch (type) { + case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_get_chunk(off); break; + case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_get_chunk(off); break; + case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_get_chunk(off); break; + default: return 0; break; + } +} + +uint32_t +bfi_image_get_size(int type) +{ + switch (type) { + case BFI_IMAGE_CT_FC: return bfi_image_ct_fc_size; break; + case BFI_IMAGE_CT_CNA: return bfi_image_ct_cna_size; break; + case BFI_IMAGE_CB_FC: return bfi_image_cb_fc_size; break; + default: return 0; break; + } +} diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h index b36be15044a..0a122abbbe8 100644 --- a/drivers/scsi/bfa/bfad_im_compat.h +++ b/drivers/scsi/bfa/bfad_im_compat.h @@ -18,9 +18,6 @@ #ifndef __BFAD_IM_COMPAT_H__ #define __BFAD_IM_COMPAT_H__ -extern u32 *bfi_image_buf; -extern u32 bfi_image_size; - extern struct device_attribute *bfad_im_host_attrs[]; extern struct device_attribute *bfad_im_vport_attrs[]; @@ -37,10 +34,12 @@ bfad_load_fwimg(struct pci_dev *pdev) static inline void bfad_free_fwimg(void) { - if (bfi_image_ct_size && bfi_image_ct) - vfree(bfi_image_ct); - if (bfi_image_cb_size && bfi_image_cb) - vfree(bfi_image_cb); + if (bfi_image_ct_fc_size && bfi_image_ct_fc) + vfree(bfi_image_ct_fc); + if (bfi_image_ct_cna_size && bfi_image_ct_cna) + vfree(bfi_image_ct_cna); + if (bfi_image_cb_fc_size && bfi_image_cb_fc) + vfree(bfi_image_cb_fc); } #endif diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c index 2b7dbecbebc..fed27d16365 100644 --- a/drivers/scsi/bfa/bfad_intr.c +++ b/drivers/scsi/bfa/bfad_intr.c @@ -151,8 +151,8 @@ bfad_setup_intr(struct bfad_s *bfad) /* Set up the msix entry table */ bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); - if ((pdev->device == BFA_PCI_DEVICE_ID_CT && !msix_disable_ct) || - (pdev->device != BFA_PCI_DEVICE_ID_CT && !msix_disable_cb)) { + if ((bfa_asic_id_ct(pdev->device) && !msix_disable_ct) || + (!bfa_asic_id_ct(pdev->device) && !msix_disable_cb)) { error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); if (error) { diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h index a0158aac002..03a9c9408ca 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h +++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h @@ -63,6 +63,7 @@ struct bfi_ioc_attr_s { char fw_version[BFA_VERSION_LEN]; char optrom_version[BFA_VERSION_LEN]; struct bfa_mfg_vpd_s vpd; + uint32_t card_type; /* card type */ }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h index c5bd9c36ad4..bfb50eb2124 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h @@ -86,6 +86,9 @@ enum { BFA_MFG_TYPE_FC4P1 = 415, /* 4G 1port FC card */ BFA_MFG_TYPE_CNA10P2 = 1020, /* 10G 2port CNA card */ BFA_MFG_TYPE_CNA10P1 = 1010, /* 10G 1port CNA card */ + BFA_MFG_TYPE_JAYHAWK = 804, /* Jayhawk mezz card */ + BFA_MFG_TYPE_WANCHESE = 1007, /* Wanchese mezz card */ + BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ }; #pragma pack(1) diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h index c9b83321694..ea7d89bbc0b 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h @@ -26,8 +26,13 @@ enum { BFA_PCI_DEVICE_ID_FC_8G2P = 0x13, BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, BFA_PCI_DEVICE_ID_CT = 0x14, + BFA_PCI_DEVICE_ID_CT_FC = 0x21, }; +#define bfa_asic_id_ct(devid) \ + ((devid) == BFA_PCI_DEVICE_ID_CT || \ + (devid) == BFA_PCI_DEVICE_ID_CT_FC) + /** * PCI sub-system device and vendor ID information */ @@ -35,7 +40,9 @@ enum { BFA_PCI_FCOE_SSDEVICE_ID = 0x14, }; -#define BFA_PCI_ACCESS_RANGES 1 /* Maximum number of device address ranges - * mapped through different BAR(s). */ +/** + * Maximum number of device address ranges mapped through different BAR(s) + */ +#define BFA_PCI_ACCESS_RANGES 1 #endif /* __BFA_DEFS_PCI_H__ */ -- cgit v1.2.3-70-g09d2 From ed96932470e4ca3aab29518a748dc1162853b456 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:45:56 -0700 Subject: [SCSI] bfa: enable basic PBC support The patch includes the driver side changes to enable basic PBC (PreBoot Configuration) feature. - Data structure changes and new definitions for PBC. - APIs to access PBC info. - Remove unused code. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcpim.c | 5 -- drivers/scsi/bfa/bfa_fcport.c | 42 ++++++++-------- drivers/scsi/bfa/bfa_fcxp.c | 14 ++---- drivers/scsi/bfa/bfa_ioc.c | 41 ++++------------ drivers/scsi/bfa/bfa_ioc.h | 1 - drivers/scsi/bfa/bfa_iocfc.c | 27 ++++++----- drivers/scsi/bfa/bfa_iocfc.h | 5 +- drivers/scsi/bfa/bfa_lps.c | 6 --- drivers/scsi/bfa/bfa_port_priv.h | 4 +- drivers/scsi/bfa/bfa_priv.h | 3 -- drivers/scsi/bfa/bfa_rport.c | 5 -- drivers/scsi/bfa/bfa_sgpg.c | 5 -- drivers/scsi/bfa/bfa_uf.c | 5 -- drivers/scsi/bfa/include/bfi/bfi_iocfc.h | 2 + drivers/scsi/bfa/include/bfi/bfi_pbc.h | 62 ++++++++++++++++++++++++ drivers/scsi/bfa/include/defs/bfa_defs_adapter.h | 3 +- drivers/scsi/bfa/include/defs/bfa_defs_boot.h | 10 ++++ drivers/scsi/bfa/include/defs/bfa_defs_mfg.h | 38 +++++++-------- drivers/scsi/bfa/include/defs/bfa_defs_pport.h | 3 ++ 19 files changed, 154 insertions(+), 127 deletions(-) create mode 100644 drivers/scsi/bfa/include/bfi/bfi_pbc.h diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 790c945aeae..12849e9071c 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -79,11 +79,6 @@ bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_ioim_attach(fcpim, meminfo); } -static void -bfa_fcpim_initdone(struct bfa_s *bfa) -{ -} - static void bfa_fcpim_detach(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index c589488db0c..4961b8da912 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -911,25 +911,6 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport); } -static void -bfa_fcport_initdone(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - /** - * Initialize port attributes from IOC hardware data. - */ - bfa_fcport_set_wwns(fcport); - if (fcport->cfg.maxfrsize == 0) - fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc); - fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); - fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); - - bfa_assert(fcport->cfg.maxfrsize); - bfa_assert(fcport->cfg.rx_bbcredit); - bfa_assert(fcport->speed_sup); -} - static void bfa_fcport_detach(struct bfa_s *bfa) { @@ -1262,6 +1243,29 @@ bfa_fcport_send_stats_clear(void *cbarg) * bfa_pport_public */ +/** + * Called to initialize port attributes + */ +void +bfa_fcport_init(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + + /** + * Initialize port attributes from IOC hardware data. + */ + bfa_fcport_set_wwns(fcport); + if (fcport->cfg.maxfrsize == 0) + fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc); + fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); + fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); + + bfa_assert(fcport->cfg.maxfrsize); + bfa_assert(fcport->cfg.rx_bbcredit); + bfa_assert(fcport->speed_sup); +} + + /** * Firmware message handler. */ diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c index cf0ad678268..8258f88bfee 100644 --- a/drivers/scsi/bfa/bfa_fcxp.c +++ b/drivers/scsi/bfa/bfa_fcxp.c @@ -148,11 +148,6 @@ bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, claim_fcxps_mem(mod, meminfo); } -static void -bfa_fcxp_initdone(struct bfa_s *bfa) -{ -} - static void bfa_fcxp_detach(struct bfa_s *bfa) { @@ -225,7 +220,7 @@ bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, bfa_status_t req_status, u32 rsp_len, u32 resid_len, struct fchs_s *rsp_fchs) { - /**discarded fcxp completion */ + /* discarded fcxp completion */ } static void @@ -527,11 +522,8 @@ bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, if (nreq_sgles > BFI_SGE_INLINE) { nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles); - if (bfa_sgpg_malloc - (bfa, &fcxp->req_sgpg_q, nreq_sgpg) + if (bfa_sgpg_malloc(bfa, &fcxp->req_sgpg_q, nreq_sgpg) != BFA_STATUS_OK) { - /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe, - nreq_sgpg); */ /* * TODO */ @@ -685,7 +677,7 @@ bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, fcxp->send_cbarg = cbarg; /** - * If no room in CPE queue, wait for + * If no room in CPE queue, wait for space in request queue */ send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); if (!send_req) { diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index ef3b3fefbe7..268c071ce67 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -1608,6 +1608,13 @@ bfa_ioc_error_isr(struct bfa_ioc_s *ioc) bfa_fsm_send_event(ioc, IOC_E_HWERROR); } +void +bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) +{ + ioc->fcmode = BFA_TRUE; + ioc->port_id = bfa_ioc_pcifn(ioc); +} + #ifndef BFA_BIOS_BUILD /** @@ -1697,6 +1704,9 @@ bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, /* For now, model descr uses same model string */ bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr); + ad_attr->card_type = ioc_attr->card_type; + ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type); + if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop)) ad_attr->prototype = 1; else @@ -1866,30 +1876,6 @@ bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc) return w.wwn; } -wwn_t -bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst) -{ - union { - wwn_t wwn; - u8 byte[sizeof(wwn_t)]; - } - w , w5; - - bfa_trc(ioc, inst); - - w.wwn = ioc->attr->mfg_wwn; - w5.byte[0] = 0x50 | w.byte[2] >> 4; - w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4; - w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4; - w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4; - w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4; - w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4; - w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8; - w5.byte[7] = (inst & 0xff); - - return w5.wwn; -} - u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc) { @@ -1907,13 +1893,6 @@ bfa_ioc_get_mac(struct bfa_ioc_s *ioc) return mac; } -void -bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc) -{ - ioc->fcmode = BFA_TRUE; - ioc->port_id = bfa_ioc_pcifn(ioc); -} - bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) { diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 2fbb6b2efc7..df15eccd760 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -303,7 +303,6 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, */ wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc); wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc); -wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst); mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc); u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc); diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index 273ecece79a..afa3da08b78 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -290,18 +290,6 @@ bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg, } } -/** - * BFA submodules initialization completion notification. - */ -static void -bfa_iocfc_initdone_submod(struct bfa_s *bfa) -{ - int i; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->initdone(bfa); -} - /** * Start BFA submodules. */ @@ -394,6 +382,8 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) /** * Configuration is complete - initialize/start submodules */ + bfa_fcport_init(bfa); + if (iocfc->action == BFA_IOCFC_ACT_INIT) bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa); else @@ -531,7 +521,6 @@ bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) return; } - bfa_iocfc_initdone_submod(bfa); bfa_iocfc_send_cfg(bfa); } @@ -881,6 +870,18 @@ bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns) *wwns = cfgrsp->bootwwns.wwn; } +void +bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + + pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled; + pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns; + pbcfg->speed = cfgrsp->pbc_cfg.port_speed; + memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun)); +} + #endif diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h index fbb4bdc9d60..3ee9fe7a796 100644 --- a/drivers/scsi/bfa/bfa_iocfc.h +++ b/drivers/scsi/bfa/bfa_iocfc.h @@ -116,7 +116,8 @@ struct bfa_iocfc_s { #define bfa_isr_mode_set(__bfa, __msix) \ ((__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix)) #define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ - (__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) + ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ + __nvecs, __maxvec)) /* * FC specific IOC functions. @@ -166,6 +167,8 @@ void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len); void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi, bfa_boolean_t mincfg); void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns); +void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, + struct bfa_boot_pbc_s *pbcfg); #endif /* __BFA_IOCFC_H__ */ diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c index ad06f618909..acabb44f092 100644 --- a/drivers/scsi/bfa/bfa_lps.c +++ b/drivers/scsi/bfa/bfa_lps.c @@ -41,7 +41,6 @@ static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); -static void bfa_lps_initdone(struct bfa_s *bfa); static void bfa_lps_detach(struct bfa_s *bfa); static void bfa_lps_start(struct bfa_s *bfa); static void bfa_lps_stop(struct bfa_s *bfa); @@ -346,11 +345,6 @@ bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, } } -static void -bfa_lps_initdone(struct bfa_s *bfa) -{ -} - static void bfa_lps_detach(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h index 40e256ec67f..c52fe56df0b 100644 --- a/drivers/scsi/bfa/bfa_port_priv.h +++ b/drivers/scsi/bfa/bfa_port_priv.h @@ -87,5 +87,7 @@ struct bfa_fcport_s { /* * public functions */ -void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); +void bfa_fcport_init(struct bfa_s *bfa); +void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); + #endif /* __BFA_PORT_PRIV_H__ */ diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h index be80fc7e1b0..bf4939b1676 100644 --- a/drivers/scsi/bfa/bfa_priv.h +++ b/drivers/scsi/bfa/bfa_priv.h @@ -37,7 +37,6 @@ void *bfad, struct bfa_iocfc_cfg_s *cfg, \ struct bfa_meminfo_s *meminfo, \ struct bfa_pcidev_s *pcidev); \ - static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa); \ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \ static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \ @@ -47,7 +46,6 @@ struct bfa_module_s hal_mod_ ## __mod = { \ bfa_ ## __mod ## _meminfo, \ bfa_ ## __mod ## _attach, \ - bfa_ ## __mod ## _initdone, \ bfa_ ## __mod ## _detach, \ bfa_ ## __mod ## _start, \ bfa_ ## __mod ## _stop, \ @@ -69,7 +67,6 @@ struct bfa_module_s { struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev); - void (*initdone) (struct bfa_s *bfa); void (*detach) (struct bfa_s *bfa); void (*start) (struct bfa_s *bfa); void (*stop) (struct bfa_s *bfa); diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c index 7c509fa244e..ccd0680f6f1 100644 --- a/drivers/scsi/bfa/bfa_rport.c +++ b/drivers/scsi/bfa/bfa_rport.c @@ -635,11 +635,6 @@ bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_meminfo_kva(meminfo) = (u8 *) rp; } -static void -bfa_rport_initdone(struct bfa_s *bfa) -{ -} - static void bfa_rport_detach(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c index 279d8f9b890..ae452c42e40 100644 --- a/drivers/scsi/bfa/bfa_sgpg.c +++ b/drivers/scsi/bfa/bfa_sgpg.c @@ -93,11 +93,6 @@ bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa; } -static void -bfa_sgpg_initdone(struct bfa_s *bfa) -{ -} - static void bfa_sgpg_detach(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c index 4b3c2417d18..b2a37fc952d 100644 --- a/drivers/scsi/bfa/bfa_uf.c +++ b/drivers/scsi/bfa/bfa_uf.c @@ -169,11 +169,6 @@ bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, uf_mem_claim(ufm, meminfo); } -static void -bfa_uf_initdone(struct bfa_s *bfa) -{ -} - static void bfa_uf_detach(struct bfa_s *bfa) { diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h index c3760df7257..ccdfcc5d7e0 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h +++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h @@ -19,6 +19,7 @@ #define __BFI_IOCFC_H__ #include "bfi.h" +#include #include #include #include @@ -78,6 +79,7 @@ struct bfi_iocfc_cfgrsp_s { struct bfa_iocfc_fwcfg_s fwcfg; struct bfa_iocfc_intr_attr_s intr_attr; struct bfi_iocfc_bootwwns bootwwns; + struct bfi_pbc_s pbc_cfg; }; /** diff --git a/drivers/scsi/bfa/include/bfi/bfi_pbc.h b/drivers/scsi/bfa/include/bfi/bfi_pbc.h new file mode 100644 index 00000000000..88a4154c30c --- /dev/null +++ b/drivers/scsi/bfa/include/bfi/bfi_pbc.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __BFI_PBC_H__ +#define __BFI_PBC_H__ + +#pragma pack(1) + +#define BFI_PBC_MAX_BLUNS 8 +#define BFI_PBC_MAX_VPORTS 16 + +#define BFI_PBC_PORT_DISABLED 2 +/** + * PBC boot lun configuration + */ +struct bfi_pbc_blun_s { + wwn_t tgt_pwwn; + lun_t tgt_lun; +}; + +/** + * PBC virtual port configuration + */ +struct bfi_pbc_vport_s { + wwn_t vp_pwwn; + wwn_t vp_nwwn; +}; + +/** + * BFI pre-boot configuration information + */ +struct bfi_pbc_s { + u8 port_enabled; + u8 boot_enabled; + u8 nbluns; + u8 nvports; + u8 port_speed; + u8 rsvd_a; + u16 hss; + wwn_t pbc_pwwn; + wwn_t pbc_nwwn; + struct bfi_pbc_blun_s blun[BFI_PBC_MAX_BLUNS]; + struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS]; +}; + +#pragma pack() + +#endif /* __BFI_PBC_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h index 8c208fc8e32..aea0360d67d 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h @@ -39,7 +39,7 @@ enum { struct bfa_adapter_attr_s { char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - u32 rsvd1; + u32 card_type; char model[BFA_ADAPTER_MODEL_NAME_LEN]; char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; wwn_t pwwn; @@ -60,6 +60,7 @@ struct bfa_adapter_attr_s { u8 pcie_lanes_orig; u8 pcie_lanes; u8 cna_capable; + u8 is_mezz; }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h index 6f4aa528354..0fca10b6ad1 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h @@ -24,6 +24,8 @@ enum { BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */ + BFA_PREBOOT_BOOTLUN_MAX = 8, /* maximum preboot lun per IOC */ + }; #define BOOT_CFG_REV1 1 @@ -67,5 +69,13 @@ struct bfa_boot_cfg_s { struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX]; }; +struct bfa_boot_pbc_s { + u8 enable; /* enable/disable SAN boot */ + u8 speed; /* boot speed settings */ + u8 topology; /* boot topology setting */ + u8 rsvd1; + u32 nbluns; /* number of boot luns */ + struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX]; +}; #endif /* __BFA_DEFS_BOOT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h index bfb50eb2124..d22fb790964 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h @@ -44,26 +44,6 @@ */ #define BFA_MFG_CHKSUM_SIZE 16 -/** - * Manufacturing block encrypted version - */ -#define BFA_MFG_ENC_VER 2 - -/** - * Manufacturing block version 1 length - */ -#define BFA_MFG_VER1_LEN 128 - -/** - * Manufacturing block header length - */ -#define BFA_MFG_HDR_LEN 4 - -/** - * Checksum size - */ -#define BFA_MFG_CHKSUM_SIZE 16 - /** * Manufacturing block format */ @@ -98,6 +78,24 @@ enum { */ #define bfa_mfg_type2port_num(card_type) (((card_type) / 10) % 10) +/** + * Check if Mezz card + */ +#define bfa_mfg_is_mezz(type) (( \ + (type) == BFA_MFG_TYPE_JAYHAWK || \ + (type) == BFA_MFG_TYPE_WANCHESE)) + +/** + * Check if card type valid + */ +#define bfa_mfg_is_card_type_valid(type) (( \ + (type) == BFA_MFG_TYPE_FC8P2 || \ + (type) == BFA_MFG_TYPE_FC8P1 || \ + (type) == BFA_MFG_TYPE_FC4P2 || \ + (type) == BFA_MFG_TYPE_FC4P1 || \ + (type) == BFA_MFG_TYPE_CNA10P2 || \ + (type) == BFA_MFG_TYPE_CNA10P1 || \ + bfa_mfg_is_mezz(type))) /** * All numerical fields are in big-endian format. diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h index 26e5cc78095..de6181cf967 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h @@ -38,6 +38,7 @@ enum bfa_pport_states { BFA_PPORT_ST_IOCDOWN = 10, BFA_PPORT_ST_IOCDIS = 11, BFA_PPORT_ST_FWMISMATCH = 12, + BFA_PPORT_ST_PREBOOT_DISABLED = 13, BFA_PPORT_ST_MAX_STATE, }; @@ -203,6 +204,8 @@ struct bfa_pport_attr_s { */ wwn_t nwwn; /* node wwn */ wwn_t pwwn; /* port wwn */ + wwn_t factorynwwn; /* factory node wwn */ + wwn_t factorypwwn; /* factory port wwn */ enum fc_cos cos_supported; /* supported class of services */ u32 rsvd; struct fc_symname_s port_symname; /* port symbolic name */ -- cgit v1.2.3-70-g09d2 From d9883548a0b0afec4786e6c5cd8d03d43a30b779 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:46:26 -0700 Subject: [SCSI] bfa: PBC vport create This patch enables creating PBC vport. During fcs init, fcs will read PBC vport using bfa iocfc API and invoke fcb callback to add the pbc vport entries into a list. The pbc vport list will be traversed in the subsequent pci probe process and vport will be created using fc transport provided vport create function. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcs.c | 10 +++- drivers/scsi/bfa/bfa_iocfc.c | 11 +++++ drivers/scsi/bfa/bfa_iocfc.h | 3 ++ drivers/scsi/bfa/bfad.c | 61 +++++++++++++++++++++++-- drivers/scsi/bfa/bfad_attr.c | 43 ++++++++++------- drivers/scsi/bfa/bfad_drv.h | 8 ++++ drivers/scsi/bfa/bfad_im.c | 1 + drivers/scsi/bfa/fabric.c | 2 +- drivers/scsi/bfa/fcs_vport.h | 1 + drivers/scsi/bfa/include/defs/bfa_defs_port.h | 12 ++--- drivers/scsi/bfa/include/defs/bfa_defs_status.h | 5 +- drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h | 3 +- drivers/scsi/bfa/include/fcs/bfa_fcs.h | 4 +- drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h | 4 ++ drivers/scsi/bfa/vport.c | 45 ++++++++++++++++++ 15 files changed, 179 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index 3516172c597..3ec2f49de61 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -99,14 +99,22 @@ bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, void bfa_fcs_init(struct bfa_fcs_s *fcs) { - int i; + int i, npbc_vports; struct bfa_fcs_mod_s *mod; + struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { mod = &fcs_modules[i]; if (mod->modinit) mod->modinit(fcs); } + /* Initialize pbc vports */ + if (!fcs->min_cfg) { + npbc_vports = + bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); + for (i = 0; i < npbc_vports; i++) + bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]); + } } /** diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index afa3da08b78..d3f1052744d 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -882,6 +882,17 @@ bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg) memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun)); } +int +bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport) +{ + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + + memcpy(pbc_vport, cfgrsp->pbc_cfg.vport, sizeof(cfgrsp->pbc_cfg.vport)); + return cfgrsp->pbc_cfg.nvports; +} + + #endif diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h index 3ee9fe7a796..a08309fb981 100644 --- a/drivers/scsi/bfa/bfa_iocfc.h +++ b/drivers/scsi/bfa/bfa_iocfc.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #define BFA_REQQ_NELEMS_MIN (4) @@ -169,6 +170,8 @@ void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi, void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns); void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg); +int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, + struct bfi_pbc_vport_s *pbc_vport); #endif /* __BFA_IOCFC_H__ */ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 1b869add20b..37f886d2792 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -322,7 +322,31 @@ ext: return rc; } +/** + * @brief + * FCS PBC VPORT Create + */ +void +bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) +{ + + struct bfad_pcfg_s *pcfg; + + pcfg = kzalloc(sizeof(struct bfad_pcfg_s), GFP_ATOMIC); + if (!pcfg) { + bfa_trc(bfad, 0); + return; + } + pcfg->port_cfg.roles = BFA_PORT_ROLE_FCP_IM; + pcfg->port_cfg.pwwn = pbc_vport.vp_pwwn; + pcfg->port_cfg.nwwn = pbc_vport.vp_nwwn; + pcfg->port_cfg.preboot_vp = BFA_TRUE; + + list_add_tail(&pcfg->list_entry, &bfad->pbc_pcfg_list); + + return; +} void bfad_hal_mem_release(struct bfad_s *bfad) @@ -481,10 +505,10 @@ ext: */ bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_port_cfg_s *port_cfg, struct device *dev) + struct bfa_port_cfg_s *port_cfg, struct device *dev) { struct bfad_vport_s *vport; - int rc = BFA_STATUS_OK; + int rc = BFA_STATUS_OK; unsigned long flags; struct completion fcomp; @@ -496,8 +520,12 @@ bfad_vport_create(struct bfad_s *bfad, u16 vf_id, vport->drv_port.bfad = bfad; spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id, - port_cfg, vport); + if (port_cfg->preboot_vp == BFA_TRUE) + rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport, + &bfad->bfa_fcs, vf_id, port_cfg, vport); + else + rc = bfa_fcs_vport_create(&vport->fcs_vport, + &bfad->bfa_fcs, vf_id, port_cfg, vport); spin_unlock_irqrestore(&bfad->bfad_lock, flags); if (rc != BFA_STATUS_OK) @@ -884,6 +912,7 @@ bfa_status_t bfad_start_ops(struct bfad_s *bfad) { int retval; + struct bfad_pcfg_s *pcfg, *pcfg_new; /* PPORT FCS config */ bfad_fcs_port_cfg(bfad); @@ -901,6 +930,27 @@ bfad_start_ops(struct bfad_s *bfad) bfad_drv_start(bfad); + /* pbc vport creation */ + list_for_each_entry_safe(pcfg, pcfg_new, &bfad->pbc_pcfg_list, + list_entry) { + struct fc_vport_identifiers vid; + struct fc_vport *fc_vport; + + memset(&vid, 0, sizeof(vid)); + vid.roles = FC_PORT_ROLE_FCP_INITIATOR; + vid.vport_type = FC_PORTTYPE_NPIV; + vid.disable = false; + vid.node_name = wwn_to_u64((u8 *)&pcfg->port_cfg.nwwn); + vid.port_name = wwn_to_u64((u8 *)&pcfg->port_cfg.pwwn); + fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid); + if (!fc_vport) + printk(KERN_WARNING "bfad%d: failed to create pbc vport" + " %llx\n", bfad->inst_no, vid.port_name); + list_del(&pcfg->list_entry); + kfree(pcfg); + + } + /* * If bfa_linkup_delay is set to -1 default; try to retrive the * value using the bfad_os_get_linkup_delay(); else use the @@ -928,7 +978,7 @@ out_cfg_pport_failure: } int -bfad_worker (void *ptr) +bfad_worker(void *ptr) { struct bfad_s *bfad; unsigned long flags; @@ -1031,6 +1081,7 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) bfad->ref_count = 0; bfad->pport.bfad = bfad; + INIT_LIST_HEAD(&bfad->pbc_pcfg_list); bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, "%s", "bfad_worker"); diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index e477bfbfa7d..871a3036356 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -373,47 +373,53 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) (struct bfad_im_port_s *) shost->hostdata[0]; struct bfad_s *bfad = im_port->bfad; struct bfa_port_cfg_s port_cfg; + struct bfad_pcfg_s *pcfg; int status = 0, rc; unsigned long flags; memset(&port_cfg, 0, sizeof(port_cfg)); - - port_cfg.pwwn = wwn_to_u64((u8 *) &fc_vport->port_name); - port_cfg.nwwn = wwn_to_u64((u8 *) &fc_vport->node_name); - + u64_to_wwn(fc_vport->node_name, (u8 *)&port_cfg.nwwn); + u64_to_wwn(fc_vport->port_name, (u8 *)&port_cfg.pwwn); if (strlen(vname) > 0) strcpy((char *)&port_cfg.sym_name, vname); - port_cfg.roles = BFA_PORT_ROLE_FCP_IM; - rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev); + spin_lock_irqsave(&bfad->bfad_lock, flags); + list_for_each_entry(pcfg, &bfad->pbc_pcfg_list, list_entry) { + if (port_cfg.pwwn == pcfg->port_cfg.pwwn) { + port_cfg.preboot_vp = pcfg->port_cfg.preboot_vp; + break; + } + } + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev); if (rc == BFA_STATUS_OK) { - struct bfad_vport_s *vport; + struct bfad_vport_s *vport; struct bfa_fcs_vport_s *fcs_vport; struct Scsi_Host *vshost; spin_lock_irqsave(&bfad->bfad_lock, flags); fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, port_cfg.pwwn); - if (fcs_vport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (fcs_vport == NULL) return VPCERR_BAD_WWN; - } fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); if (disable) { + spin_lock_irqsave(&bfad->bfad_lock, flags); bfa_fcs_vport_stop(fcs_vport); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); vport = fcs_vport->vport_drv; vshost = vport->drv_port.im_port->shost; - fc_host_node_name(vshost) = wwn_to_u64((u8 *) &port_cfg.nwwn); - fc_host_port_name(vshost) = wwn_to_u64((u8 *) &port_cfg.pwwn); + fc_host_node_name(vshost) = wwn_to_u64((u8 *)&port_cfg.nwwn); + fc_host_port_name(vshost) = wwn_to_u64((u8 *)&port_cfg.pwwn); fc_vport->dd_data = vport; vport->drv_port.im_port->fc_vport = fc_vport; - } else if (rc == BFA_STATUS_INVALID_WWN) return VPCERR_BAD_WWN; else if (rc == BFA_STATUS_VPORT_EXISTS) @@ -422,7 +428,7 @@ bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) return VPCERR_NO_FABRIC_SUPP; else if (rc == BFA_STATUS_VPORT_WWN_BP) return VPCERR_BAD_WWN; - else + else return FC_VPORT_FAILED; return status; @@ -449,7 +455,7 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) port = im_port->port; vshost = vport->drv_port.im_port->shost; - pwwn = wwn_to_u64((u8 *) &fc_host_port_name(vshost)); + u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn); spin_lock_irqsave(&bfad->bfad_lock, flags); fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); @@ -467,6 +473,9 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) rc = bfa_fcs_vport_delete(&vport->fcs_vport); spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (rc == BFA_STATUS_PBC) + return -1; + wait_for_completion(vport->comp_del); free_scsi_host: @@ -490,7 +499,7 @@ bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable) vport = (struct bfad_vport_s *)fc_vport->dd_data; bfad = vport->drv_port.bfad; vshost = vport->drv_port.im_port->shost; - pwwn = wwn_to_u64((u8 *) &fc_vport->port_name); + u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn); spin_lock_irqsave(&bfad->bfad_lock, flags); fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 6c920c1b53a..2b58b29fe30 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -120,6 +120,8 @@ struct bfad_vport_s { struct bfad_port_s drv_port; struct bfa_fcs_vport_s fcs_vport; struct completion *comp_del; + struct list_head list_entry; + struct bfa_port_cfg_s port_cfg; }; /* @@ -195,6 +197,12 @@ struct bfad_s { bfa_boolean_t ipfc_enabled; union bfad_tmp_buf tmp_buf; struct fc_host_statistics link_stats; + struct list_head pbc_pcfg_list; +}; + +struct bfad_pcfg_s { + struct list_head list_entry; + struct bfa_port_cfg_s port_cfg; }; /* diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 5b7cf539e50..0dff0d4b03c 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -567,6 +567,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, out_fc_rel: scsi_host_put(im_port->shost); + im_port->shost = NULL; out_free_idr: mutex_lock(&bfad_mutex); idr_remove(&bfad_im_port_index, im_port->idr_id); diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c index 8166e9745ec..9315383fff8 100644 --- a/drivers/scsi/bfa/fabric.c +++ b/drivers/scsi/bfa/fabric.c @@ -789,7 +789,7 @@ bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric) list_for_each_safe(qe, qen, &fabric->vport_q) { vport = (struct bfa_fcs_vport_s *)qe; - bfa_fcs_vport_delete(vport); + bfa_fcs_vport_fcs_delete(vport); } bfa_fcs_port_delete(&fabric->bport); diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h index 13c32ebf946..bb647a4a5dd 100644 --- a/drivers/scsi/bfa/fcs_vport.h +++ b/drivers/scsi/bfa/fcs_vport.h @@ -26,6 +26,7 @@ void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); +void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); #endif /* __FCS_VPORT_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h index 501bc9739d9..752a81293d5 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_port.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h @@ -50,12 +50,12 @@ enum bfa_port_role { * FCS port configuration. */ struct bfa_port_cfg_s { - wwn_t pwwn; /* port wwn */ - wwn_t nwwn; /* node wwn */ - struct bfa_port_symname_s sym_name; /* vm port symbolic name */ - enum bfa_port_role roles; /* FCS port roles */ - u32 rsvd; - u8 tag[16]; /* opaque tag from application */ + wwn_t pwwn; /* port wwn */ + wwn_t nwwn; /* node wwn */ + struct bfa_port_symname_s sym_name; /* vm port symbolic name */ + bfa_boolean_t preboot_vp; /* vport created from PBC */ + enum bfa_port_role roles; /* FCS port roles */ + u8 tag[16]; /* opaque tag from application */ }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h index ec78b4cb121..819db5abf46 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h @@ -213,7 +213,8 @@ enum bfa_status { * loaded */ BFA_STATUS_CARD_TYPE_MISMATCH = 131, /* Card type mismatch */ BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */ - BFA_STATUS_NO_DRIVER = 133, /* Brocade adapter/driver not installed or loaded */ + BFA_STATUS_NO_DRIVER = 133, /* Brocade adapter/driver not installed + * or loaded */ BFA_STATUS_INVALID_MAC = 134, /* Invalid mac address */ BFA_STATUS_IM_NO_VLAN = 135, /* No VLANs configured on the adapter */ BFA_STATUS_IM_ETH_LB_FAILED = 136, /* Ethernet loopback test failed */ @@ -249,6 +250,8 @@ enum bfa_status { BFA_STATUS_IM_TEAM_CFG_NOT_ALLOWED = 153, /* Given settings are not * allowed for the current * Teaming mode */ + BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot + * configuration */ BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h index a39f474c2fc..cfd6ba7c47e 100644 --- a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h +++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h @@ -40,7 +40,8 @@ struct bfad_vport_s; * * @return None */ -void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv); +void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv); +void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s); diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h index f2fd35fdee2..54e5b81ab2a 100644 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs.h +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h @@ -61,8 +61,8 @@ struct bfa_fcs_s { /* * bfa fcs API functions */ -void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, - bfa_boolean_t min_cfg); +void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, + struct bfad_s *bfad, bfa_boolean_t min_cfg); void bfa_fcs_init(struct bfa_fcs_s *fcs); void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, struct bfa_fcs_driver_info_s *driver_info); diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h index cd33f2cd5c3..0af26243086 100644 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h @@ -49,6 +49,10 @@ bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, u16 vf_id, struct bfa_port_cfg_s *port_cfg, struct bfad_vport_s *vport_drv); +bfa_status_t bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, + struct bfa_fcs_s *fcs, uint16_t vf_id, + struct bfa_port_cfg_s *port_cfg, + struct bfad_vport_s *vport_drv); bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport); bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport); bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport); diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c index 27cd619a227..f14e9f2d2c3 100644 --- a/drivers/scsi/bfa/vport.c +++ b/drivers/scsi/bfa/vport.c @@ -593,6 +593,15 @@ bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) vport->vport_stats.fab_cleanup++; } +/** + * delete notification from fabric SM. To be invoked from within FCS. + */ +void +bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport) +{ + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); +} + /** * Delete completion callback from associated lport */ @@ -646,6 +655,7 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, return BFA_STATUS_VPORT_MAX; vport->vport_drv = vport_drv; + vport_cfg->preboot_vp = BFA_FALSE; bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport); @@ -656,6 +666,36 @@ bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, return BFA_STATUS_OK; } +/** + * Use this function to instantiate a new FCS PBC vport object. This + * function will not trigger any HW initialization process (which will be + * done in vport_start() call) + * + * param[in] vport - pointer to bfa_fcs_vport_t. This space + * needs to be allocated by the driver. + * param[in] fcs - FCS instance + * param[in] vport_cfg - vport configuration + * param[in] vf_id - VF_ID if vport is created within a VF. + * FC_VF_ID_NULL to specify base fabric. + * param[in] vport_drv - Opaque handle back to the driver's vport + * structure + * + * retval BFA_STATUS_OK - on success. + * retval BFA_STATUS_FAILED - on failure. + */ +bfa_status_t +bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, + uint16_t vf_id, struct bfa_port_cfg_s *vport_cfg, + struct bfad_vport_s *vport_drv) +{ + bfa_status_t rc; + + rc = bfa_fcs_vport_create(vport, fcs, vf_id, vport_cfg, vport_drv); + vport->lport.port_cfg.preboot_vp = BFA_TRUE; + + return rc; +} + /** * Use this function initialize the vport. * @@ -692,6 +732,8 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) * Use this function to delete a vport object. Fabric object should * be stopped before this function call. * + * Donot invoke this from within FCS + * * param[in] vport - pointer to bfa_fcs_vport_t. * * return None @@ -699,6 +741,9 @@ bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport) { + if (vport->lport.port_cfg.preboot_vp) + return BFA_STATUS_PBC; + bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); return BFA_STATUS_OK; -- cgit v1.2.3-70-g09d2 From 1769f990fc182695bc215ce4369688064addcd1e Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:47:08 -0700 Subject: [SCSI] bfa: vport state machine fix Vport state machine does not cleanup associated lport in some states: while waiting for fdisc response or fdisc failure state. The fixe is to cleanup lport on vport delete in all states. In fdisc state, discard fdisc response and delete lport and wait for lport deletecompletion. in error state, delete lport and wait for delete completion. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/vport.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c index f14e9f2d2c3..66f30a0d61e 100644 --- a/drivers/scsi/bfa/vport.c +++ b/drivers/scsi/bfa/vport.c @@ -218,9 +218,9 @@ bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); bfa_lps_discard(vport->lps); - bfa_fcs_vport_do_logo(vport); + bfa_fcs_port_delete(&vport->lport); break; case BFA_FCS_VPORT_SM_OFFLINE: @@ -357,8 +357,9 @@ bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, switch (event) { case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_vport_free(vport); + bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); + bfa_fcs_port_delete(&vport->lport); + break; default: -- cgit v1.2.3-70-g09d2 From 15b64a835def4c784c6e62ad762677f5cb56eba2 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:48:12 -0700 Subject: [SCSI] bfa: ioc attributes fix This patch fixes the APIs to obtain ioc attributes - fix API to obtain wwpn, wwnn, and mac. - add API to get mfg wwpn, wwnn, and mac. - fix API to obtain wwn of boot target. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcport.c | 3 ++ drivers/scsi/bfa/bfa_ioc.c | 58 +++++++++++++++++----------------- drivers/scsi/bfa/bfa_ioc.h | 3 ++ drivers/scsi/bfa/bfa_iocfc.c | 18 ++++++++--- drivers/scsi/bfa/bfa_iocfc.h | 2 +- drivers/scsi/bfa/bfad_im.c | 8 ++--- drivers/scsi/bfa/fabric.c | 16 ++++++++++ drivers/scsi/bfa/fcs_fabric.h | 2 ++ drivers/scsi/bfa/include/bfi/bfi_ioc.h | 19 +++++++---- drivers/scsi/bfa/ns.c | 4 +-- 10 files changed, 86 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index 4961b8da912..d28b721acaf 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -1569,6 +1569,9 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr) attr->nwwn = fcport->nwwn; attr->pwwn = fcport->pwwn; + attr->factorypwwn = bfa_ioc_get_mfg_pwwn(&bfa->ioc); + attr->factorynwwn = bfa_ioc_get_mfg_nwwn(&bfa->ioc); + bfa_os_memcpy(&attr->pport_cfg, &fcport->cfg, sizeof(struct bfa_pport_cfg_s)); /* diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 268c071ce67..1600f747eb6 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -1838,54 +1838,54 @@ bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) } /** - * hal_wwn_public + * bfa_wwn_public */ wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc) { - union { - wwn_t wwn; - u8 byte[sizeof(wwn_t)]; - } - w; - - w.wwn = ioc->attr->mfg_wwn; - - if (bfa_ioc_portid(ioc) == 1) - w.byte[7]++; - - return w.wwn; + return ioc->attr->pwwn; } wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc) { - union { - wwn_t wwn; - u8 byte[sizeof(wwn_t)]; - } - w; - - w.wwn = ioc->attr->mfg_wwn; - - if (bfa_ioc_portid(ioc) == 1) - w.byte[7]++; - - w.byte[0] = 0x20; - - return w.wwn; + return ioc->attr->nwwn; } u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc) { - return ioc->attr->mfg_wwn; + return ioc->attr->mfg_pwwn; } mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc) { - mac_t mac; + /* + * Currently mfg mac is used as FCoE enode mac (not configured by PBC) + */ + if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE) + return bfa_ioc_get_mfg_mac(ioc); + else + return ioc->attr->mac; +} + +wwn_t +bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc) +{ + return ioc->attr->mfg_pwwn; +} + +wwn_t +bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc) +{ + return ioc->attr->mfg_nwwn; +} + +mac_t +bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc) +{ + mac_t mac; mac = ioc->attr->mfg_mac; mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc); diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index df15eccd760..2425c00a72d 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -304,6 +304,9 @@ bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc); wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc); mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc); +wwn_t bfa_ioc_get_mfg_pwwn(struct bfa_ioc_s *ioc); +wwn_t bfa_ioc_get_mfg_nwwn(struct bfa_ioc_s *ioc); +mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc); u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc); #endif /* __BFA_IOC_H__ */ diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index d3f1052744d..6f54bea356c 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -861,13 +861,23 @@ bfa_iocfc_is_operational(struct bfa_s *bfa) * Return boot target port wwns -- read from boot information in flash. */ void -bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns) +bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns) { - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + int i; + + if (cfgrsp->pbc_cfg.boot_enabled && cfgrsp->pbc_cfg.nbluns) { + bfa_trc(bfa, cfgrsp->pbc_cfg.nbluns); + *nwwns = cfgrsp->pbc_cfg.nbluns; + for (i = 0; i < cfgrsp->pbc_cfg.nbluns; i++) + wwns[i] = cfgrsp->pbc_cfg.blun[i].tgt_pwwn; + + return; + } *nwwns = cfgrsp->bootwwns.nwwns; - *wwns = cfgrsp->bootwwns.wwn; + memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(cfgrsp->bootwwns.wwn)); } void diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h index a08309fb981..2b281037fd7 100644 --- a/drivers/scsi/bfa/bfa_iocfc.h +++ b/drivers/scsi/bfa/bfa_iocfc.h @@ -167,7 +167,7 @@ void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len); void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi, bfa_boolean_t mincfg); -void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns); +void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns); void bfa_iocfc_get_pbc_boot_cfg(struct bfa_s *bfa, struct bfa_boot_pbc_s *pbcfg); int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 0dff0d4b03c..943bc4b3728 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -1205,9 +1205,9 @@ int bfad_os_get_linkup_delay(struct bfad_s *bfad) { - u8 nwwns = 0; - wwn_t *wwns; - int ldelay; + u8 nwwns = 0; + wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; + int ldelay; /* * Querying for the boot target port wwns @@ -1216,7 +1216,7 @@ bfad_os_get_linkup_delay(struct bfad_s *bfad) * else => local boot machine set bfa_linkup_delay = 10 */ - bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns); + bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns); if (nwwns > 0) { /* If boot over SAN; linkup_delay = 30sec */ diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c index 9315383fff8..c646d6dd789 100644 --- a/drivers/scsi/bfa/fabric.c +++ b/drivers/scsi/bfa/fabric.c @@ -1270,6 +1270,22 @@ bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, } +/** + * + * @param[in] fabric - fabric + * @param[in] node_symname - + * Caller allocated buffer to receive the symbolic name + * + * @return - none + */ +void +bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname) +{ + bfa_os_memcpy(node_symname, + fcs->fabric.bport.port_cfg.sym_name.symname, + BFA_SYMNAME_MAXLEN); +} + /** * Not used by FCS. */ diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h index 244c3f00c50..ed532db14e8 100644 --- a/drivers/scsi/bfa/fcs_fabric.h +++ b/drivers/scsi/bfa/fcs_fabric.h @@ -60,4 +60,6 @@ void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, wwn_t fabric_name); +void bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname); + #endif /* __FCS_FABRIC_H__ */ diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h index 03a9c9408ca..7c5e6d5716d 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h +++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h @@ -48,9 +48,14 @@ struct bfi_ioc_getattr_req_s { }; struct bfi_ioc_attr_s { - wwn_t mfg_wwn; + wwn_t mfg_pwwn; /* Mfg port wwn */ + wwn_t mfg_nwwn; /* Mfg node wwn */ mac_t mfg_mac; - u16 rsvd_a; + u16 rsvd_a; + wwn_t pwwn; + wwn_t nwwn; + mac_t mac; /* PBC or Mfg mac */ + u16 rsvd_b; char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; u8 pcie_gen; u8 pcie_lanes_orig; @@ -58,12 +63,12 @@ struct bfi_ioc_attr_s { u8 rx_bbcredit; /* receive buffer credits */ u32 adapter_prop; /* adapter properties */ u16 maxfrsize; /* max receive frame size */ - char asic_rev; - u8 rsvd_b; - char fw_version[BFA_VERSION_LEN]; - char optrom_version[BFA_VERSION_LEN]; + char asic_rev; + u8 rsvd_c; + char fw_version[BFA_VERSION_LEN]; + char optrom_version[BFA_VERSION_LEN]; struct bfa_mfg_vpd_s vpd; - uint32_t card_type; /* card type */ + u32 card_type; /* card type */ }; /** diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c index d20dd7e1574..2d6d2d6ff8d 100644 --- a/drivers/scsi/bfa/ns.c +++ b/drivers/scsi/bfa/ns.c @@ -1228,10 +1228,10 @@ bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port) struct bfa_fcs_rport_s *rport; u8 nwwns; - wwn_t *wwns; + wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; int ii; - bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns); + bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns); for (ii = 0; ii < nwwns; ++ii) { rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); -- cgit v1.2.3-70-g09d2 From b85d045ee866011df535565bf12d684e8e5b7a9d Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:48:49 -0700 Subject: [SCSI] bfa: statistics and typo fix - Added time stamp for fcport stats reset - Added new fileds to the statistics data structures. - Typo removal and minor cleanup. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcpim_priv.h | 1 + drivers/scsi/bfa/bfa_fcport.c | 25 +++++++++++++++++++++-- drivers/scsi/bfa/bfa_port.c | 27 +++++++++++++++++++++++-- drivers/scsi/bfa/bfa_port_priv.h | 3 ++- drivers/scsi/bfa/bfad_drv.h | 13 ------------ drivers/scsi/bfa/fcpim.c | 1 + drivers/scsi/bfa/include/bfa.h | 2 ++ drivers/scsi/bfa/include/cna/port/bfa_port.h | 1 + drivers/scsi/bfa/include/defs/bfa_defs_auth.h | 6 +++--- drivers/scsi/bfa/include/defs/bfa_defs_fcport.h | 26 +++++++++--------------- drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h | 12 +++++++---- drivers/scsi/bfa/include/defs/bfa_defs_itnim.h | 10 +++++++++ drivers/scsi/bfa/include/defs/bfa_defs_port.h | 2 +- drivers/scsi/bfa/include/defs/bfa_defs_pport.h | 4 ++-- drivers/scsi/bfa/include/defs/bfa_defs_status.h | 24 ++++++++++++---------- drivers/scsi/bfa/ms.c | 3 +++ 16 files changed, 105 insertions(+), 55 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h index 5cf418460f7..3db39da7242 100644 --- a/drivers/scsi/bfa/bfa_fcpim_priv.h +++ b/drivers/scsi/bfa/bfa_fcpim_priv.h @@ -141,6 +141,7 @@ struct bfa_itnim_s { struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ struct bfa_fcpim_mod_s *fcpim; /* fcpim module */ struct bfa_itnim_hal_stats_s stats; + struct bfa_itnim_latency_s io_latency; }; #define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index d28b721acaf..18d33072bec 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -888,6 +888,7 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); struct bfa_pport_cfg_s *port_cfg = &fcport->cfg; struct bfa_fcport_ln_s *ln = &fcport->ln; + struct bfa_timeval_s tv; bfa_os_memset(fcport, 0, sizeof(struct bfa_fcport_s)); fcport->bfa = bfa; @@ -898,6 +899,12 @@ bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, bfa_sm_set_state(fcport, bfa_fcport_sm_uninit); bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); + /** + * initialize time stamp for stats reset + */ + bfa_os_gettimeofday(&tv); + fcport->stats_reset_time = tv.tv_sec; + /** * initialize and set default configuration */ @@ -1126,16 +1133,22 @@ __bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete) if (complete) { if (fcport->stats_status == BFA_STATUS_OK) { + struct bfa_timeval_s tv; /* Swap FC QoS or FCoE stats */ - if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) + if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { bfa_fcport_qos_stats_swap( &fcport->stats_ret->fcqos, &fcport->stats->fcqos); - else + } else { bfa_fcport_fcoe_stats_swap( &fcport->stats_ret->fcoe, &fcport->stats->fcoe); + + bfa_os_gettimeofday(&tv); + fcport->stats_ret->fcoe.secs_reset = + tv.tv_sec - fcport->stats_reset_time; + } } fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status); } else { @@ -1191,6 +1204,14 @@ __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete) struct bfa_fcport_s *fcport = cbarg; if (complete) { + struct bfa_timeval_s tv; + + /** + * re-initialize time stamp for stats reset + */ + bfa_os_gettimeofday(&tv); + fcport->stats_reset_time = tv.tv_sec; + fcport->stats_cbfn(fcport->stats_cbarg, fcport->stats_status); } else { fcport->stats_busy = BFA_FALSE; diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c index cab19028361..6773e2282dd 100644 --- a/drivers/scsi/bfa/bfa_port.c +++ b/drivers/scsi/bfa/bfa_port.c @@ -102,9 +102,14 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) port->stats_busy = BFA_FALSE; if (status == BFA_STATUS_OK) { + struct bfa_timeval_s tv; + memcpy(port->stats, port->stats_dma.kva, sizeof(union bfa_pport_stats_u)); bfa_port_stats_swap(port, port->stats); + + bfa_os_gettimeofday(&tv); + port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time; } if (port->stats_cbfn) { @@ -125,9 +130,17 @@ bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) static void bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) { + struct bfa_timeval_s tv; + port->stats_status = status; port->stats_busy = BFA_FALSE; + /** + * re-initialize time stamp for stats reset + */ + bfa_os_gettimeofday(&tv); + port->stats_reset_time = tv.tv_sec; + if (port->stats_cbfn) { port->stats_cbfn(port->stats_cbarg, status); port->stats_cbfn = NULL; @@ -428,6 +441,8 @@ void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod) { + struct bfa_timeval_s tv; + bfa_assert(port); port->dev = dev; @@ -435,13 +450,21 @@ bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev, port->trcmod = trcmod; port->logmod = logmod; - port->stats_busy = port->endis_pending = BFA_FALSE; - port->stats_cbfn = port->endis_cbfn = NULL; + port->stats_busy = BFA_FALSE; + port->endis_pending = BFA_FALSE; + port->stats_cbfn = NULL; + port->endis_cbfn = NULL; bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port); bfa_ioc_hbfail_register(port->ioc, &port->hbfail); + /** + * initialize time stamp for stats reset + */ + bfa_os_gettimeofday(&tv); + port->stats_reset_time = tv.tv_sec; + bfa_trc(port, 0); } diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h index c52fe56df0b..c9ebe0426fa 100644 --- a/drivers/scsi/bfa/bfa_port_priv.h +++ b/drivers/scsi/bfa/bfa_port_priv.h @@ -75,8 +75,9 @@ struct bfa_fcport_s { bfa_status_t stats_status; /* stats/statsclr status */ bfa_boolean_t stats_busy; /* outstanding stats/statsclr */ bfa_boolean_t stats_qfull; + u32 stats_reset_time; /* stats reset time stamp */ bfa_cb_pport_t stats_cbfn; /* driver callback function */ - void *stats_cbarg; /* *!< user callback arg */ + void *stats_cbarg; /* user callback arg */ bfa_boolean_t diag_busy; /* diag busy status */ bfa_boolean_t beacon; /* port beacon status */ bfa_boolean_t link_e2e_beacon; /* link beacon status */ diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 2b58b29fe30..8629f64a528 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -141,18 +141,6 @@ struct bfad_cfg_param_s { u32 binding_method; }; -union bfad_tmp_buf { - /* From struct bfa_adapter_attr_s */ - char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char fw_ver[BFA_VERSION_LEN]; - char optrom_ver[BFA_VERSION_LEN]; - - /* From struct bfa_ioc_pci_attr_s */ - u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */ -}; - /* * BFAD (PCI function) data structure */ @@ -195,7 +183,6 @@ struct bfad_s { struct bfa_plog_s plog_buf; int ref_count; bfa_boolean_t ipfc_enabled; - union bfad_tmp_buf tmp_buf; struct fc_host_statistics link_stats; struct list_head pbc_pcfg_list; }; diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c index 8ae4a2cfa85..412018196bd 100644 --- a/drivers/scsi/bfa/fcpim.c +++ b/drivers/scsi/bfa/fcpim.c @@ -738,6 +738,7 @@ bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn, attr->rec_support = itnim->rec_support; attr->conf_comp = itnim->conf_comp; attr->task_retry_id = itnim->task_retry_id; + bfa_os_memset(&attr->io_latency, 0, sizeof(struct bfa_itnim_latency_s)); return BFA_STATUS_OK; } diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h index 1f5966cfbd1..9519a6d8104 100644 --- a/drivers/scsi/bfa/include/bfa.h +++ b/drivers/scsi/bfa/include/bfa.h @@ -126,6 +126,8 @@ struct bfa_sge_s { bfa_ioc_get_type(&(__bfa)->ioc) #define bfa_get_mac(__bfa) \ bfa_ioc_get_mac(&(__bfa)->ioc) +#define bfa_get_fw_clock_res(__bfa) \ + ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res) /* * bfa API functions diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h index 7cbf17d3141..d7babaf9784 100644 --- a/drivers/scsi/bfa/include/cna/port/bfa_port.h +++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h @@ -37,6 +37,7 @@ struct bfa_port_s { bfa_port_stats_cbfn_t stats_cbfn; void *stats_cbarg; bfa_status_t stats_status; + u32 stats_reset_time; union bfa_pport_stats_u *stats; struct bfa_dma_s stats_dma; bfa_boolean_t endis_pending; diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h index 45df3282091..f56ed871bb9 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h @@ -125,10 +125,10 @@ struct bfa_auth_attr_s { enum bfa_auth_status status; enum bfa_auth_algo algo; enum bfa_auth_group dh_grp; - u16 rjt_code; - u16 rjt_code_exp; + enum bfa_auth_rej_code rjt_code; + enum bfa_auth_rej_code_exp rjt_code_exp; u8 secret_set; - u8 resv[7]; + u8 resv[3]; }; #endif /* __BFA_DEFS_AUTH_H__ */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h index a07ef4a3cd7..af86a639643 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcport.h @@ -48,7 +48,7 @@ struct bfa_fcoe_stats_s { u64 disc_fcf_unavail; /* Discovery FCF not avail */ u64 linksvc_unsupp; /* FIP link service req unsupp. */ u64 linksvc_err; /* FIP link service req errors */ - u64 logo_req; /* FIP logo */ + u64 logo_req; /* FIP logos received */ u64 clrvlink_req; /* Clear virtual link requests */ u64 op_unsupp; /* FIP operation unsupp. */ u64 untagged; /* FIP untagged frames */ @@ -64,21 +64,15 @@ struct bfa_fcoe_stats_s { u64 txf_timeout; /* Tx timeouts */ u64 txf_parity_errors; /* Transmit parity err */ u64 txf_fid_parity_errors; /* Transmit FID parity err */ - u64 tx_pause; /* Tx pause frames */ - u64 tx_zero_pause; /* Tx zero pause frames */ - u64 tx_first_pause; /* Tx first pause frames */ - u64 rx_pause; /* Rx pause frames */ - u64 rx_zero_pause; /* Rx zero pause frames */ - u64 rx_first_pause; /* Rx first pause frames */ - u64 rxf_ucast_octets; /* Rx unicast octets */ - u64 rxf_ucast; /* Rx unicast frames */ - u64 rxf_ucast_vlan; /* Rx unicast vlan frames */ - u64 rxf_mcast_octets; /* Rx multicast octets */ - u64 rxf_mcast; /* Rx multicast frames */ - u64 rxf_mcast_vlan; /* Rx multicast vlan frames */ - u64 rxf_bcast_octets; /* Rx broadcast octests */ - u64 rxf_bcast; /* Rx broadcast frames */ - u64 rxf_bcast_vlan; /* Rx broadcast vlan frames */ + u64 rxf_ucast_octets; /* Rx FCoE unicast octets */ + u64 rxf_ucast; /* Rx FCoE unicast frames */ + u64 rxf_ucast_vlan; /* Rx FCoE unicast vlan frames */ + u64 rxf_mcast_octets; /* Rx FCoE multicast octets */ + u64 rxf_mcast; /* Rx FCoE multicast frames */ + u64 rxf_mcast_vlan; /* Rx FCoE multicast vlan frames */ + u64 rxf_bcast_octets; /* Rx FCoE broadcast octets */ + u64 rxf_bcast; /* Rx FCoE broadcast frames */ + u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */ }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h index c290fb13d2d..31e728a631e 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h @@ -51,8 +51,10 @@ struct bfa_iocfc_fwcfg_s { u16 num_tsktm_reqs; /* TM task management requests*/ u16 num_fcxp_reqs; /* unassisted FC exchanges */ u16 num_uf_bufs; /* unsolicited recv buffers */ - u8 num_cqs; - u8 rsvd[5]; + u8 num_cqs; + u8 fw_tick_res; /*!< FW clock resolution in ms */ + u8 rsvd[4]; + }; struct bfa_iocfc_drvcfg_s { @@ -176,10 +178,10 @@ struct bfa_fw_port_fpg_stats_s { u32 nos_rx; u32 lip_rx; u32 arbf0_rx; + u32 arb_rx; u32 mrk_rx; u32 const_mrk_rx; u32 prim_unknown; - u32 rsvd; }; @@ -200,6 +202,8 @@ struct bfa_fw_port_lksm_stats_s { u32 lrr_tx; /* No. of times LRR tx started */ u32 ols_tx; /* No. of times OLS tx started */ u32 nos_tx; /* No. of times NOS tx started */ + u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ + u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ }; @@ -239,7 +243,7 @@ struct bfa_fw_fip_stats_s { u32 disc_fcf_unavail; /* Discovery FCF Not Avail. */ u32 linksvc_unsupp; /* Unsupported link service req */ u32 linksvc_err; /* Parse error in link service req */ - u32 logo_req; /* Number of FIP logos received */ + u32 logo_req; /* FIP logos received */ u32 clrvlink_req; /* Clear virtual link req */ u32 op_unsupp; /* Unsupported FIP operation */ u32 untagged; /* Untagged frames (ignored) */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h index 2ec769903d2..d77788b3999 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h @@ -34,6 +34,15 @@ enum bfa_itnim_state { BFA_ITNIM_INITIATIOR = 7, /* initiator */ }; +struct bfa_itnim_latency_s { + u32 min; + u32 max; + u32 count; + u32 clock_res; + u32 avg; + u32 rsvd; +}; + struct bfa_itnim_hal_stats_s { u32 onlines; /* ITN nexus onlines (PRLI done) */ u32 offlines; /* ITN Nexus offlines */ @@ -91,6 +100,7 @@ struct bfa_itnim_attr_s { u8 task_retry_id; /* task retry ident support */ u8 rec_support; /* REC supported */ u8 conf_comp; /* confirmed completion supp */ + struct bfa_itnim_latency_s io_latency; /* IO latency */ }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h index 752a81293d5..ebdf0d1731a 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_port.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h @@ -159,7 +159,7 @@ struct bfa_port_stats_s { u32 ms_plogi_rsp_err; u32 ms_plogi_acc_err; u32 ms_plogi_accepts; - u32 ms_rejects; /* NS command rejects */ + u32 ms_rejects; /* MS command rejects */ u32 ms_plogi_unknown_rsp; u32 ms_plogi_alloc_wait; diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h index de6181cf967..2c2cec5ee27 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h @@ -246,7 +246,7 @@ struct bfa_pport_fc_stats_s { u64 secs_reset; /* Seconds since stats is reset */ u64 tx_frames; /* Tx frames */ u64 tx_words; /* Tx words */ - u64 tx_lip; /* TX LIP */ + u64 tx_lip; /* Tx LIP */ u64 tx_nos; /* Tx NOS */ u64 tx_ols; /* Tx OLS */ u64 tx_lr; /* Tx LR */ @@ -312,7 +312,7 @@ struct bfa_pport_eth_stats_s { u64 rx_zero_pause; /* Rx zero pause */ u64 tx_pause; /* Tx pause */ u64 tx_zero_pause; /* Tx zero pause */ - u64 rx_fcoe_pause; /* Rx fcoe pause */ + u64 rx_fcoe_pause; /* Rx FCoE pause */ u64 rx_fcoe_zero_pause; /* Rx FCoE zero pause */ u64 tx_fcoe_pause; /* Tx FCoE pause */ u64 tx_fcoe_zero_pause; /* Tx FCoE zero pause */ diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h index 819db5abf46..7cef900707c 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h @@ -84,8 +84,9 @@ enum bfa_status { BFA_STATUS_BADFRMHDR = 48, /* Bad frame header */ BFA_STATUS_BADFRMSZ = 49, /* Bad frame size check and replace * SFP/cable */ - BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace - * SFP/cable */ + BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace + * SFP/cable or for Mezz card check and + * replace pass through module */ BFA_STATUS_LINKTIMEOUT = 51, /* Link timeout check and replace * SFP/cable */ BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the @@ -173,7 +174,7 @@ enum bfa_status { BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ BFA_STATUS_CEE_NOT_DN = 110, /* eth port is not at down state, please * bring down first */ - BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G HBA */ + BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G CNA */ BFA_STATUS_IM_INV_TEAM_NAME = 112, /* Invalid team name */ BFA_STATUS_IM_DUP_TEAM_NAME = 113, /* Given team name already * exists */ @@ -215,11 +216,11 @@ enum bfa_status { BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */ BFA_STATUS_NO_DRIVER = 133, /* Brocade adapter/driver not installed * or loaded */ - BFA_STATUS_INVALID_MAC = 134, /* Invalid mac address */ + BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ BFA_STATUS_IM_NO_VLAN = 135, /* No VLANs configured on the adapter */ BFA_STATUS_IM_ETH_LB_FAILED = 136, /* Ethernet loopback test failed */ - BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port vlan (PVID) */ - BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port vlan (PVID) */ + BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port VLAN (PVID) */ + BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port VLAN (PVID) */ BFA_STATUS_CNA_NO_BOOT = 139, /* Boot upload not allowed for CNA */ BFA_STATUS_IM_PVID_NON_ZERO = 140, /* Port VLAN ID (PVID) is Set to * Non-Zero Value */ @@ -233,14 +234,15 @@ enum bfa_status { BFA_STATUS_INSUFFICIENT_PERMS = 144, /* User doesn't have sufficient * permissions to execute the BCU * application */ - BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved Vlan name + BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved VLAN name * string. The name is not allowed - * for the normal Vlans */ + * for the normal VLAN */ BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */ - BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthru vlan id */ - BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation + BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthrough VLAN + * id */ + BFA_STATUS_IM_BIND_FAILED = 148, /* IM Driver bind operation * failed */ - BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation + BFA_STATUS_IM_UNBIND_FAILED = 149, /* IM Driver unbind operation * failed */ BFA_STATUS_IM_PORT_IN_TEAM = 150, /* Port is already part of the * team */ diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c index 5e8c8dee6c9..e776bcb4960 100644 --- a/drivers/scsi/bfa/ms.c +++ b/drivers/scsi/bfa/ms.c @@ -157,6 +157,7 @@ bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) * Start timer for a delayed retry */ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry); + ms->port->stats.ms_retries++; bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer, bfa_fcs_port_ms_timeout, ms, BFA_FCS_RETRY_TIMEOUT); @@ -279,6 +280,7 @@ bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) */ if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry); + ms->port->stats.ms_retries++; bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer, bfa_fcs_port_ms_timeout, ms, BFA_FCS_RETRY_TIMEOUT); @@ -479,6 +481,7 @@ bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event) */ if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry); + ms->port->stats.ms_retries++; bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer, bfa_fcs_port_ms_timeout, ms, BFA_FCS_RETRY_TIMEOUT); -- cgit v1.2.3-70-g09d2 From 4f1806bc3c409395de4dab5984f7a235dc4a0eda Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:50:15 -0700 Subject: [SCSI] bfa: use standards defined timeout for ELS/CT Use standards defined 2 * RA_TOV as a timeout for ELS Request retries. And standards defined 3 * RA_TOV as a timeout for FC-CT Request retries. Also, added a check to send RPSC2 to a Brocade Fabric only. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/fabric.c | 26 ++++++++++++++++++++++++++ drivers/scsi/bfa/fcpim.c | 2 +- drivers/scsi/bfa/fcs_fabric.h | 3 +++ drivers/scsi/bfa/fdmi.c | 6 +++--- drivers/scsi/bfa/include/protocol/fc.h | 1 + drivers/scsi/bfa/ms.c | 6 +++--- drivers/scsi/bfa/ns.c | 10 +++++----- drivers/scsi/bfa/rport.c | 8 ++++---- drivers/scsi/bfa/rport_ftrs.c | 13 +++++++++---- drivers/scsi/bfa/scn.c | 2 +- 10 files changed, 56 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c index c646d6dd789..ddd4ba9317e 100644 --- a/drivers/scsi/bfa/fabric.c +++ b/drivers/scsi/bfa/fabric.c @@ -1027,6 +1027,32 @@ bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric) return fabric->num_vports; } +/* + * Get OUI of the attached switch. + * + * Note : Use of this function should be avoided as much as possible. + * This function should be used only if there is any requirement + * to check for FOS version below 6.3. + * To check if the attached fabric is a brocade fabric, use + * bfa_lps_is_brcd_fabric() which works for FOS versions 6.3 + * or above only. + */ + +u16 +bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric) +{ + wwn_t fab_nwwn; + u8 *tmp; + u16 oui; + + fab_nwwn = bfa_lps_get_peer_nwwn(fabric->lps); + + tmp = (uint8_t *)&fab_nwwn; + oui = (tmp[3] << 8) | tmp[4]; + + return oui; +} + /** * Unsolicited frame receive handling. */ diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c index 412018196bd..7a0207e5669 100644 --- a/drivers/scsi/bfa/fcpim.c +++ b/drivers/scsi/bfa/fcpim.c @@ -422,7 +422,7 @@ bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ, - FC_RA_TOV); + FC_ELS_TOV); itnim->stats.prli_sent++; bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT); diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h index ed532db14e8..432ab8ab8c3 100644 --- a/drivers/scsi/bfa/fcs_fabric.h +++ b/drivers/scsi/bfa/fcs_fabric.h @@ -26,6 +26,8 @@ #include #include +#define BFA_FCS_BRCD_SWITCH_OUI 0x051e + /* * fcs friend functions: only between fcs modules */ @@ -60,6 +62,7 @@ void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, wwn_t fabric_name); +u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); void bfa_fcs_get_sym_name(const struct bfa_fcs_s *fcs, char *node_symname); #endif /* __FCS_FABRIC_H__ */ diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c index 8f17076d1a8..2b50eabf4b1 100644 --- a/drivers/scsi/bfa/fdmi.c +++ b/drivers/scsi/bfa/fdmi.c @@ -532,7 +532,7 @@ bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, (len + attr_len), &fchs, bfa_fcs_port_fdmi_rhba_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_RA_TOV); + FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT); } @@ -823,7 +823,7 @@ bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len + attr_len, &fchs, bfa_fcs_port_fdmi_rprt_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_RA_TOV); + FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT); } @@ -1043,7 +1043,7 @@ bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len + attr_len, &fchs, bfa_fcs_port_fdmi_rpa_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_RA_TOV); + FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT); } diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h index 8d1038035a7..436dd7c5643 100644 --- a/drivers/scsi/bfa/include/protocol/fc.h +++ b/drivers/scsi/bfa/include/protocol/fc.h @@ -1080,6 +1080,7 @@ struct fc_alpabm_s{ #define FC_REC_TOV (FC_ED_TOV + 1) #define FC_RA_TOV 10 #define FC_ELS_TOV (2 * FC_RA_TOV) +#define FC_FCCT_TOV (3 * FC_RA_TOV) /* * virtual fabric related defines diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c index e776bcb4960..1d579ef2612 100644 --- a/drivers/scsi/bfa/ms.c +++ b/drivers/scsi/bfa/ms.c @@ -361,7 +361,7 @@ bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response, - (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); } @@ -560,7 +560,7 @@ bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response, - (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ms, FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); } @@ -640,7 +640,7 @@ bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_plogi_response, - (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ms, FC_MAX_PDUSZ, FC_ELS_TOV); port->stats.ms_plogi_sent++; bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c index 2d6d2d6ff8d..ae0edcc86ed 100644 --- a/drivers/scsi/bfa/ns.c +++ b/drivers/scsi/bfa/ns.c @@ -664,7 +664,7 @@ bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_plogi_response, - (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ns, FC_MAX_PDUSZ, FC_ELS_TOV); port->stats.ns_plogi_sent++; bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); @@ -791,7 +791,7 @@ bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); port->stats.ns_rspnid_sent++; @@ -865,7 +865,7 @@ bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); port->stats.ns_rftid_sent++; bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); @@ -943,7 +943,7 @@ bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response, - (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)ns, FC_MAX_PDUSZ, FC_FCCT_TOV); port->stats.ns_rffid_sent++; bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); @@ -1029,7 +1029,7 @@ bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response, (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa), - FC_RA_TOV); + FC_FCCT_TOV); port->stats.ns_gidft_sent++; diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c index 7b096f2e383..2796403222e 100644 --- a/drivers/scsi/bfa/rport.c +++ b/drivers/scsi/bfa/rport.c @@ -1378,7 +1378,7 @@ bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, - (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.plogis++; bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); @@ -1519,7 +1519,7 @@ bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response, - rport, FC_MAX_PDUSZ, FC_RA_TOV); + rport, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.adisc_sent++; bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); @@ -1580,7 +1580,7 @@ bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response, - (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)rport, FC_MAX_PDUSZ, FC_FCCT_TOV); bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); } @@ -1692,7 +1692,7 @@ bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ, - FC_ED_TOV); + FC_ELS_TOV); rport->stats.logos++; bfa_fcxp_discard(rport->fcxp); diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c index ae7bba67ae2..acecab83f82 100644 --- a/drivers/scsi/bfa/rport_ftrs.c +++ b/drivers/scsi/bfa/rport_ftrs.c @@ -73,6 +73,7 @@ static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) { struct bfa_fcs_rport_s *rport = rpf->rport; + struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric; bfa_trc(rport->fcs, rport->pwwn); bfa_trc(rport->fcs, rport->pid); @@ -80,12 +81,16 @@ bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) switch (event) { case RPFSM_EVENT_RPORT_ONLINE: - if (!BFA_FCS_PID_IS_WKA(rport->pid)) { + /* Send RPSC2 to a Brocade fabric only. */ + if ((!BFA_FCS_PID_IS_WKA(rport->pid)) && + ((bfa_lps_is_brcd_fabric(rport->port->fabric->lps)) || + (bfa_fcs_fabric_get_switch_oui(fabric) == + BFA_FCS_BRCD_SWITCH_OUI))) { bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); rpf->rpsc_retries = 0; bfa_fcs_rpf_send_rpsc2(rpf, NULL); - break; - }; + } + break; case RPFSM_EVENT_RPORT_OFFLINE: break; @@ -307,7 +312,7 @@ bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response, - rpf, FC_MAX_PDUSZ, FC_RA_TOV); + rpf, FC_MAX_PDUSZ, FC_ELS_TOV); rport->stats.rpsc_sent++; bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT); diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c index 8fe09ba88a9..8a60129e630 100644 --- a/drivers/scsi/bfa/scn.c +++ b/drivers/scsi/bfa/scn.c @@ -218,7 +218,7 @@ bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced) bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response, - (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV); + (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV); bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT); } -- cgit v1.2.3-70-g09d2 From 7c8146510c9cacdaaeb273b5fef6b9201d933bc1 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:50:38 -0700 Subject: [SCSI] bfa: fix interrupt coalescing setting Do not update the coalesce flag of the intr_attr struct in driver config area on config response. This is to prevent the coalesce flag being reported as on after an ioc disable/enable even if it was set to off before disable. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_iocfc.c | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index 6f54bea356c..0776d74d40d 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -113,7 +113,6 @@ bfa_iocfc_send_cfg(void *bfa_arg) bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS); bfa_trc(bfa, cfg->fwcfg.num_cqs); - iocfc->cfgdone = BFA_FALSE; bfa_iocfc_reset_queues(bfa); /** @@ -144,6 +143,15 @@ bfa_iocfc_send_cfg(void *bfa_arg) bfa_os_htons(cfg->drvcfg.num_rspq_elems); } + /** + * Enable interrupt coalescing if it is driver init path + * and not ioc disable/enable path. + */ + if (!iocfc->cfgdone) + cfg_info->intr_attr.coalesce = BFA_TRUE; + + iocfc->cfgdone = BFA_FALSE; + /** * dma map IOC configuration itself */ @@ -364,7 +372,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) struct bfa_iocfc_s *iocfc = &bfa->iocfc; struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; - struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo; fwcfg->num_cqs = fwcfg->num_cqs; fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs); @@ -373,10 +380,6 @@ bfa_iocfc_cfgrsp(struct bfa_s *bfa) fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs); fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports); - cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce; - cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay); - cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency); - iocfc->cfgdone = BFA_TRUE; /** @@ -737,10 +740,20 @@ bfa_adapter_get_id(struct bfa_s *bfa) void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) { - struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + + attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce; + + attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ? + bfa_os_ntohs(iocfc->cfginfo->intr_attr.delay) : + bfa_os_ntohs(iocfc->cfgrsp->intr_attr.delay); + + attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ? + bfa_os_ntohs(iocfc->cfginfo->intr_attr.latency) : + bfa_os_ntohs(iocfc->cfgrsp->intr_attr.latency); + + attr->config = iocfc->cfg; - attr->intr_attr = iocfc->cfginfo->intr_attr; - attr->config = iocfc->cfg; } bfa_status_t @@ -749,7 +762,10 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) struct bfa_iocfc_s *iocfc = &bfa->iocfc; struct bfi_iocfc_set_intr_req_s *m; - iocfc->cfginfo->intr_attr = *attr; + iocfc->cfginfo->intr_attr.coalesce = attr->coalesce; + iocfc->cfginfo->intr_attr.delay = bfa_os_htons(attr->delay); + iocfc->cfginfo->intr_attr.latency = bfa_os_htons(attr->latency); + if (!bfa_iocfc_is_operational(bfa)) return BFA_STATUS_OK; @@ -759,9 +775,10 @@ bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, bfa_lpuid(bfa)); - m->coalesce = attr->coalesce; - m->delay = bfa_os_htons(attr->delay); - m->latency = bfa_os_htons(attr->latency); + m->coalesce = iocfc->cfginfo->intr_attr.coalesce; + m->delay = iocfc->cfginfo->intr_attr.delay; + m->latency = iocfc->cfginfo->intr_attr.latency; + bfa_trc(bfa, attr->delay); bfa_trc(bfa, attr->latency); -- cgit v1.2.3-70-g09d2 From c507341713114e2510ad7621088b359367adf1ce Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:51:28 -0700 Subject: [SCSI] bfa: fix rport speed setting When a rport goes offline, its speed setting was not reset. Subsequently, if the rport was not deleted due to it coming back online within rport del timeout, previously discovered speed would continue to show up. The fix is to reset the speed when processing rport offline transition. In rport attributes, rport's with unknown speed were indicated as TRL enforced. The right thing do to would be to use TRL default speed to determine if TRL is enforced, when TRL is enabled. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/lport_api.c | 30 +++++++++++++++++++++--------- drivers/scsi/bfa/rport_api.c | 11 ++++++++--- drivers/scsi/bfa/rport_ftrs.c | 1 + 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c index d3907d184e2..72b3f508d0e 100644 --- a/drivers/scsi/bfa/lport_api.c +++ b/drivers/scsi/bfa/lport_api.c @@ -137,6 +137,8 @@ bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[], /* * Iterate's through all the rport's in the given port to * determine the maximum operating speed. + * + * To be used in TRL Functionality only */ enum bfa_pport_speed bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) @@ -146,7 +148,8 @@ bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) struct bfa_fcs_s *fcs; enum bfa_pport_speed max_speed = 0; struct bfa_pport_attr_s pport_attr; - enum bfa_pport_speed pport_speed; + enum bfa_pport_speed pport_speed, rport_speed; + bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa); if (port == NULL) return 0; @@ -164,19 +167,28 @@ bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port) qe = bfa_q_first(qh); while (qe != qh) { - rport = (struct bfa_fcs_rport_s *)qe; - if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) - || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) { + rport = (struct bfa_fcs_rport_s *) qe; + if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000) || + (bfa_fcs_rport_get_state(rport) == + BFA_RPORT_OFFLINE)) { qe = bfa_q_next(qe); continue; } - if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS) - || (rport->rpf.rpsc_speed > pport_speed)) { - max_speed = rport->rpf.rpsc_speed; + rport_speed = rport->rpf.rpsc_speed; + if ((trl_enabled) && (rport_speed == + BFA_PPORT_SPEED_UNKNOWN)) { + /* Use default ratelim speed setting */ + rport_speed = + bfa_fcport_get_ratelim_speed(port->fcs->bfa); + } + + if ((rport_speed == BFA_PPORT_SPEED_8GBPS) || + (rport_speed > pport_speed)) { + max_speed = rport_speed; break; - } else if (rport->rpf.rpsc_speed > max_speed) { - max_speed = rport->rpf.rpsc_speed; + } else if (rport_speed > max_speed) { + max_speed = rport_speed; } qe = bfa_q_next(qe); diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c index a441f41d2a6..15e0c470afd 100644 --- a/drivers/scsi/bfa/rport_api.c +++ b/drivers/scsi/bfa/rport_api.c @@ -83,6 +83,7 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, { struct bfa_rport_qos_attr_s qos_attr; struct bfa_fcs_port_s *port = rport->port; + enum bfa_pport_speed rport_speed = rport->rpf.rpsc_speed; bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); @@ -102,10 +103,14 @@ bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, rport_attr->qos_attr = qos_attr; rport_attr->trl_enforced = BFA_FALSE; + if (bfa_fcport_is_ratelim(port->fcs->bfa)) { - if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) || - (rport->rpf.rpsc_speed < - bfa_fcs_port_get_rport_max_speed(port))) + if (rport_speed == BFA_PPORT_SPEED_UNKNOWN) { + /* Use default ratelim speed setting */ + rport_speed = + bfa_fcport_get_ratelim_speed(rport->fcs->bfa); + } + if (rport_speed < bfa_fcs_port_get_rport_max_speed(port)) rport_attr->trl_enforced = BFA_TRUE; } diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c index acecab83f82..f2a9361ce9a 100644 --- a/drivers/scsi/bfa/rport_ftrs.c +++ b/drivers/scsi/bfa/rport_ftrs.c @@ -274,6 +274,7 @@ void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport) if (__fcs_min_cfg(rport->port->fcs)) return; + rport->rpf.rpsc_speed = 0; bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE); } -- cgit v1.2.3-70-g09d2 From 41188cf5a60a24bf54df5be70142f0928f413788 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:52:00 -0700 Subject: [SCSI] bfa: fix prli retry issues Add a max retry limit for PRLI retries. Max retry limit (5) is same as used in rport PLOGI. Once the retries are exhausted, invoke rport offline so that existing logic of rport re-discovery can kick-in. Also fixed a bug in rport.c where one less retry was happening. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/fcpim.c | 13 +++++++++++-- drivers/scsi/bfa/fcs_rport.h | 2 ++ drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h | 1 + drivers/scsi/bfa/rport.c | 4 +--- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c index 7a0207e5669..d090f7a6368 100644 --- a/drivers/scsi/bfa/fcpim.c +++ b/drivers/scsi/bfa/fcpim.c @@ -110,6 +110,7 @@ bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, switch (event) { case BFA_FCS_ITNIM_SM_ONLINE: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); + itnim->prli_retries = 0; bfa_fcs_itnim_send_prli(itnim, NULL); break; @@ -218,8 +219,16 @@ bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, switch (event) { case BFA_FCS_ITNIM_SM_TIMEOUT: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); - bfa_fcs_itnim_send_prli(itnim, NULL); + if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) { + itnim->prli_retries++; + bfa_trc(itnim->fcs, itnim->prli_retries); + bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); + bfa_fcs_itnim_send_prli(itnim, NULL); + } else { + /* invoke target offline */ + bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); + bfa_fcs_rport_logo_imp(itnim->rport); + } break; case BFA_FCS_ITNIM_SM_OFFLINE: diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h index 9c8d1d29238..5242ee0f03c 100644 --- a/drivers/scsi/bfa/fcs_rport.h +++ b/drivers/scsi/bfa/fcs_rport.h @@ -24,6 +24,8 @@ #include +#define BFA_FCS_RPORT_MAX_RETRIES (5) + void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, u16 len); void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport); diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h index e719f2c3eb3..9a35ecf5cdf 100644 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h @@ -41,6 +41,7 @@ struct bfa_fcs_itnim_s { struct bfa_fcs_s *fcs; /* fcs instance */ struct bfa_timer_s timer; /* timer functions */ struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */ + u32 prli_retries; /* max prli retry attempts */ bfa_boolean_t seq_rec; /* seq recovery support */ bfa_boolean_t rec_support; /* REC supported */ bfa_boolean_t conf_comp; /* FCP_CONF support */ diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c index 2796403222e..4e1fff21a5b 100644 --- a/drivers/scsi/bfa/rport.c +++ b/drivers/scsi/bfa/rport.c @@ -36,8 +36,6 @@ BFA_TRC_FILE(FCS, RPORT); -#define BFA_FCS_RPORT_MAX_RETRIES (5) - /* In millisecs */ static u32 bfa_fcs_rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000; @@ -356,8 +354,8 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, */ case RPSM_EVENT_TIMEOUT: - rport->plogi_retries++; if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) { + rport->plogi_retries++; bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); bfa_fcs_rport_send_plogi(rport, NULL); } else { -- cgit v1.2.3-70-g09d2 From 3e98cc013fc4902df5f9d9defe1856df0f0cb657 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:52:46 -0700 Subject: [SCSI] bfa: add PBC port disable handling Add PBC port disable handling in BFA and return the appropriate status from BFA APIs. In bfa_fcs_lport.c, handle OFFLINE event to avoid BFA_ASSERT. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcport.c | 38 +++++++++++++++++++++++++++++++++----- drivers/scsi/bfa/bfa_fcs_lport.c | 3 +++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index 18d33072bec..d3b5efba8af 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1380,6 +1381,14 @@ bfa_status_t bfa_fcport_enable(struct bfa_s *bfa) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + + /* if port is PBC disabled, return error */ + if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) { + bfa_trc(bfa, fcport->pwwn); + return BFA_STATUS_PBC; + } if (fcport->diag_busy) return BFA_STATUS_DIAG_BUSY; @@ -1394,6 +1403,16 @@ bfa_fcport_enable(struct bfa_s *bfa) bfa_status_t bfa_fcport_disable(struct bfa_s *bfa) { + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; + + /* if port is PBC disabled, return error */ + if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) { + bfa_trc(bfa, fcport->pwwn); + return BFA_STATUS_PBC; + } + bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE); return BFA_STATUS_OK; } @@ -1584,6 +1603,8 @@ void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr) { struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + struct bfa_iocfc_s *iocfc = &bfa->iocfc; + struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s)); @@ -1618,11 +1639,18 @@ bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr) attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); - attr->port_state = bfa_sm_to_state(hal_pport_sm_table, fcport->sm); - if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) - attr->port_state = BFA_PPORT_ST_IOCDIS; - else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) - attr->port_state = BFA_PPORT_ST_FWMISMATCH; + + /* PBC Disabled State */ + if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) + attr->port_state = BFA_PPORT_ST_PREBOOT_DISABLED; + else { + attr->port_state = bfa_sm_to_state( + hal_pport_sm_table, fcport->sm); + if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) + attr->port_state = BFA_PPORT_ST_IOCDIS; + else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) + attr->port_state = BFA_PPORT_ST_FWMISMATCH; + } } #define BFA_FCPORT_STATS_TOV 1000 diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 7c1251c682d..35df20e68a5 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -135,6 +135,9 @@ bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event) bfa_fcs_port_deleted(port); break; + case BFA_FCS_PORT_SM_OFFLINE: + break; + default: bfa_sm_fault(port->fcs, event); } -- cgit v1.2.3-70-g09d2 From 9aeb6802ddc06b66fc1a58a882fa54bba37040b3 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:53:40 -0700 Subject: [SCSI] bfa: update to support firmware configuation Update related data structures to support firmeare configuration. Add AEN events related to firmware configuation. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioc.c | 6 +- drivers/scsi/bfa/bfa_ioc.h | 1 + drivers/scsi/bfa/bfa_log_module.c | 86 +++++++++++++++++++++++++ drivers/scsi/bfa/include/aen/bfa_aen_ioc.h | 8 +++ drivers/scsi/bfa/include/cs/bfa_debug.h | 3 +- drivers/scsi/bfa/include/defs/bfa_defs_ioc.h | 7 +- drivers/scsi/bfa/include/defs/bfa_defs_status.h | 3 + drivers/scsi/bfa/include/log/bfa_log_linux.h | 6 +- 8 files changed, 112 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 1600f747eb6..c4922fb995d 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -71,8 +71,6 @@ bfa_boolean_t bfa_auto_recover = BFA_TRUE; /* * forward declarations */ -static void bfa_ioc_aen_post(struct bfa_ioc_s *bfa, - enum bfa_ioc_aen_event event); static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc); static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc); static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force); @@ -1902,7 +1900,7 @@ bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc) /** * Send AEN notification */ -static void +void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) { union bfa_aen_data_u aen_data; @@ -2052,7 +2050,7 @@ bfa_ioc_recover(struct bfa_ioc_s *ioc) #else -static void +void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) { } diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h index 2425c00a72d..cae05b251c9 100644 --- a/drivers/scsi/bfa/bfa_ioc.h +++ b/drivers/scsi/bfa/bfa_ioc.h @@ -297,6 +297,7 @@ void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr); bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr); +void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event); /* * bfa mfg wwn API functions diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c index 5c154d341d6..cf577ef7cb9 100644 --- a/drivers/scsi/bfa/bfa_log_module.c +++ b/drivers/scsi/bfa/bfa_log_module.c @@ -110,6 +110,27 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = { "Running firmware version is incompatible with the driver version.", (0), 0}, +{BFA_AEN_IOC_FWCFG_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWCFG_ERROR", + "Link initialization failed due to firmware configuration read error:" + " WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_INVALID_VENDOR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_VENDOR", + "Unsupported switch vendor. Link initialization failed: WWN = %s.", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_AEN_IOC_INVALID_NWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_NWWN", + "Invalid NWWN. Link initialization failed: NWWN = 00:00:00:00:00:00:00:00.", + (0), 0}, + +{BFA_AEN_IOC_INVALID_PWWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "BFA_AEN_IOC_INVALID_PWWN", + "Invalid PWWN. Link initialization failed: PWWN = 00:00:00:00:00:00:00:00.", + (0), 0}, + @@ -347,6 +368,22 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = { ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) | (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3}, +{BFA_LOG_HAL_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "HAL_DRIVER_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_HAL_DRIVER_CONFIG_ERROR, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "HAL_DRIVER_CONFIG_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_HAL_MBOX_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "HAL_MBOX_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + @@ -412,6 +449,55 @@ struct bfa_log_msgdef_s bfa_log_msg_array[] = { ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) | (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3}, +{BFA_LOG_LINUX_DRIVER_CONFIG_ERROR, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_DRIVER_CONFIG_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_BNA_STATE_MACHINE, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_BNA_STATE_MACHINE", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_IOC_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_IOC_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_RESOURCE_ALLOC_ERROR, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_RESOURCE_ALLOC_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_RING_BUFFER_ERROR, + BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO, + "LINUX_RING_BUFFER_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_DRIVER_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_ERROR, "LINUX_DRIVER_ERROR", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_DRIVER_INFO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_DRIVER_INFO", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_DRIVER_DIAG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_DRIVER_DIAG", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + +{BFA_LOG_LINUX_DRIVER_AEN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, + BFA_LOG_INFO, "LINUX_DRIVER_AEN", + "%s", + ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1}, + diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h index 71378b446b6..4daf96faa26 100644 --- a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h +++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h @@ -32,6 +32,14 @@ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE) #define BFA_AEN_IOC_FWMISMATCH \ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH) +#define BFA_AEN_IOC_FWCFG_ERROR \ + BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWCFG_ERROR) +#define BFA_AEN_IOC_INVALID_VENDOR \ + BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_VENDOR) +#define BFA_AEN_IOC_INVALID_NWWN \ + BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_NWWN) +#define BFA_AEN_IOC_INVALID_PWWN \ + BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_INVALID_PWWN) #endif diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h index 441be86b1b0..75a911ea793 100644 --- a/drivers/scsi/bfa/include/cs/bfa_debug.h +++ b/drivers/scsi/bfa/include/cs/bfa_debug.h @@ -28,7 +28,8 @@ } while (0) #define bfa_sm_fault(__mod, __event) do { \ - bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \ + bfa_trc(__mod, (((uint32_t)0xDEAD << 16) | __event)); \ + bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \ } while (0) #ifndef BFA_PERF_BUILD diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h index 8d8e6a96653..add0a05d941 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h @@ -126,7 +126,7 @@ struct bfa_ioc_attr_s { struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ struct bfa_ioc_pci_attr_s pci_attr; u8 port_id; /* port number */ - u8 rsvd[7]; /*!< 64bit align */ + u8 rsvd[7]; /* 64bit align */ }; /** @@ -138,6 +138,11 @@ enum bfa_ioc_aen_event { BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */ BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */ BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */ + BFA_IOC_AEN_FWCFG_ERROR = 6, /* IOC firmware config error */ + BFA_IOC_AEN_INVALID_VENDOR = 7, + BFA_IOC_AEN_INVALID_NWWN = 8, /* Zero NWWN */ + BFA_IOC_AEN_INVALID_PWWN = 9 /* Zero PWWN */ + }; /** diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h index 7cef900707c..c8bc60ad2df 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h @@ -254,6 +254,9 @@ enum bfa_status { * Teaming mode */ BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot * configuration */ + BFA_STATUS_DEVID_MISSING = 155, /* Boot image is not for the adapter(s) + * installed */ + BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */ BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h index bd451db4c30..44bc89768bd 100644 --- a/drivers/scsi/bfa/include/log/bfa_log_linux.h +++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h @@ -53,8 +53,10 @@ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 16) #define BFA_LOG_LINUX_DRIVER_ERROR \ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 17) -#define BFA_LOG_LINUX_DRIVER_DIAG \ +#define BFA_LOG_LINUX_DRIVER_INFO \ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 18) -#define BFA_LOG_LINUX_DRIVER_AEN \ +#define BFA_LOG_LINUX_DRIVER_DIAG \ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 19) +#define BFA_LOG_LINUX_DRIVER_AEN \ + (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 20) #endif -- cgit v1.2.3-70-g09d2 From df2a52a6c8c4995e0bec0b739ddb2f51664837dd Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:54:39 -0700 Subject: [SCSI] bfa: fix chip and memory initialization Clear PSS memory reset that is set as part of power-on-reset (pci reset). Complete PMM memory reset before BISTR start. Clear EDRAM BISTR start bit after fixed delay. BISTR DONE bit status is not getting set. Use a fixed 1ms delay for BISTR now. Expose PMM IT memory definitions to host. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioc_ct.c | 25 +++++++++++++++++++++++++ drivers/scsi/bfa/include/bfi/bfi_ctreg.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/drivers/scsi/bfa/bfa_ioc_ct.c b/drivers/scsi/bfa/bfa_ioc_ct.c index 17bd1513b34..68f027da001 100644 --- a/drivers/scsi/bfa/bfa_ioc_ct.c +++ b/drivers/scsi/bfa/bfa_ioc_ct.c @@ -376,10 +376,35 @@ bfa_ioc_ct_pll_init(struct bfa_ioc_s *ioc) bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk | __APP_PLL_425_ENABLE); + /** + * PSS memory reset is asserted at power-on-reset. Need to clear + * this before running EDRAM BISTR + */ + if (ioc->cna) { + bfa_reg_write((rb + PMM_1T_RESET_REG_P0), __PMM_1T_RESET_P); + bfa_reg_write((rb + PMM_1T_RESET_REG_P1), __PMM_1T_RESET_P); + } + + r32 = bfa_reg_read((rb + PSS_CTL_REG)); + r32 &= ~__PSS_LMEM_RESET; + bfa_reg_write((rb + PSS_CTL_REG), r32); + bfa_os_udelay(1000); + + if (ioc->cna) { + bfa_reg_write((rb + PMM_1T_RESET_REG_P0), 0); + bfa_reg_write((rb + PMM_1T_RESET_REG_P1), 0); + } + bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START); bfa_os_udelay(1000); r32 = bfa_reg_read((rb + MBIST_STAT_REG)); bfa_trc(ioc, r32); + + /** + * Clear BISTR + */ + bfa_reg_write((rb + MBIST_CTL_REG), 0); + /* * release semaphore. */ diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h index 57a8497105a..c0ef5a93b79 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h +++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h @@ -455,6 +455,9 @@ enum { #define __PSS_LPU0_RAM_ERR 0x00000001 #define ERR_SET_REG 0x00018818 #define __PSS_ERR_STATUS_SET 0x003fffff +#define PMM_1T_RESET_REG_P0 0x0002381c +#define __PMM_1T_RESET_P 0x00000001 +#define PMM_1T_RESET_REG_P1 0x00023c1c #define HQM_QSET0_RXQ_DRBL_P0 0x00038000 #define __RXQ0_ADD_VECTORS_P 0x80000000 #define __RXQ0_STOP_P 0x40000000 -- cgit v1.2.3-70-g09d2 From 4b5e759dca9fb26d921c1267283350004dbf197b Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:55:41 -0700 Subject: [SCSI] bfa: fix uf post and rport fcpim state machine BFA UF module did not hold lock when seding uf post buffer message to firmware causing CPE-Q corruption. Fix is to check present of FCS and if FCS present hold lock while posting UF buffers. Handle PRLO with sending acc to it and relogin with rport. Discard fcxp before any state change. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_uf.c | 5 +- drivers/scsi/bfa/fcpim.c | 16 +++--- drivers/scsi/bfa/fcs_rport.h | 1 + drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h | 1 + drivers/scsi/bfa/rport.c | 76 +++++++++++++++++++++++++++- 5 files changed, 89 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c index b2a37fc952d..b9a9a686ef6 100644 --- a/drivers/scsi/bfa/bfa_uf.c +++ b/drivers/scsi/bfa/bfa_uf.c @@ -251,7 +251,10 @@ uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) (struct fchs_s *) buf, pld_w0); } - bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); + if (bfa->fcs) + __bfa_cb_uf_recv(uf, BFA_TRUE); + else + bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); } static void diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c index d090f7a6368..6b8976ad22f 100644 --- a/drivers/scsi/bfa/fcpim.c +++ b/drivers/scsi/bfa/fcpim.c @@ -175,8 +175,12 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, switch (event) { case BFA_FCS_ITNIM_SM_RSP_OK: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online); - bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec); + if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR) { + bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); + } else { + bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online); + bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec); + } break; case BFA_FCS_ITNIM_SM_RSP_ERROR: @@ -194,9 +198,7 @@ bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, case BFA_FCS_ITNIM_SM_INITIATOR: bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - /* - * dont discard fcxp. accept will reach same state - */ + bfa_fcxp_discard(itnim->fcxp); break; case BFA_FCS_ITNIM_SM_DELETE: @@ -476,7 +478,7 @@ bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, BFA_RPORT_INITIATOR; itnim->stats.prli_rsp_acc++; bfa_sm_send_event(itnim, - BFA_FCS_ITNIM_SM_INITIATOR); + BFA_FCS_ITNIM_SM_RSP_OK); return; } @@ -803,7 +805,7 @@ bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs, switch (els_cmd->els_code) { case FC_ELS_PRLO: - /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */ + bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id); break; default: diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h index 5242ee0f03c..e634fb7a69b 100644 --- a/drivers/scsi/bfa/fcs_rport.h +++ b/drivers/scsi/bfa/fcs_rport.h @@ -43,6 +43,7 @@ void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, struct fc_logi_s *plogi); void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport); +void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id); void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport); void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport); void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport); diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h index 702b95b76c2..3027fc6c772 100644 --- a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h +++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h @@ -58,6 +58,7 @@ struct bfa_fcs_rport_s { u16 reply_oxid; /* OX_ID of inbound requests */ enum fc_cos fc_cos; /* FC classes of service supp */ bfa_boolean_t cisc; /* CISC capable device */ + bfa_boolean_t prlo; /* processing prlo or LOGO */ wwn_t pwwn; /* port wwn of rport */ wwn_t nwwn; /* node wwn of rport */ struct bfa_rport_symname_s psym_name; /* port symbolic name */ diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c index 4e1fff21a5b..9b4c2c9a644 100644 --- a/drivers/scsi/bfa/rport.c +++ b/drivers/scsi/bfa/rport.c @@ -93,6 +93,7 @@ static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, u8 reason_code_expl); static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, u16 len); +static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport); /** * fcs_rport_sm FCS rport state machine events */ @@ -113,7 +114,8 @@ enum rport_event { RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ - RPSM_EVENT_ADDRESS_DISC = 16 /* Need to Discover rport's PID */ + RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ + RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ }; static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, @@ -373,6 +375,7 @@ bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_free(rport); break; + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_LOGO_RCVD: break; @@ -428,6 +431,13 @@ bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) case RPSM_EVENT_LOGO_RCVD: bfa_fcs_rport_send_logo_acc(rport); + /* + * !! fall through !! + */ + case RPSM_EVENT_PRLO_RCVD: + if (rport->prlo == BFA_TRUE) + bfa_fcs_rport_send_prlo_acc(rport); + bfa_fcxp_discard(rport->fcxp); /* * !! fall through !! @@ -502,6 +512,9 @@ bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_online_action(rport); break; + case RPSM_EVENT_PRLO_RCVD: + break; + case RPSM_EVENT_LOGO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv); bfa_rport_offline(rport->bfa_rport); @@ -580,6 +593,7 @@ bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); bfa_fcs_rport_offline_action(rport); break; @@ -622,6 +636,7 @@ bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_fcs_rport_offline_action(rport); @@ -688,6 +703,7 @@ bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); bfa_fcxp_discard(rport->fcxp); bfa_fcs_rport_offline_action(rport); @@ -738,6 +754,7 @@ bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_fcs_rport_offline_action(rport); @@ -809,6 +826,7 @@ bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); bfa_fcxp_discard(rport->fcxp); bfa_fcs_rport_offline_action(rport); @@ -841,6 +859,7 @@ bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_ADDRESS_CHANGE: break; @@ -892,6 +911,7 @@ bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_SCN: case RPSM_EVENT_LOGO_IMP: case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_ADDRESS_CHANGE: /** * rport is already going offline. @@ -951,6 +971,7 @@ bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_SCN: case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: /** * Ignore, already offline. */ @@ -976,8 +997,11 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, switch (event) { case RPSM_EVENT_HCB_OFFLINE: case RPSM_EVENT_ADDRESS_CHANGE: - if (rport->pid) + if (rport->pid && (rport->prlo == BFA_TRUE)) + bfa_fcs_rport_send_prlo_acc(rport); + if (rport->pid && (rport->prlo == BFA_FALSE)) bfa_fcs_rport_send_logo_acc(rport); + /* * If the lport is online and if the rport is not a well known * address port, we try to re-discover the r-port. @@ -1011,6 +1035,7 @@ bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: /** * Ignore - already processing a LOGO. */ @@ -1040,6 +1065,7 @@ bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_ADDRESS_CHANGE: break; @@ -1073,6 +1099,7 @@ bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); bfa_fcs_rport_free(rport); @@ -1121,6 +1148,7 @@ bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) break; case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_LOGO_IMP: break; @@ -1172,6 +1200,7 @@ bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, case RPSM_EVENT_SCN: case RPSM_EVENT_LOGO_RCVD: + case RPSM_EVENT_PRLO_RCVD: case RPSM_EVENT_PLOGI_SEND: break; @@ -1248,6 +1277,10 @@ bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_send_logo_acc(rport); break; + case RPSM_EVENT_PRLO_RCVD: + bfa_fcs_rport_send_prlo_acc(rport); + break; + case RPSM_EVENT_PLOGI_COMP: bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); bfa_timer_stop(&rport->timer); @@ -1320,6 +1353,10 @@ bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, bfa_fcs_rport_del_timeout); break; + case RPSM_EVENT_PRLO_RCVD: + bfa_fcs_rport_send_prlo_acc(rport); + break; + case RPSM_EVENT_SCN: /** * ignore, wait for NS query response @@ -2182,6 +2219,7 @@ bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) rport->reply_oxid = fchs->ox_id; bfa_trc(rport->fcs, rport->reply_oxid); + rport->prlo = BFA_FALSE; rport->stats.logo_rcvd++; bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD); } @@ -2551,6 +2589,30 @@ bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, } } +/* Send best case acc to prlo */ +static void +bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport) +{ + struct bfa_fcs_port_s *port = rport->port; + struct fchs_s fchs; + struct bfa_fcxp_s *fcxp; + int len; + + bfa_trc(rport->fcs, rport->pid); + + fcxp = bfa_fcs_fcxp_alloc(port->fcs); + if (!fcxp) + return; + + len = fc_prlo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), + rport->pid, bfa_fcs_port_get_fcid(port), + rport->reply_oxid, 0); + + bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, + port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, + NULL, NULL, FC_MAX_PDUSZ, 0); +} + /* * Send a LS reject */ @@ -2602,3 +2664,13 @@ bfa_fcs_rport_set_del_timeout(u8 rport_tmo) if (rport_tmo > 0) bfa_fcs_rport_del_timeout = rport_tmo * 1000; } + +void +bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, uint16_t ox_id) +{ + bfa_trc(rport->fcs, rport->pid); + + rport->prlo = BFA_TRUE; + rport->reply_oxid = ox_id; + bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD); +} -- cgit v1.2.3-70-g09d2 From 36d345a703b7b3f80a56ee37abb7908c52d1cd67 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:57:33 -0700 Subject: [SCSI] bfa: add dynamic queue selection Add new bfa functionality to support dynamic queue selection (IO redirection). IO redirection can only be enabled when QoS is disabled. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_cb_ioim_macros.h | 7 +++++- drivers/scsi/bfa/bfa_fcpim.c | 24 ++++++++++++++++++++ drivers/scsi/bfa/bfa_fcpim_priv.h | 5 ++++- drivers/scsi/bfa/bfa_fcport.c | 13 ++++++++++- drivers/scsi/bfa/bfa_hw_cb.c | 7 +++++- drivers/scsi/bfa/bfa_hw_ct.c | 7 +++++- drivers/scsi/bfa/bfa_intr.c | 1 + drivers/scsi/bfa/bfa_iocfc.c | 2 ++ drivers/scsi/bfa/bfa_iocfc.h | 9 +++++++- drivers/scsi/bfa/bfa_ioim.c | 29 +++++++++++++++---------- drivers/scsi/bfa/bfad_im.c | 9 ++++++++ drivers/scsi/bfa/include/bfa_fcpim.h | 20 ++++++++++++++++- drivers/scsi/bfa/include/bfa_svc.h | 1 + drivers/scsi/bfa/include/defs/bfa_defs_driver.h | 2 +- 14 files changed, 117 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h index 53a616f5f50..3906ed92696 100644 --- a/drivers/scsi/bfa/bfa_cb_ioim_macros.h +++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h @@ -171,6 +171,11 @@ bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio) return cmnd->cmd_len; } - +/** + * Assign queue to be used for the I/O request. This value depends on whether + * the driver wants to use the queues via any specific algorithm. Currently, + * this is not supported. + */ +#define bfa_cb_ioim_get_reqq(__dio) BFA_FALSE #endif /* __BFA_HCB_IOIM_MACROS_H__ */ diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c index 12849e9071c..8c703d8dc94 100644 --- a/drivers/scsi/bfa/bfa_fcpim.c +++ b/drivers/scsi/bfa/bfa_fcpim.c @@ -167,4 +167,28 @@ bfa_fcpim_qdepth_get(struct bfa_s *bfa) return fcpim->q_depth; } +void +bfa_fcpim_update_ioredirect(struct bfa_s *bfa) +{ + bfa_boolean_t ioredirect; + + /* + * IO redirection is turned off when QoS is enabled and vice versa + */ + ioredirect = bfa_fcport_is_qos_enabled(bfa) ? BFA_FALSE : BFA_TRUE; + /* + * Notify the bfad module of a possible state change in + * IO redirection capability, due to a QoS state change. bfad will + * check on the support for io redirection and update the + * fcpim's ioredirect state accordingly. + */ + bfa_cb_ioredirect_state_change((void *)(bfa->bfad), ioredirect); +} + +void +bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state) +{ + struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa); + fcpim->ioredirect = state; +} diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h index 3db39da7242..762516cb5cb 100644 --- a/drivers/scsi/bfa/bfa_fcpim_priv.h +++ b/drivers/scsi/bfa/bfa_fcpim_priv.h @@ -49,7 +49,8 @@ struct bfa_fcpim_mod_s { int num_tskim_reqs; u32 path_tov; u16 q_depth; - u16 rsvd; + u8 reqq; /* Request queue to be used */ + u8 rsvd; struct list_head itnim_q; /* queue of active itnim */ struct list_head ioim_free_q; /* free IO resources */ struct list_head ioim_resfree_q; /* IOs waiting for f/w */ @@ -58,6 +59,7 @@ struct bfa_fcpim_mod_s { u32 ios_active; /* current active IOs */ u32 delay_comp; struct bfa_fcpim_stats_s stats; + bfa_boolean_t ioredirect; }; struct bfa_ioim_s; @@ -82,6 +84,7 @@ struct bfa_ioim_s { struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ bfa_cb_cbfn_t io_cbfn; /* IO completion handler */ struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */ + u8 reqq; /* Request queue for I/O */ }; struct bfa_ioim_sp_s { diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index d3b5efba8af..e0e7a0dda54 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -1857,8 +1857,13 @@ bfa_fcport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off) bfa_trc(bfa, ioc_type); - if (ioc_type == BFA_IOC_TYPE_FC) + if (ioc_type == BFA_IOC_TYPE_FC) { fcport->cfg.qos_enabled = on_off; + /** + * Notify fcpim of the change in QoS state + */ + bfa_fcpim_update_ioredirect(bfa); + } } void @@ -1942,4 +1947,10 @@ bfa_fcport_is_linkup(struct bfa_s *bfa) return bfa_sm_cmp_state(BFA_FCPORT_MOD(bfa), bfa_fcport_sm_linkup); } +bfa_boolean_t +bfa_fcport_is_qos_enabled(struct bfa_s *bfa) +{ + struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); + return fcport->cfg.qos_enabled; +} diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c index 871a4e28575..edfd729445c 100644 --- a/drivers/scsi/bfa/bfa_hw_cb.c +++ b/drivers/scsi/bfa/bfa_hw_cb.c @@ -152,4 +152,9 @@ bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix; } - +void +bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) +{ + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q7; +} diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c index 76ceb9a4bf2..a357fb3066f 100644 --- a/drivers/scsi/bfa/bfa_hw_ct.c +++ b/drivers/scsi/bfa/bfa_hw_ct.c @@ -168,4 +168,9 @@ bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) bfa_ioc_isr_mode_set(&bfa->ioc, msix); } - +void +bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) +{ + *start = BFA_MSIX_RME_Q0; + *end = BFA_MSIX_RME_Q3; +} diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c index 0eba3f930d5..493678889b2 100644 --- a/drivers/scsi/bfa/bfa_intr.c +++ b/drivers/scsi/bfa/bfa_intr.c @@ -134,6 +134,7 @@ bfa_isr_enable(struct bfa_s *bfa) bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask); bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask); + bfa->iocfc.intr_mask = ~intr_unmask; bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); } diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c index 0776d74d40d..90820be9986 100644 --- a/drivers/scsi/bfa/bfa_iocfc.c +++ b/drivers/scsi/bfa/bfa_iocfc.c @@ -187,6 +187,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; + iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range; } else { iocfc->hwif.hw_reginit = bfa_hwcb_reginit; iocfc->hwif.hw_reqq_ack = bfa_hwcb_reqq_ack; @@ -196,6 +197,7 @@ bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; + iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; } iocfc->hwif.hw_reginit(bfa); diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h index 2b281037fd7..74a6a048d1f 100644 --- a/drivers/scsi/bfa/bfa_iocfc.h +++ b/drivers/scsi/bfa/bfa_iocfc.h @@ -63,6 +63,8 @@ struct bfa_hwif_s { void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, u32 *maxvec); + void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start, + u32 *end); }; typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status); @@ -104,7 +106,8 @@ struct bfa_iocfc_s { struct bfa_hwif_s hwif; bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ - void *updateq_cbarg; /* bios callback arg */ + void *updateq_cbarg; /* bios callback arg */ + u32 intr_mask; }; #define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc) @@ -119,6 +122,8 @@ struct bfa_iocfc_s { #define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ __nvecs, __maxvec)) +#define bfa_msix_get_rme_range(__bfa, __start, __end) \ + ((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end)) /* * FC specific IOC functions. @@ -154,6 +159,7 @@ void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, u32 *maxvec); +void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end); void bfa_hwct_reginit(struct bfa_s *bfa); void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq); void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq); @@ -163,6 +169,7 @@ void bfa_hwct_msix_uninstall(struct bfa_s *bfa); void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, u32 *maxvec); +void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end); void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len); void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi, diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c index 687f3d6e252..680b87d8f0d 100644 --- a/drivers/scsi/bfa/bfa_ioim.c +++ b/drivers/scsi/bfa/bfa_ioim.c @@ -234,8 +234,8 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) bfa_sm_set_state(ioim, bfa_ioim_sm_abort); else { bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull); - bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, - &ioim->iosp->reqq_wait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); } break; @@ -247,8 +247,8 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); else { bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, - &ioim->iosp->reqq_wait); + bfa_reqq_wait(ioim->bfa, ioim->reqq, + &ioim->iosp->reqq_wait); } break; @@ -305,7 +305,7 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); else { bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, + bfa_reqq_wait(ioim->bfa, ioim->reqq, &ioim->iosp->reqq_wait); } break; @@ -738,9 +738,9 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) /** * check for room in queue to send request now */ - m = bfa_reqq_next(ioim->bfa, itnim->reqq); + m = bfa_reqq_next(ioim->bfa, ioim->reqq); if (!m) { - bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq, + bfa_reqq_wait(ioim->bfa, ioim->reqq, &ioim->iosp->reqq_wait); return BFA_FALSE; } @@ -832,7 +832,7 @@ bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) /** * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, itnim->reqq); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -930,14 +930,13 @@ bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim) static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim) { - struct bfa_itnim_s *itnim = ioim->itnim; struct bfi_ioim_abort_req_s *m; enum bfi_ioim_h2i msgop; /** * check for room in queue to send request now */ - m = bfa_reqq_next(ioim->bfa, itnim->reqq); + m = bfa_reqq_next(ioim->bfa, ioim->reqq); if (!m) return BFA_FALSE; @@ -956,7 +955,7 @@ bfa_ioim_send_abort(struct bfa_ioim_s *ioim) /** * queue I/O message to firmware */ - bfa_reqq_produce(ioim->bfa, itnim->reqq); + bfa_reqq_produce(ioim->bfa, ioim->reqq); return BFA_TRUE; } @@ -1306,6 +1305,14 @@ void bfa_ioim_start(struct bfa_ioim_s *ioim) { bfa_trc_fp(ioim->bfa, ioim->iotag); + + /** + * Obtain the queue over which this request has to be issued + */ + ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ? + bfa_cb_ioim_get_reqq(ioim->dio) : + bfa_itnim_get_reqq(ioim); + bfa_sm_send_event(ioim, BFA_IOIM_SM_START); } diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 943bc4b3728..ffbec9ba21b 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -702,6 +702,15 @@ bfad_im_probe_undo(struct bfad_s *bfad) } } +/** + * Call back function to handle IO redirection state change + */ +void +bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect) +{ + /* Do nothing */ +} + struct Scsi_Host * bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) { diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h index 04789795fa5..4bc9453081d 100644 --- a/drivers/scsi/bfa/include/bfa_fcpim.h +++ b/drivers/scsi/bfa/include/bfa_fcpim.h @@ -42,6 +42,24 @@ u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_fcpim_stats_s *modstats); bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa); +void bfa_fcpim_set_ioredirect(struct bfa_s *bfa, bfa_boolean_t state); +void bfa_fcpim_update_ioredirect(struct bfa_s *bfa); +void bfa_cb_ioredirect_state_change(void *hcb_bfad, bfa_boolean_t ioredirect); + +#define bfa_fcpim_ioredirect_enabled(__bfa) \ + (((struct bfa_fcpim_mod_s *)(BFA_FCPIM_MOD(__bfa)))->ioredirect) + +#define bfa_fcpim_get_next_reqq(__bfa, __qid) \ +{ \ + struct bfa_fcpim_mod_s *__fcpim = BFA_FCPIM_MOD(__bfa); \ + __fcpim->reqq++; \ + __fcpim->reqq &= (BFI_IOC_MAX_CQS - 1); \ + *(__qid) = __fcpim->reqq; \ +} + +#define bfa_iocfc_map_msg_to_qid(__msg, __qid) \ + *(__qid) = (u8)((__msg) & (BFI_IOC_MAX_CQS - 1)); + /* * bfa itnim API functions @@ -56,6 +74,7 @@ void bfa_itnim_get_stats(struct bfa_itnim_s *itnim, struct bfa_itnim_hal_stats_s *stats); void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim); +#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq) /** * BFA completion callback for bfa_itnim_online(). @@ -156,4 +175,3 @@ void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, enum bfi_tskim_status tsk_status); #endif /* __BFA_FCPIM_H__ */ - diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h index 1349b99a3c6..7840943d73b 100644 --- a/drivers/scsi/bfa/include/bfa_svc.h +++ b/drivers/scsi/bfa/include/bfa_svc.h @@ -215,6 +215,7 @@ bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg); bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg); +bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); /* * bfa rport API functions diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h index 50382dd2ab4..7d00d00d396 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h @@ -29,7 +29,7 @@ struct bfa_driver_stats_s { u16 tm_target_reset; u16 tm_bus_reset; u16 ioc_restart; /* IOC restart count */ - u16 io_pending; /* outstanding io count per-IOC */ + u16 rsvd; u64 control_req; u64 input_req; u64 output_req; -- cgit v1.2.3-70-g09d2 From db954c04cbebd7d719927118c7f58eddd8dd9913 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:58:01 -0700 Subject: [SCSI] bfa: fix link state structure When the FCoE Linkup event is sent to the host, the link_state (struct bfa_pport_link_s) structure is copied to the RME buf to be sent to the host. But the size of this structure(164 bytes) is larger than the reserved RME buffer size(128 byes). The following changes reduce the size of the structure to be less than RME buffer size(128 bytes): - Remove the trunk and loop info from link_state structure, because both trunk and loop are not supported. - Combine qos_vc_attr and fcf into an union. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcport.c | 15 +++++++++------ drivers/scsi/bfa/include/defs/bfa_defs_pport.h | 22 +++------------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index e0e7a0dda54..c855e225af1 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -311,10 +311,12 @@ bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { - bfa_trc(fcport->bfa, pevent->link_state.fcf.fipenabled); - bfa_trc(fcport->bfa, pevent->link_state.fcf.fipfailed); + bfa_trc(fcport->bfa, + pevent->link_state.vc_fcf.fcf.fipenabled); + bfa_trc(fcport->bfa, + pevent->link_state.vc_fcf.fcf.fipfailed); - if (pevent->link_state.fcf.fipfailed) + if (pevent->link_state.vc_fcf.fcf.fipfailed) bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_FIP_FCF_DISC, 0, "FIP FCF Discovery Failed"); @@ -960,14 +962,15 @@ bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) fcport->topology = pevent->link_state.topology; if (fcport->topology == BFA_PPORT_TOPOLOGY_LOOP) - fcport->myalpa = - pevent->link_state.tl.loop_info.myalpa; + fcport->myalpa = 0; /* * QoS Details */ bfa_os_assign(fcport->qos_attr, pevent->link_state.qos_attr); - bfa_os_assign(fcport->qos_vc_attr, pevent->link_state.qos_vc_attr); + bfa_os_assign(fcport->qos_vc_attr, + pevent->link_state.vc_fcf.qos_vc_attr); + bfa_trc(fcport->bfa, fcport->speed); bfa_trc(fcport->bfa, fcport->topology); diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h index 2c2cec5ee27..2de675839c2 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h @@ -384,26 +384,10 @@ struct bfa_pport_link_s { u8 trunked; /* Trunked or not (1 or 0) */ u8 resvd[3]; struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ - struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ union { - struct { - u8 tmaster;/* Trunk Master or - * not (1 or 0) */ - u8 tlinks; /* Trunk links bitmap - * (linkup) */ - u8 resv1; /* Reserved */ - } trunk_info; - - struct { - u8 myalpa; /* alpa claimed */ - u8 login_req; /* Login required or - * not (1 or 0) */ - u8 alpabm_val;/* alpa bitmap valid - * or not (1 or 0) */ - struct fc_alpabm_s alpabm; /* alpa bitmap */ - } loop_info; - } tl; - struct bfa_fcport_fcf_s fcf; /*!< FCF information (for FCoE) */ + struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ + struct bfa_fcport_fcf_s fcf; /* FCF information (for FCoE) */ + } vc_fcf; }; #endif /* __BFA_DEFS_PPORT_H__ */ -- cgit v1.2.3-70-g09d2 From 56d218fc93ede28a2a5b71c5db334f193b39988f Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:58:45 -0700 Subject: [SCSI] bfa: fix possible IO double completion While processing the ioim in callback functions, the ioim is still in io_q. During this time, if the itnim goes offline, the ioim is requeued from itnim->io_q into itnim->delay_comp_q although the request is already completed. This results in requeing the ioim into the callback queue if the ioim is not freed by the time the ioim is requeued. This results in double completion of the ioim. To fix this, whenever a response is received from firmware for an ioim, deque it from io_q and enque to fcpim->comp_q. This will eliminate any possibility of itnim picking any ioim for which the response is already received. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioim.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c index 680b87d8f0d..4148ae09f99 100644 --- a/drivers/scsi/bfa/bfa_ioim.c +++ b/drivers/scsi/bfa/bfa_ioim.c @@ -133,6 +133,8 @@ bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_IOTOV: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_pathtov, ioim); break; @@ -182,6 +184,8 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_ABORT: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; @@ -189,6 +193,8 @@ bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -210,18 +216,24 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) switch (event) { case BFA_IOIM_SM_COMP_GOOD: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_good_comp, ioim); break; case BFA_IOIM_SM_COMP: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, ioim); break; case BFA_IOIM_SM_DONE: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, ioim); break; @@ -254,6 +266,8 @@ bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -287,12 +301,16 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_ABORT_COMP: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; case BFA_IOIM_SM_COMP_UTAG: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; @@ -312,6 +330,8 @@ bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -365,6 +385,8 @@ bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -399,6 +421,8 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_ABORT: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; @@ -414,6 +438,8 @@ bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -448,6 +474,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_COMP: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; @@ -455,6 +483,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_DONE: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, ioim); break; @@ -462,6 +492,8 @@ bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; @@ -511,6 +543,8 @@ bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) case BFA_IOIM_SM_HWFAIL: bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); bfa_reqq_wcancel(&ioim->iosp->reqq_wait); + list_del(&ioim->qe); + list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, ioim); break; -- cgit v1.2.3-70-g09d2 From 07b2838669dc7704e02e079b1a96602656893d78 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:59:24 -0700 Subject: [SCSI] bfa: update to support BOFM Update bfa driver API and data structure to support BOFM (IBM BladeCenter Open Fabric Manager). Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioc.c | 44 +++++++++++-------------- drivers/scsi/bfa/include/bfa.h | 2 ++ drivers/scsi/bfa/include/bfi/bfi_ioc.h | 2 +- drivers/scsi/bfa/include/defs/bfa_defs_status.h | 16 +++++++-- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index c4922fb995d..8e78f20110a 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -84,6 +84,7 @@ static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force); static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc); static void bfa_ioc_recover(struct bfa_ioc_s *ioc); +static void bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc); static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); @@ -429,6 +430,7 @@ bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) switch (event) { case IOC_E_FWRSP_GETATTR: bfa_ioc_timer_stop(ioc); + bfa_ioc_check_attr_wwns(ioc); bfa_fsm_set_state(ioc, bfa_ioc_sm_op); break; @@ -977,8 +979,13 @@ bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) /** * If IOC function is disabled and firmware version is same, * just re-enable IOC. + * + * If option rom, IOC must not be in operational state. With + * convergence, IOC will be in operational state when 2nd driver + * is loaded. */ - if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) { + if (ioc_fwstate == BFI_IOC_DISABLED || + (!bfa_ioc_is_optrom(ioc) && ioc_fwstate == BFI_IOC_OP)) { bfa_trc(ioc, ioc_fwstate); /** @@ -1281,6 +1288,7 @@ bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param) bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING); } + bfa_ioc_msgflush(ioc); bfa_ioc_download_fw(ioc, boot_type, boot_param); /** @@ -1788,28 +1796,17 @@ void bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) { struct bfi_ioc_attr_s *ioc_attr; - u8 nports; - u8 max_speed; bfa_assert(model); bfa_os_memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN); ioc_attr = ioc->attr; - nports = bfa_ioc_get_nports(ioc); - max_speed = bfa_ioc_speed_sup(ioc); - /** * model name */ - if (max_speed == 10) { - strcpy(model, "BR-10?0"); - model[5] = '0' + nports; - } else { - strcpy(model, "Brocade-??5"); - model[8] = '0' + max_speed; - model[9] = '0' + nports; - } + snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", + BFA_MFG_NAME, ioc_attr->card_type); } enum bfa_ioc_state @@ -2048,19 +2045,16 @@ bfa_ioc_recover(struct bfa_ioc_s *ioc) bfa_fsm_send_event(ioc, IOC_E_HBFAIL); } -#else - -void -bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) -{ -} - static void -bfa_ioc_recover(struct bfa_ioc_s *ioc) +bfa_ioc_check_attr_wwns(struct bfa_ioc_s *ioc) { - bfa_assert(0); + if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_LL) + return; + + if (ioc->attr->nwwn == 0) + bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_NWWN); + if (ioc->attr->pwwn == 0) + bfa_ioc_aen_post(ioc, BFA_IOC_AEN_INVALID_PWWN); } #endif - - diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h index 9519a6d8104..d52b32f5695 100644 --- a/drivers/scsi/bfa/include/bfa.h +++ b/drivers/scsi/bfa/include/bfa.h @@ -126,6 +126,8 @@ struct bfa_sge_s { bfa_ioc_get_type(&(__bfa)->ioc) #define bfa_get_mac(__bfa) \ bfa_ioc_get_mac(&(__bfa)->ioc) +#define bfa_get_mfg_mac(__bfa) \ + bfa_ioc_get_mfg_mac(&(__bfa)->ioc) #define bfa_get_fw_clock_res(__bfa) \ ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res) diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h index 7c5e6d5716d..450ded6e9bc 100644 --- a/drivers/scsi/bfa/include/bfi/bfi_ioc.h +++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h @@ -50,7 +50,7 @@ struct bfi_ioc_getattr_req_s { struct bfi_ioc_attr_s { wwn_t mfg_pwwn; /* Mfg port wwn */ wwn_t mfg_nwwn; /* Mfg node wwn */ - mac_t mfg_mac; + mac_t mfg_mac; /* Mfg mac */ u16 rsvd_a; wwn_t pwwn; wwn_t nwwn; diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h index c8bc60ad2df..6eb4e62096f 100644 --- a/drivers/scsi/bfa/include/defs/bfa_defs_status.h +++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h @@ -256,8 +256,20 @@ enum bfa_status { * configuration */ BFA_STATUS_DEVID_MISSING = 155, /* Boot image is not for the adapter(s) * installed */ - BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */ - BFA_STATUS_MAX_VAL /* Unknown error code */ + BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */ + BFA_STATUS_CREATE_FILE = 157, /* Failed to create temporary file */ + BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */ + BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */ + BFA_STATUS_NO_TOPOLOGY_FOR_CNA = 160, /* Topology command not + * applicable to CNA */ + BFA_STATUS_BOOT_CODE_UPDATED = 161, /* reboot -- -r is needed after + * boot code updated */ + BFA_STATUS_BOOT_VERSION = 162, /* Boot code version not compatible with + * the driver installed */ + BFA_STATUS_CARDTYPE_MISSING = 163, /* Boot image is not for the + * adapter(s) installed */ + BFA_STATUS_INVALID_CARDTYPE = 164, /* Invalid card type provided */ + BFA_STATUS_MAX_VAL /* Unknown error code */ }; #define bfa_status_t enum bfa_status -- cgit v1.2.3-70-g09d2 From 604158ade0d5378622541232a007bf975c8bd03f Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 19:59:49 -0700 Subject: [SCSI] bfa: add description for module parameters Add description for bfa driver module parameters. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfad.c | 33 ++++++++++++++++++++++++++++++--- drivers/scsi/bfa/bfad_intr.c | 4 ++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 37f886d2792..a17800e6277 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -54,31 +54,58 @@ static int bfa_io_max_sge = BFAD_IO_MAX_SGE; static int log_level = BFA_LOG_WARNING; static int ioc_auto_recover = BFA_TRUE; static int ipfc_enable = BFA_FALSE; -static int ipfc_mtu = -1; static int fdmi_enable = BFA_TRUE; int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; int bfa_linkup_delay = -1; module_param(os_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); module_param(os_patch, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(os_patch, "OS patch level of the hba host machine"); module_param(host_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(host_name, "Hostname of the hba host machine"); module_param(num_rports, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_rports, "Max number of rports supported per port" + " (physical/logical), default=1024"); module_param(num_ios, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_ios, "Max number of ioim requests, default=2000"); module_param(num_tms, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_tms, "Max number of task im requests, default=128"); module_param(num_fcxps, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_fcxps, "Max number of fcxp requests, default=64"); module_param(num_ufbufs, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_ufbufs, "Max number of unsolicited frame buffers," + " default=64"); module_param(reqq_size, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(reqq_size, "Max number of request queue elements," + " default=256"); module_param(rspq_size, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rspq_size, "Max number of response queue elements," + " default=64"); module_param(num_sgpgs, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(num_sgpgs, "Number of scatter/gather pages, default=2048"); module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rport_del_timeout, "Rport delete timeout, default=90 secs," + " Range[>0]"); module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32," + " Range[>0]"); module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255"); module_param(log_level, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(log_level, "Driver log level, default=3," + " Range[Critical:1|Error:2|Warning:3|Info:4]"); module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1," + " Range[off:0|on:1]"); module_param(ipfc_enable, int, S_IRUGO | S_IWUSR); -module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR); -module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ipfc_enable, "Enable IPoFC, default=0, Range[off:0|on:1]"); module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for boot" + " port. Otherwise Range[>0]"); +module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1," + " Range[false:0|true:1]"); /* * Stores the module parm num_sgpgs value; diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c index fed27d16365..56a351584f0 100644 --- a/drivers/scsi/bfa/bfad_intr.c +++ b/drivers/scsi/bfa/bfad_intr.c @@ -26,7 +26,11 @@ BFA_TRC_FILE(LDRV, INTR); static int msix_disable_cb; static int msix_disable_ct; module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(msix_disable_cb, "Disable MSIX for Brocade-415/425/815/825" + " cards, default=0, Range[false:0|true:1]"); module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(msix_disable_ct, "Disable MSIX for Brocade-1010/1020/804" + " cards, default=0, Range[false:0|true:1]"); /** * Line based interrupt handler. */ -- cgit v1.2.3-70-g09d2 From ba8345821ac34d1630e99db7d4835db8ab20f50b Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 20:00:24 -0700 Subject: [SCSI] bfa: add ioc state checking This patch adds ioc state checking while enabling a port. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_fcport.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c index c855e225af1..f0933d8d1ed 100644 --- a/drivers/scsi/bfa/bfa_fcport.c +++ b/drivers/scsi/bfa/bfa_fcport.c @@ -1393,6 +1393,9 @@ bfa_fcport_enable(struct bfa_s *bfa) return BFA_STATUS_PBC; } + if (bfa_ioc_is_disabled(&bfa->ioc)) + return BFA_STATUS_IOC_DISABLED; + if (fcport->diag_busy) return BFA_STATUS_DIAG_BUSY; else if (bfa_sm_cmp_state -- cgit v1.2.3-70-g09d2 From 8a4adf1c906ee07a01cb47297130a71489f2e4f0 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 20:01:07 -0700 Subject: [SCSI] bfa: fix wrong arg to callback This patch fixes the issue of passing wrong argument to callback function. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_port.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c index 6773e2282dd..c7e69f1e56e 100644 --- a/drivers/scsi/bfa/bfa_port.c +++ b/drivers/scsi/bfa/bfa_port.c @@ -407,7 +407,7 @@ bfa_port_hbfail(void *arg) */ if (port->stats_busy) { if (port->stats_cbfn) - port->stats_cbfn(port->dev, BFA_STATUS_FAILED); + port->stats_cbfn(port->stats_cbarg, BFA_STATUS_FAILED); port->stats_cbfn = NULL; port->stats_busy = BFA_FALSE; } @@ -417,7 +417,7 @@ bfa_port_hbfail(void *arg) */ if (port->endis_pending) { if (port->endis_cbfn) - port->endis_cbfn(port->dev, BFA_STATUS_FAILED); + port->endis_cbfn(port->endis_cbarg, BFA_STATUS_FAILED); port->endis_cbfn = NULL; port->endis_pending = BFA_FALSE; } -- cgit v1.2.3-70-g09d2 From c54d557c3f6a7bbf833a8f9cffad88f34513a7c4 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 20:01:49 -0700 Subject: [SCSI] bfa: vport fixes This patch fixes 3 bugs in vport create/delete. 1) Replace scsi_add_host() with scsi_add_host_with_dma() 2) Fix rmmod hang when there are vports configured. This is due to a race condition between the workqueue destroy in pci remove context and the vport delete works being handled. The fix is to use a counter to track the vport delete work, so that workqueue destroy will not be called until all configured vports are deleted from workqueue. 3) Fix rmmmod crash when there are PBC vport configured. PBC is not allowed to be deleted dynamically. However, if someone try to delete it, it leaves the vport is wrong state. The fix is to restore the vport back to original state when the attempt to delete pbc vport delete is failed. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfad_attr.c | 5 ++++- drivers/scsi/bfa/bfad_drv.h | 1 + drivers/scsi/bfa/bfad_im.c | 15 +++++++++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 871a3036356..0818eb07ef8 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -473,8 +473,11 @@ bfad_im_vport_delete(struct fc_vport *fc_vport) rc = bfa_fcs_vport_delete(&vport->fcs_vport); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc == BFA_STATUS_PBC) + if (rc == BFA_STATUS_PBC) { + vport->drv_port.flags &= ~BFAD_PORT_DELETE; + vport->comp_del = NULL; return -1; + } wait_for_completion(vport->comp_del); diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index 8629f64a528..dcf28830fee 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -185,6 +185,7 @@ struct bfad_s { bfa_boolean_t ipfc_enabled; struct fc_host_statistics link_stats; struct list_head pbc_pcfg_list; + atomic_t wq_reqcnt; }; struct bfad_pcfg_s { diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index ffbec9ba21b..678120b7046 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -554,7 +554,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, im_port->shost->transportt = bfad_im_scsi_vport_transport_template; - error = scsi_add_host(im_port->shost, dev); + error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev); if (error) { printk(KERN_WARNING "scsi_add_host failure %d\n", error); goto out_fc_rel; @@ -598,10 +598,12 @@ bfad_im_port_delete_handler(struct work_struct *work) { struct bfad_im_port_s *im_port = container_of(work, struct bfad_im_port_s, port_delete_work); + struct bfad_s *bfad = im_port->bfad; if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { im_port->flags |= BFAD_PORT_DELETE; fc_vport_terminate(im_port->fc_vport); + atomic_dec(&bfad->wq_reqcnt); } } @@ -634,8 +636,11 @@ bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port) { struct bfad_im_port_s *im_port = port->im_port; - queue_work(bfad->im->drv_workq, + if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { + atomic_inc(&bfad->wq_reqcnt); + queue_work(bfad->im->drv_workq, &im_port->port_delete_work); + } } void @@ -696,6 +701,12 @@ void bfad_im_probe_undo(struct bfad_s *bfad) { if (bfad->im) { + while (atomic_read(&bfad->wq_reqcnt)) { + printk(KERN_INFO "bfa %s: waiting workq processing," + " wq_reqcnt:%x\n", bfad->pci_name, + atomic_read(&bfad->wq_reqcnt)); + schedule_timeout_uninterruptible(HZ); + } bfad_os_destroy_workq(bfad->im); kfree(bfad->im); bfad->im = NULL; -- cgit v1.2.3-70-g09d2 From 08a17ced7a78064f4f03de7d68b8cd32581f0510 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 20:02:31 -0700 Subject: [SCSI] bfa: update driver version string Update driver version to 2.2.2.1 Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfad_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index dcf28830fee..fb6ac1d3fd1 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -46,7 +46,7 @@ #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "2.1.2.1" +#define BFAD_DRIVER_VERSION "2.2.2.1" #endif -- cgit v1.2.3-70-g09d2 From ab2a9ba189e889b3e8990e52e90d2cd9606b2aa1 Mon Sep 17 00:00:00 2001 From: Jing Huang Date: Thu, 8 Jul 2010 20:02:55 -0700 Subject: [SCSI] bfa: add debugfs support - Add debugfs support to obtain firmware trace, driver trace and read/write to registers. - debugfs hierarchy: /sys/kernel/debug/bfa/host# where the host number corresponds to the one under /sys/class/scsi_host/host# - Following are the new debugfs entries added: drvtrc: collect current driver trace fwtrc: collect current firmware trace. fwsave: collect last saved fw trace as a result of firmware crash. regwr: write one word to chip register regrd: read one or more words from chip register. Signed-off-by: Jing Huang Signed-off-by: James Bottomley --- drivers/scsi/bfa/Makefile | 2 +- drivers/scsi/bfa/bfad.c | 12 + drivers/scsi/bfa/bfad_debugfs.c | 547 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/bfa/bfad_drv.h | 12 +- 4 files changed, 571 insertions(+), 2 deletions(-) create mode 100644 drivers/scsi/bfa/bfad_debugfs.c diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile index 17e06cae71b..ac3fdf02d5f 100644 --- a/drivers/scsi/bfa/Makefile +++ b/drivers/scsi/bfa/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_SCSI_BFA_FC) := bfa.o bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o - +bfa-y += bfad_debugfs.o bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index a17800e6277..915a29d6c7a 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -57,6 +57,7 @@ static int ipfc_enable = BFA_FALSE; static int fdmi_enable = BFA_TRUE; int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; int bfa_linkup_delay = -1; +int bfa_debugfs_enable = 1; module_param(os_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); @@ -106,6 +107,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for boot" module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1," " Range[false:0|true:1]"); +module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1," + " Range[false:0|true:1]"); /* * Stores the module parm num_sgpgs value; @@ -903,6 +907,10 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; } + /* Setup the debugfs node for this scsi_host */ + if (bfa_debugfs_enable) + bfad_debugfs_init(&bfad->pport); + bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; out: @@ -912,6 +920,10 @@ out: void bfad_uncfg_pport(struct bfad_s *bfad) { + /* Remove the debugfs node for this scsi_host */ + kfree(bfad->regdata); + bfad_debugfs_exit(&bfad->pport); + if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) { bfad_ipfc_port_delete(bfad, &bfad->pport); bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC; diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c new file mode 100644 index 00000000000..4b82f12aad6 --- /dev/null +++ b/drivers/scsi/bfa/bfad_debugfs.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. + * All rights reserved + * www.brocade.com + * + * Linux driver for Brocade Fibre Channel Host Bus Adapter. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License (GPL) Version 2 as + * published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include + +#include +#include + +/* + * BFA debufs interface + * + * To access the interface, debugfs file system should be mounted + * if not already mounted using: + * mount -t debugfs none /sys/kernel/debug + * + * BFA Hierarchy: + * - bfa/host# + * where the host number corresponds to the one under /sys/class/scsi_host/host# + * + * Debugging service available per host: + * fwtrc: To collect current firmware trace. + * drvtrc: To collect current driver trace + * fwsave: To collect last saved fw trace as a result of firmware crash. + * regwr: To write one word to chip register + * regrd: To read one or more words from chip register. + */ + +struct bfad_debug_info { + char *debug_buffer; + void *i_private; + int buffer_len; +}; + +static int +bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file) +{ + struct bfad_port_s *port = inode->i_private; + struct bfad_s *bfad = port->bfad; + struct bfad_debug_info *debug; + + debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + if (!debug) + return -ENOMEM; + + debug->debug_buffer = (void *) bfad->trcmod; + debug->buffer_len = sizeof(struct bfa_trc_mod_s); + + file->private_data = debug; + + return 0; +} + +static int +bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file) +{ + struct bfad_port_s *port = inode->i_private; + struct bfad_s *bfad = port->bfad; + struct bfad_debug_info *fw_debug; + unsigned long flags; + int rc; + + fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + if (!fw_debug) + return -ENOMEM; + + fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); + + fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); + if (!fw_debug->debug_buffer) { + kfree(fw_debug); + printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n", + bfad->inst_no); + return -ENOMEM; + } + + memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + rc = bfa_debug_fwtrc(&bfad->bfa, + fw_debug->debug_buffer, + &fw_debug->buffer_len); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (rc != BFA_STATUS_OK) { + vfree(fw_debug->debug_buffer); + fw_debug->debug_buffer = NULL; + kfree(fw_debug); + printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n", + bfad->inst_no); + return -ENOMEM; + } + + file->private_data = fw_debug; + + return 0; +} + +static int +bfad_debugfs_open_fwsave(struct inode *inode, struct file *file) +{ + struct bfad_port_s *port = inode->i_private; + struct bfad_s *bfad = port->bfad; + struct bfad_debug_info *fw_debug; + unsigned long flags; + int rc; + + fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + if (!fw_debug) + return -ENOMEM; + + fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); + + fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); + if (!fw_debug->debug_buffer) { + kfree(fw_debug); + printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n", + bfad->inst_no); + return -ENOMEM; + } + + memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); + + spin_lock_irqsave(&bfad->bfad_lock, flags); + rc = bfa_debug_fwsave(&bfad->bfa, + fw_debug->debug_buffer, + &fw_debug->buffer_len); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + if (rc != BFA_STATUS_OK) { + vfree(fw_debug->debug_buffer); + fw_debug->debug_buffer = NULL; + kfree(fw_debug); + printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n", + bfad->inst_no); + return -ENOMEM; + } + + file->private_data = fw_debug; + + return 0; +} + +static int +bfad_debugfs_open_reg(struct inode *inode, struct file *file) +{ + struct bfad_debug_info *reg_debug; + + reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); + if (!reg_debug) + return -ENOMEM; + + reg_debug->i_private = inode->i_private; + + file->private_data = reg_debug; + + return 0; +} + +/* Changes the current file position */ +static loff_t +bfad_debugfs_lseek(struct file *file, loff_t offset, int orig) +{ + struct bfad_debug_info *debug; + loff_t pos = file->f_pos; + + debug = file->private_data; + + switch (orig) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = debug->buffer_len - offset; + break; + default: + return -EINVAL; + } + + if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { + file->f_pos = pos; + return -EINVAL; + } + + return file->f_pos; +} + +static ssize_t +bfad_debugfs_read(struct file *file, char __user *buf, + size_t nbytes, loff_t *pos) +{ + struct bfad_debug_info *debug = file->private_data; + + if (!debug || !debug->debug_buffer) + return 0; + + return memory_read_from_buffer(buf, nbytes, pos, + debug->debug_buffer, debug->buffer_len); +} + +#define BFA_REG_CT_ADDRSZ (0x40000) +#define BFA_REG_CB_ADDRSZ (0x20000) +#define BFA_REG_ADDRSZ(__bfa) \ + ((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \ + BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ) +#define BFA_REG_ADDRMSK(__bfa) ((uint32_t)(BFA_REG_ADDRSZ(__bfa) - 1)) + +static bfa_status_t +bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) +{ + u8 area; + + /* check [16:15] */ + area = (offset >> 15) & 0x7; + if (area == 0) { + /* PCIe core register */ + if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ + return BFA_STATUS_EINVAL; + } else if (area == 0x1) { + /* CB 32 KB memory page */ + if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ + return BFA_STATUS_EINVAL; + } else { + /* CB register space 64KB */ + if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa)) + return BFA_STATUS_EINVAL; + } + return BFA_STATUS_OK; +} + +static ssize_t +bfad_debugfs_read_regrd(struct file *file, char __user *buf, + size_t nbytes, loff_t *pos) +{ + struct bfad_debug_info *regrd_debug = file->private_data; + struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; + struct bfad_s *bfad = port->bfad; + ssize_t rc; + + if (!bfad->regdata) + return 0; + + rc = memory_read_from_buffer(buf, nbytes, pos, + bfad->regdata, bfad->reglen); + + if ((*pos + nbytes) >= bfad->reglen) { + kfree(bfad->regdata); + bfad->regdata = NULL; + bfad->reglen = 0; + } + + return rc; +} + +static ssize_t +bfad_debugfs_write_regrd(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct bfad_debug_info *regrd_debug = file->private_data; + struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; + struct bfad_s *bfad = port->bfad; + struct bfa_s *bfa = &bfad->bfa; + struct bfa_ioc_s *ioc = &bfa->ioc; + int addr, len, rc, i; + u32 *regbuf; + void __iomem *rb, *reg_addr; + unsigned long flags; + + rc = sscanf(buf, "%x:%x", &addr, &len); + if (rc < 2) { + printk(KERN_INFO + "bfad[%d]: %s failed to read user buf\n", + bfad->inst_no, __func__); + return -EINVAL; + } + + kfree(bfad->regdata); + bfad->regdata = NULL; + bfad->reglen = 0; + + bfad->regdata = kzalloc(len << 2, GFP_KERNEL); + if (!bfad->regdata) { + printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n", + bfad->inst_no); + return -ENOMEM; + } + + bfad->reglen = len << 2; + rb = bfa_ioc_bar0(ioc); + addr &= BFA_REG_ADDRMSK(bfa); + + /* offset and len sanity check */ + rc = bfad_reg_offset_check(bfa, addr, len); + if (rc) { + printk(KERN_INFO "bfad[%d]: Failed reg offset check\n", + bfad->inst_no); + kfree(bfad->regdata); + bfad->regdata = NULL; + bfad->reglen = 0; + return -EINVAL; + } + + reg_addr = rb + addr; + regbuf = (u32 *)bfad->regdata; + spin_lock_irqsave(&bfad->bfad_lock, flags); + for (i = 0; i < len; i++) { + *regbuf = bfa_reg_read(reg_addr); + regbuf++; + reg_addr += sizeof(u32); + } + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return nbytes; +} + +static ssize_t +bfad_debugfs_write_regwr(struct file *file, const char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct bfad_debug_info *debug = file->private_data; + struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private; + struct bfad_s *bfad = port->bfad; + struct bfa_s *bfa = &bfad->bfa; + struct bfa_ioc_s *ioc = &bfa->ioc; + int addr, val, rc; + void __iomem *reg_addr; + unsigned long flags; + + rc = sscanf(buf, "%x:%x", &addr, &val); + if (rc < 2) { + printk(KERN_INFO + "bfad[%d]: %s failed to read user buf\n", + bfad->inst_no, __func__); + return -EINVAL; + } + + addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */ + + /* offset and len sanity check */ + rc = bfad_reg_offset_check(bfa, addr, 1); + if (rc) { + printk(KERN_INFO + "bfad[%d]: Failed reg offset check\n", + bfad->inst_no); + return -EINVAL; + } + + reg_addr = (uint32_t *) ((uint8_t *) bfa_ioc_bar0(ioc) + addr); + spin_lock_irqsave(&bfad->bfad_lock, flags); + bfa_reg_write(reg_addr, val); + spin_unlock_irqrestore(&bfad->bfad_lock, flags); + + return nbytes; +} + +static int +bfad_debugfs_release(struct inode *inode, struct file *file) +{ + struct bfad_debug_info *debug = file->private_data; + + if (!debug) + return 0; + + file->private_data = NULL; + kfree(debug); + return 0; +} + +static int +bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file) +{ + struct bfad_debug_info *fw_debug = file->private_data; + + if (!fw_debug) + return 0; + + if (fw_debug->debug_buffer) + vfree(fw_debug->debug_buffer); + + file->private_data = NULL; + kfree(fw_debug); + return 0; +} + +static const struct file_operations bfad_debugfs_op_drvtrc = { + .owner = THIS_MODULE, + .open = bfad_debugfs_open_drvtrc, + .llseek = bfad_debugfs_lseek, + .read = bfad_debugfs_read, + .release = bfad_debugfs_release, +}; + +static const struct file_operations bfad_debugfs_op_fwtrc = { + .owner = THIS_MODULE, + .open = bfad_debugfs_open_fwtrc, + .llseek = bfad_debugfs_lseek, + .read = bfad_debugfs_read, + .release = bfad_debugfs_release_fwtrc, +}; + +static const struct file_operations bfad_debugfs_op_fwsave = { + .owner = THIS_MODULE, + .open = bfad_debugfs_open_fwsave, + .llseek = bfad_debugfs_lseek, + .read = bfad_debugfs_read, + .release = bfad_debugfs_release_fwtrc, +}; + +static const struct file_operations bfad_debugfs_op_regrd = { + .owner = THIS_MODULE, + .open = bfad_debugfs_open_reg, + .llseek = bfad_debugfs_lseek, + .read = bfad_debugfs_read_regrd, + .write = bfad_debugfs_write_regrd, + .release = bfad_debugfs_release, +}; + +static const struct file_operations bfad_debugfs_op_regwr = { + .owner = THIS_MODULE, + .open = bfad_debugfs_open_reg, + .llseek = bfad_debugfs_lseek, + .write = bfad_debugfs_write_regwr, + .release = bfad_debugfs_release, +}; + +struct bfad_debugfs_entry { + const char *name; + mode_t mode; + const struct file_operations *fops; +}; + +static const struct bfad_debugfs_entry bfad_debugfs_files[] = { + { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, }, + { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, }, + { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, }, + { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, }, + { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, }, +}; + +static struct dentry *bfa_debugfs_root; +static atomic_t bfa_debugfs_port_count; + +inline void +bfad_debugfs_init(struct bfad_port_s *port) +{ + struct bfad_im_port_s *im_port = port->im_port; + struct bfad_s *bfad = im_port->bfad; + struct Scsi_Host *shost = im_port->shost; + const struct bfad_debugfs_entry *file; + char name[16]; + int i; + + if (!bfa_debugfs_enable) + return; + + /* Setup the BFA debugfs root directory*/ + if (!bfa_debugfs_root) { + bfa_debugfs_root = debugfs_create_dir("bfa", NULL); + atomic_set(&bfa_debugfs_port_count, 0); + if (!bfa_debugfs_root) { + printk(KERN_WARNING + "BFA debugfs root dir creation failed\n"); + goto err; + } + } + + /* + * Setup the host# directory for the port, + * corresponds to the scsi_host num of this port. + */ + snprintf(name, sizeof(name), "host%d", shost->host_no); + if (!port->port_debugfs_root) { + port->port_debugfs_root = + debugfs_create_dir(name, bfa_debugfs_root); + if (!port->port_debugfs_root) { + printk(KERN_WARNING + "BFA host root dir creation failed\n"); + goto err; + } + + atomic_inc(&bfa_debugfs_port_count); + + for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { + file = &bfad_debugfs_files[i]; + bfad->bfad_dentry_files[i] = + debugfs_create_file(file->name, + file->mode, + port->port_debugfs_root, + port, + file->fops); + if (!bfad->bfad_dentry_files[i]) { + printk(KERN_WARNING + "BFA host%d: create %s entry failed\n", + shost->host_no, file->name); + goto err; + } + } + } + +err: + return; +} + +inline void +bfad_debugfs_exit(struct bfad_port_s *port) +{ + struct bfad_im_port_s *im_port = port->im_port; + struct bfad_s *bfad = im_port->bfad; + int i; + + for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { + if (bfad->bfad_dentry_files[i]) { + debugfs_remove(bfad->bfad_dentry_files[i]); + bfad->bfad_dentry_files[i] = NULL; + } + } + + /* + * Remove the host# directory for the port, + * corresponds to the scsi_host num of this port. + */ + if (port->port_debugfs_root) { + debugfs_remove(port->port_debugfs_root); + port->port_debugfs_root = NULL; + atomic_dec(&bfa_debugfs_port_count); + } + + /* Remove the BFA debugfs root directory */ + if (atomic_read(&bfa_debugfs_port_count) == 0) { + debugfs_remove(bfa_debugfs_root); + bfa_debugfs_root = NULL; + } +} diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index fb6ac1d3fd1..465b8b86ec9 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -111,6 +111,9 @@ struct bfad_port_s { struct bfad_im_port_s *im_port; /* IM specific data */ struct bfad_tm_port_s *tm_port; /* TM specific data */ struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */ + + /* port debugfs specific data */ + struct dentry *port_debugfs_root; }; /* @@ -186,6 +189,10 @@ struct bfad_s { struct fc_host_statistics link_stats; struct list_head pbc_pcfg_list; atomic_t wq_reqcnt; + /* debugfs specific data */ + char *regdata; + u32 reglen; + struct dentry *bfad_dentry_files[5]; }; struct bfad_pcfg_s { @@ -276,7 +283,9 @@ void bfad_drv_uninit(struct bfad_s *bfad); void bfad_drv_log_level_set(struct bfad_s *bfad); bfa_status_t bfad_fc4_module_init(void); void bfad_fc4_module_exit(void); -int bfad_worker (void *ptr); +int bfad_worker(void *ptr); +void bfad_debugfs_init(struct bfad_port_s *port); +void bfad_debugfs_exit(struct bfad_port_s *port); void bfad_pci_remove(struct pci_dev *pdev); int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid); @@ -289,6 +298,7 @@ extern struct list_head bfad_list; extern int bfa_lun_queue_depth; extern int bfad_supported_fc4s; extern int bfa_linkup_delay; +extern int bfa_debugfs_enable; extern struct mutex bfad_mutex; #endif /* __BFAD_DRV_H__ */ -- cgit v1.2.3-70-g09d2 From e349fa35363fa96f11addecb67e0f8a6edfb0e3a Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:48:36 +0530 Subject: [SCSI] qla4xxx: set driver ddb state correctly in process_ddb_changed If fw ddb state is ACTIVE mark driver ddb stat as ONLINE and unblock iscsi session. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 5510df8a7fa..8947743e54d 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1487,7 +1487,10 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); if (old_fw_ddb_device_state == state && state == DDB_DS_SESSION_ACTIVE) { - /* Do nothing, state not changed. */ + if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + iscsi_unblock_session(ddb_entry->sess); + } return QLA_SUCCESS; } -- cgit v1.2.3-70-g09d2 From 363863256a711819130ea4ac210ee001bc80c3b2 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:49:01 +0530 Subject: [SCSI] qla4xxx: unblock iscsi session after setting ddb state online. Once the device goes *missing*, driver blocks the session ie iscsi_block_session() to stall the I/O. So after device comes back *online*, driver needs to unblock the session ie iscsi_unblock_session(), else I/Os will fail even if ddb_state is ONLINE. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 8947743e54d..16565226f55 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -993,6 +993,7 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha) DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked " "ONLINE\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); + iscsi_unblock_session(ddb_entry->sess); } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) qla4xxx_mark_device_missing(ha, ddb_entry); } -- cgit v1.2.3-70-g09d2 From b966346c344f592c8e6a84c9c274a7dedbc057ad Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:49:19 +0530 Subject: [SCSI] qla4xxx: correct return status in function qla4xxx_fw_ready Handle fw_state "auto discovery in progress" correctly to avoid marking adapter as offline. Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 16565226f55..d5254054b2c 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -399,6 +399,7 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: FW initialized, but " "auto-discovery still in process\n", ha->host_no, __func__)); + ready = 1; } return ready; -- cgit v1.2.3-70-g09d2 From beabe7c18338a5112fbca9a6dbcc921f9cce6325 Mon Sep 17 00:00:00 2001 From: Prasanna Mumbai Date: Sat, 10 Jul 2010 14:49:38 +0530 Subject: [SCSI] qla4xxx: Fix the freeing of the buffer allocated for DMA Fixed the DMA allocated memory freeing which wasn't taken care in many cases. Signed-off-by: Prasanna Mumbai Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 38 ++++++++++++++++++++++++-------------- drivers/scsi/qla4xxx/ql4_mbx.c | 15 ++++++++------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index d5254054b2c..4a332c32d71 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -444,17 +444,17 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, if (fw_ddb_entry == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); - return NULL; + goto exit_get_ddb_entry_no_free; } if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, fw_ddb_entry_dma, NULL, NULL, &device_state, NULL, NULL, NULL) == - QLA_ERROR) { + QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " "fw_ddb_index %d\n", ha->host_no, __func__, fw_ddb_index)); - return NULL; + goto exit_get_ddb_entry; } /* Allocate DDB if not already allocated. */ @@ -472,6 +472,7 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, } } + /* if not found allocate new ddb */ if (!found) { DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating " "new ddb\n", ha->host_no, __func__, @@ -480,10 +481,11 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index); } - /* if not found allocate new ddb */ +exit_get_ddb_entry: dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, fw_ddb_entry_dma); +exit_get_ddb_entry_no_free: return ddb_entry; } @@ -511,7 +513,8 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, if (ddb_entry == NULL) { DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no, __func__)); - goto exit_update_ddb; + + goto exit_update_ddb_no_free; } /* Make sure the dma buffer is valid */ @@ -522,7 +525,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); - goto exit_update_ddb; + goto exit_update_ddb_no_free; } if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry, @@ -530,7 +533,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, &ddb_entry->fw_ddb_device_state, &conn_err, &ddb_entry->tcp_source_port_num, &ddb_entry->connection_id) == - QLA_ERROR) { + QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for " "fw_ddb_index %d\n", ha->host_no, __func__, fw_ddb_index)); @@ -605,6 +608,7 @@ exit_update_ddb: dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, fw_ddb_entry_dma); +exit_update_ddb_no_free: return status; } @@ -689,7 +693,7 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) **/ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) { - int status = QLA_SUCCESS; + int status = QLA_ERROR; uint32_t fw_ddb_index = 0; uint32_t next_fw_ddb_index = 0; uint32_t ddb_state; @@ -705,7 +709,8 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) if (fw_ddb_entry == NULL) { DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", __func__)); - return QLA_ERROR; + + goto exit_build_ddb_list_no_free; } dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); @@ -720,7 +725,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: get_ddb_entry, " "fw_ddb_index %d failed", ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; + goto exit_build_ddb_list; } DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, " @@ -750,7 +755,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) "get_ddb_entry %d failed\n", ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; + goto exit_build_ddb_list; } } } @@ -770,7 +775,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: Unable to allocate memory " "for device at fw_ddb_index %d\n", ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; + goto exit_build_ddb_list; } /* Fill in the device structure */ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) == @@ -778,11 +783,10 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) ha->fw_ddb_index_map[fw_ddb_index] = (struct ddb_entry *)INVALID_ENTRY; - DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed " "for fw_ddb_index %d.\n", ha->host_no, __func__, fw_ddb_index)); - return QLA_ERROR; + goto exit_build_ddb_list; } next_one: @@ -792,8 +796,14 @@ next_one: break; } + status = QLA_SUCCESS; dev_info(&ha->pdev->dev, "DDB list done..\n"); +exit_build_ddb_list: + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, + fw_ddb_entry_dma); + +exit_build_ddb_list_no_free: return status; } diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 75496fb0ae7..54db6cbbd94 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -317,7 +317,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) if (init_fw_cb == NULL) { DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, __func__)); - return 10; + goto exit_init_fw_cb_no_free; } memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); @@ -373,7 +373,7 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) exit_init_fw_cb: dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), init_fw_cb, init_fw_cb_dma); - +exit_init_fw_cb_no_free: return status; } @@ -394,7 +394,7 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) if (init_fw_cb == NULL) { printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, __func__); - return 10; + return QLA_ERROR; } /* Get Initialize Firmware Control Block. */ @@ -1019,16 +1019,16 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); ret_val = QLA_ERROR; - goto qla4xxx_send_tgts_exit; + goto exit_send_tgts_no_free; } ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); if (ret_val != QLA_SUCCESS) - goto qla4xxx_send_tgts_exit; + goto exit_send_tgts; ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index); if (ret_val != QLA_SUCCESS) - goto qla4xxx_send_tgts_exit; + goto exit_send_tgts; memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias)); @@ -1050,9 +1050,10 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma); -qla4xxx_send_tgts_exit: +exit_send_tgts: dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, fw_ddb_entry_dma); +exit_send_tgts_no_free: return ret_val; } -- cgit v1.2.3-70-g09d2 From dbaf82ece08bf93ae5200f03efd87c4f1fc453f1 Mon Sep 17 00:00:00 2001 From: Ravi Anand Date: Sat, 10 Jul 2010 14:50:32 +0530 Subject: [SCSI] qla4xxx: Handle one H/W Interrupt at a time Handle one H/W Interrupt at a time to prevent holding off H/W lock for longer period of time. Signed-off-by: Ravi Anand Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 428802616e3..3e1c990f5e2 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -118,7 +118,7 @@ #define DRIVER_NAME "qla4xxx" #define MAX_LINKED_CMDS_PER_LUN 3 -#define MAX_REQS_SERVICED_PER_INTR 16 +#define MAX_REQS_SERVICED_PER_INTR 1 #define ISCSI_IPADDR_SIZE 4 /* IP address size */ #define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ -- cgit v1.2.3-70-g09d2 From f4f5df23bf72208d0c2f1d8be629839924c2f4c2 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Wed, 28 Jul 2010 15:53:44 +0530 Subject: [SCSI] qla4xxx: Added support for ISP82XX Signed-off-by: Vikas Chaudhary Signed-off-by: Karen Higgins Signed-off-by: Ravi Anand Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/Kconfig | 8 +- drivers/scsi/qla4xxx/Makefile | 2 +- drivers/scsi/qla4xxx/ql4_def.h | 141 ++- drivers/scsi/qla4xxx/ql4_fw.h | 139 ++- drivers/scsi/qla4xxx/ql4_glbl.h | 106 +- drivers/scsi/qla4xxx/ql4_init.c | 136 ++- drivers/scsi/qla4xxx/ql4_inline.h | 2 +- drivers/scsi/qla4xxx/ql4_iocb.c | 73 +- drivers/scsi/qla4xxx/ql4_isr.c | 388 ++++++- drivers/scsi/qla4xxx/ql4_mbx.c | 172 ++- drivers/scsi/qla4xxx/ql4_nvram.c | 2 +- drivers/scsi/qla4xxx/ql4_nvram.h | 10 +- drivers/scsi/qla4xxx/ql4_nx.c | 2321 +++++++++++++++++++++++++++++++++++++ drivers/scsi/qla4xxx/ql4_nx.h | 779 +++++++++++++ drivers/scsi/qla4xxx/ql4_os.c | 678 ++++++++--- 15 files changed, 4600 insertions(+), 357 deletions(-) create mode 100644 drivers/scsi/qla4xxx/ql4_nx.c create mode 100644 drivers/scsi/qla4xxx/ql4_nx.h diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig index 69cbff3f57c..2c33ce6eac1 100644 --- a/drivers/scsi/qla4xxx/Kconfig +++ b/drivers/scsi/qla4xxx/Kconfig @@ -1,7 +1,7 @@ config SCSI_QLA_ISCSI - tristate "QLogic ISP4XXX host adapter family support" - depends on PCI && SCSI && NET + tristate "QLogic ISP4XXX and ISP82XX host adapter family support" + depends on PCI && SCSI select SCSI_ISCSI_ATTRS ---help--- - This driver supports the QLogic 40xx (ISP4XXX) iSCSI host - adapter family. + This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX) + iSCSI host adapter family. diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile index 86ea37baa0f..0339ff03a53 100644 --- a/drivers/scsi/qla4xxx/Makefile +++ b/drivers/scsi/qla4xxx/Makefile @@ -1,5 +1,5 @@ qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ - ql4_nvram.o ql4_dbg.o + ql4_nx.o ql4_nvram.o ql4_dbg.o obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 3e1c990f5e2..a79da8dd206 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -33,6 +33,8 @@ #include #include +#include "ql4_dbg.h" +#include "ql4_nx.h" #ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 #define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 @@ -46,6 +48,10 @@ #define PCI_DEVICE_ID_QLOGIC_ISP4032 0x4032 #endif +#ifndef PCI_DEVICE_ID_QLOGIC_ISP8022 +#define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 +#endif + #define QLA_SUCCESS 0 #define QLA_ERROR 1 @@ -85,15 +91,22 @@ #define BIT_30 0x40000000 #define BIT_31 0x80000000 +/** + * Macros to help code, maintain, etc. + **/ +#define ql4_printk(level, ha, format, arg...) \ + dev_printk(level , &((ha)->pdev->dev) , format , ## arg) + + /* * Host adapter default definitions ***********************************/ #define MAX_HBAS 16 #define MAX_BUSES 1 -#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_TARGETS MAX_DEV_DB_ENTRIES #define MAX_LUNS 0xffff #define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */ -#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES) +#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES #define MAX_PDU_ENTRIES 32 #define INVALID_ENTRY 0xFFFF #define MAX_CMDS_TO_RISC 1024 @@ -134,7 +147,7 @@ #define SOFT_RESET_TOV 30 #define RESET_INTR_TOV 3 #define SEMAPHORE_TOV 10 -#define ADAPTER_INIT_TOV 120 +#define ADAPTER_INIT_TOV 30 #define ADAPTER_RESET_TOV 180 #define EXTEND_CMD_TOV 60 #define WAIT_CMD_TOV 30 @@ -184,8 +197,6 @@ struct srb { uint16_t iocb_tov; uint16_t iocb_cnt; /* Number of used iocbs */ uint16_t cc_stat; - u_long r_start; /* Time we recieve a cmd from OS */ - u_long u_start; /* Time when we handed the cmd to F/W */ /* Used for extended sense / status continuation */ uint8_t *req_sense_ptr; @@ -221,7 +232,6 @@ struct ddb_entry { unsigned long dev_scan_wait_to_start_relogin; unsigned long dev_scan_wait_to_complete_relogin; - uint16_t os_target_id; /* Target ID */ uint16_t fw_ddb_index; /* DDB firmware index */ uint16_t options; uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ @@ -285,6 +295,67 @@ struct ddb_entry { #include "ql4_fw.h" #include "ql4_nvram.h" +struct ql82xx_hw_data { + /* Offsets for flash/nvram access (set to ~0 if not used). */ + uint32_t flash_conf_off; + uint32_t flash_data_off; + + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; + uint32_t fdt_unprotect_sec_cmd; + uint32_t fdt_protect_sec_cmd; + + uint32_t flt_region_flt; + uint32_t flt_region_fdt; + uint32_t flt_region_boot; + uint32_t flt_region_bootload; + uint32_t flt_region_fw; + uint32_t reserved; +}; + +struct qla4_8xxx_legacy_intr_set { + uint32_t int_vec_bit; + uint32_t tgt_status_reg; + uint32_t tgt_mask_reg; + uint32_t pci_int_reg; +}; + +/* MSI-X Support */ + +#define QLA_MSIX_DEFAULT 0x00 +#define QLA_MSIX_RSP_Q 0x01 + +#define QLA_MSIX_ENTRIES 2 +#define QLA_MIDX_DEFAULT 0 +#define QLA_MIDX_RSP_Q 1 + +struct ql4_msix_entry { + int have_irq; + uint16_t msix_vector; + uint16_t msix_entry; +}; + +/* + * ISP Operations + */ +struct isp_operations { + int (*iospace_config) (struct scsi_qla_host *ha); + void (*pci_config) (struct scsi_qla_host *); + void (*disable_intrs) (struct scsi_qla_host *); + void (*enable_intrs) (struct scsi_qla_host *); + int (*start_firmware) (struct scsi_qla_host *); + irqreturn_t (*intr_handler) (int , void *); + void (*interrupt_service_routine) (struct scsi_qla_host *, uint32_t); + int (*reset_chip) (struct scsi_qla_host *); + int (*reset_firmware) (struct scsi_qla_host *); + void (*queue_iocb) (struct scsi_qla_host *); + void (*complete_iocb) (struct scsi_qla_host *); + uint16_t (*rd_shdw_req_q_out) (struct scsi_qla_host *); + uint16_t (*rd_shdw_rsp_q_in) (struct scsi_qla_host *); + int (*get_sys_info) (struct scsi_qla_host *); +}; + /* * Linux Host Adapter structure */ @@ -296,28 +367,39 @@ struct scsi_qla_host { #define AF_INIT_DONE 1 /* 0x00000002 */ #define AF_MBOX_COMMAND 2 /* 0x00000004 */ #define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ +#define AF_DPC_SCHEDULED 5 /* 0x00000020 */ #define AF_INTERRUPTS_ON 6 /* 0x00000040 */ #define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ #define AF_LINK_UP 8 /* 0x00000100 */ #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ +#define AF_HBA_GOING_AWAY 12 /* 0x00001000 */ +#define AF_INTx_ENABLED 15 /* 0x00008000 */ +#define AF_MSI_ENABLED 16 /* 0x00010000 */ +#define AF_MSIX_ENABLED 17 /* 0x00020000 */ +#define AF_MBOX_COMMAND_NOPOLL 18 /* 0x00040000 */ + unsigned long dpc_flags; #define DPC_RESET_HA 1 /* 0x00000002 */ #define DPC_RETRY_RESET_HA 2 /* 0x00000004 */ #define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */ -#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */ +#define DPC_RESET_HA_FW_CONTEXT 4 /* 0x00000010 */ #define DPC_RESET_HA_INTR 5 /* 0x00000020 */ #define DPC_ISNS_RESTART 7 /* 0x00000080 */ #define DPC_AEN 9 /* 0x00000200 */ #define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ #define DPC_LINK_CHANGED 18 /* 0x00040000 */ +#define DPC_RESET_ACTIVE 20 /* 0x00040000 */ +#define DPC_HA_UNRECOVERABLE 21 /* 0x00080000 ISP-82xx only*/ +#define DPC_HA_NEED_QUIESCENT 22 /* 0x00100000 ISP-82xx only*/ + struct Scsi_Host *host; /* pointer to host data */ uint32_t tot_ddbs; - uint16_t iocb_cnt; + uint16_t iocb_cnt; /* SRB cache. */ #define SRB_MIN_REQ 128 @@ -332,14 +414,13 @@ struct scsi_qla_host { #define MIN_IOBASE_LEN 0x100 uint16_t req_q_count; - uint8_t rsvd1[2]; unsigned long host_no; /* NVRAM registers */ struct eeprom_data *nvram; spinlock_t hardware_lock ____cacheline_aligned; - uint32_t eeprom_cmd_data; + uint32_t eeprom_cmd_data; /* Counters for general statistics */ uint64_t isr_count; @@ -375,7 +456,6 @@ struct scsi_qla_host { uint8_t alias[32]; uint8_t name_string[256]; uint8_t heartbeat_interval; - uint8_t rsvd; /* --- From FlashSysInfo --- */ uint8_t my_mac[MAC_ADDR_LEN]; @@ -469,6 +549,40 @@ struct scsi_qla_host { struct in6_addr ipv6_addr0; struct in6_addr ipv6_addr1; struct in6_addr ipv6_default_router_addr; + + /* qla82xx specific fields */ + struct device_reg_82xx __iomem *qla4_8xxx_reg; /* Base I/O address */ + unsigned long nx_pcibase; /* Base I/O address */ + uint8_t *nx_db_rd_ptr; /* Doorbell read pointer */ + unsigned long nx_db_wr_ptr; /* Door bell write pointer */ + unsigned long first_page_group_start; + unsigned long first_page_group_end; + + uint32_t crb_win; + uint32_t curr_window; + uint32_t ddr_mn_window; + unsigned long mn_win_crb; + unsigned long ms_win_crb; + int qdr_sn_window; + rwlock_t hw_lock; + uint16_t func_num; + int link_width; + + struct qla4_8xxx_legacy_intr_set nx_legacy_intr; + u32 nx_crb_mask; + + uint8_t revision_id; + uint32_t fw_heartbeat_counter; + + struct isp_operations *isp_ops; + struct ql82xx_hw_data hw; + + struct ql4_msix_entry msix_entries[QLA_MSIX_ENTRIES]; + + uint32_t nx_dev_init_timeout; + uint32_t nx_reset_timeout; + + struct completion mbx_intr_comp; }; static inline int is_ipv4_enabled(struct scsi_qla_host *ha) @@ -496,6 +610,11 @@ static inline int is_qla4032(struct scsi_qla_host *ha) return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032; } +static inline int is_qla8022(struct scsi_qla_host *ha) +{ + return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; +} + static inline int adapter_up(struct scsi_qla_host *ha) { return (test_bit(AF_ONLINE, &ha->flags) != 0) && diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index 855226e0866..c94c9ddfb3a 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -11,7 +11,7 @@ #define MAX_PRST_DEV_DB_ENTRIES 64 #define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES -#define MAX_DEV_DB_ENTRIES 512 +#define MAX_DEV_DB_ENTRIES 512 /************************************************************************* * @@ -37,6 +37,33 @@ struct host_mem_cfg_regs { __le32 rsrvd1[31]; /* 0x84-0xFF */ }; +/* + * ISP 82xx I/O Register Set structure definitions. + */ +struct device_reg_82xx { + __le32 req_q_out; /* 0x0000 (R): Request Queue out-Pointer. */ + __le32 reserve1[63]; /* Request Queue out-Pointer. (64 * 4) */ + __le32 rsp_q_in; /* 0x0100 (R/W): Response Queue In-Pointer. */ + __le32 reserve2[63]; /* Response Queue In-Pointer. */ + __le32 rsp_q_out; /* 0x0200 (R/W): Response Queue Out-Pointer. */ + __le32 reserve3[63]; /* Response Queue Out-Pointer. */ + + __le32 mailbox_in[8]; /* 0x0300 (R/W): Mail box In registers */ + __le32 reserve4[24]; + __le32 hint; /* 0x0380 (R/W): Host interrupt register */ +#define HINT_MBX_INT_PENDING BIT_0 + __le32 reserve5[31]; + __le32 mailbox_out[8]; /* 0x0400 (R): Mail box Out registers */ + __le32 reserve6[56]; + + __le32 host_status; /* Offset 0x500 (R): host status */ +#define HSRX_RISC_MB_INT BIT_0 /* RISC to Host Mailbox interrupt */ +#define HSRX_RISC_IOCB_INT BIT_1 /* RISC to Host IOCB interrupt */ + + __le32 host_int; /* Offset 0x0504 (R/W): Interrupt status. */ +#define ISRX_82XX_RISC_INT BIT_0 /* RISC interrupt. */ +}; + /* remote register set (access via PCI memory read/write) */ struct isp_reg { #define MBOX_REG_COUNT 8 @@ -206,6 +233,79 @@ union external_hw_config_reg { uint32_t Asuint32_t; }; +/* 82XX Support start */ +/* 82xx Default FLT Addresses */ +#define FA_FLASH_LAYOUT_ADDR_82 0xFC400 +#define FA_FLASH_DESCR_ADDR_82 0xFC000 +#define FA_BOOT_LOAD_ADDR_82 0x04000 +#define FA_BOOT_CODE_ADDR_82 0x20000 +#define FA_RISC_CODE_ADDR_82 0x40000 +#define FA_GOLD_RISC_CODE_ADDR_82 0x80000 + +/* Flash Description Table */ +struct qla_fdt_layout { + uint8_t sig[4]; + uint16_t version; + uint16_t len; + uint16_t checksum; + uint8_t unused1[2]; + uint8_t model[16]; + uint16_t man_id; + uint16_t id; + uint8_t flags; + uint8_t erase_cmd; + uint8_t alt_erase_cmd; + uint8_t wrt_enable_cmd; + uint8_t wrt_enable_bits; + uint8_t wrt_sts_reg_cmd; + uint8_t unprotect_sec_cmd; + uint8_t read_man_id_cmd; + uint32_t block_size; + uint32_t alt_block_size; + uint32_t flash_size; + uint32_t wrt_enable_data; + uint8_t read_id_addr_len; + uint8_t wrt_disable_bits; + uint8_t read_dev_id_len; + uint8_t chip_erase_cmd; + uint16_t read_timeout; + uint8_t protect_sec_cmd; + uint8_t unused2[65]; +}; + +/* Flash Layout Table */ + +struct qla_flt_location { + uint8_t sig[4]; + uint16_t start_lo; + uint16_t start_hi; + uint8_t version; + uint8_t unused[5]; + uint16_t checksum; +}; + +struct qla_flt_header { + uint16_t version; + uint16_t length; + uint16_t checksum; + uint16_t unused; +}; + +/* 82xx FLT Regions */ +#define FLT_REG_FDT 0x1a +#define FLT_REG_FLT 0x1c +#define FLT_REG_BOOTLOAD_82 0x72 +#define FLT_REG_FW_82 0x74 +#define FLT_REG_GOLD_FW_82 0x75 +#define FLT_REG_BOOT_CODE_82 0x78 + +struct qla_flt_region { + uint32_t code; + uint32_t size; + uint32_t start; + uint32_t end; +}; + /************************************************************************* * * Mailbox Commands Structures and Definitions @@ -215,6 +315,10 @@ union external_hw_config_reg { /* Mailbox command definitions */ #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_PING 0x000B +#define MBOX_CMD_ENABLE_INTRS 0x0010 +#define INTR_DISABLE 0 +#define INTR_ENABLE 1 +#define MBOX_CMD_STOP_FW 0x0014 #define MBOX_CMD_ABORT_TASK 0x0015 #define MBOX_CMD_LUN_RESET 0x0016 #define MBOX_CMD_TARGET_WARM_RESET 0x0017 @@ -243,6 +347,7 @@ union external_hw_config_reg { #define DDB_DS_LOGIN_IN_PROCESS 0x07 #define MBOX_CMD_GET_FW_STATE 0x0069 #define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A +#define MBOX_CMD_GET_SYS_INFO 0x0078 #define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087 #define MBOX_CMD_SET_ACB 0x0088 #define MBOX_CMD_GET_ACB 0x0089 @@ -318,6 +423,15 @@ union external_hw_config_reg { #define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022 #define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027 +/* ACB State Defines */ +#define ACB_STATE_UNCONFIGURED 0x00 +#define ACB_STATE_INVALID 0x01 +#define ACB_STATE_ACQUIRING 0x02 +#define ACB_STATE_TENTATIVE 0x03 +#define ACB_STATE_DEPRICATED 0x04 +#define ACB_STATE_VALID 0x05 +#define ACB_STATE_DISABLING 0x06 + /*************************************************************************/ /* Host Adapter Initialization Control Block (from host) */ @@ -558,6 +672,20 @@ struct flash_sys_info { uint32_t reserved1[39]; /* 170-1ff */ }; /* 200 */ +struct mbx_sys_info { + uint8_t board_id_str[16]; /* Keep board ID string first */ + /* in this structure for GUI. */ + uint16_t board_id; /* board ID code */ + uint16_t phys_port_cnt; /* number of physical network ports */ + uint16_t port_num; /* network port for this PCI function */ + /* (port 0 is first port) */ + uint8_t mac_addr[6]; /* MAC address for this PCI function */ + uint32_t iscsi_pci_func_cnt; /* number of iSCSI PCI functions */ + uint32_t pci_func; /* this PCI function */ + unsigned char serial_number[16]; /* serial number string */ + uint8_t reserved[16]; +}; + struct crash_record { uint16_t fw_major_version; /* 00 - 01 */ uint16_t fw_minor_version; /* 02 - 03 */ @@ -814,4 +942,13 @@ struct passthru_status { uint8_t res4[16]; /* 30-3F */ }; +/* + * ISP queue - response queue entry definition. + */ +struct response { + uint8_t data[60]; + uint32_t signature; +#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ +}; + #endif /* _QLA4X_FW_H */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index c4636f6cb3c..c9cd5d6db98 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -10,31 +10,32 @@ struct iscsi_cls_conn; -void qla4xxx_hw_reset(struct scsi_qla_host *ha); +int qla4xxx_hw_reset(struct scsi_qla_host *ha); int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port); -int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb); -int qla4xxx_initialize_adapter(struct scsi_qla_host * ha, +int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb); +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, uint8_t renew_ddb_list); int qla4xxx_soft_reset(struct scsi_qla_host *ha); irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); -void qla4xxx_free_ddb_list(struct scsi_qla_host * ha); -void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen); +void qla4xxx_free_ddb_list(struct scsi_qla_host *ha); +void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); +void qla4xxx_process_aen(struct scsi_qla_host *ha, uint8_t process_aen); -int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha); -int qla4xxx_relogin_device(struct scsi_qla_host * ha, - struct ddb_entry * ddb_entry); +int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host *ha); +int qla4xxx_relogin_device(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, +int qla4xxx_reset_lun(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, int lun); -int qla4xxx_reset_target(struct scsi_qla_host * ha, - struct ddb_entry * ddb_entry); -int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, +int qla4xxx_reset_target(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); +int qla4xxx_get_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len); -int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); -int qla4xxx_get_firmware_state(struct scsi_qla_host * ha); -int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha); +int qla4xxx_get_firmware_status(struct scsi_qla_host *ha); +int qla4xxx_get_firmware_state(struct scsi_qla_host *ha); +int qla4xxx_initialize_fw_cb(struct scsi_qla_host *ha); /* FIXME: Goodness! this really wants a small struct to hold the * parameters. On x86 the args will get passed on the stack! */ @@ -54,20 +55,20 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); -u16 rd_nvram_word(struct scsi_qla_host * ha, int offset); -void qla4xxx_get_crash_record(struct scsi_qla_host * ha); +u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); +void qla4xxx_get_crash_record(struct scsi_qla_host *ha); struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha); int qla4xxx_add_sess(struct ddb_entry *); void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry); -int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha); +int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha); int qla4xxx_get_fw_version(struct scsi_qla_host * ha); -void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, +void qla4xxx_interrupt_service_routine(struct scsi_qla_host *ha, uint32_t intr_status); -int qla4xxx_init_rings(struct scsi_qla_host * ha); -struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, - uint32_t index); +int qla4xxx_init_rings(struct scsi_qla_host *ha); void qla4xxx_srb_compl(struct kref *ref); -int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); +struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, + uint32_t index); +int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha); int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t state, uint32_t conn_error); void qla4xxx_dump_buffer(void *b, uint32_t size); @@ -75,8 +76,65 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err); +int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); + +void qla4xxx_queue_iocb(struct scsi_qla_host *ha); +void qla4xxx_complete_iocb(struct scsi_qla_host *ha); +int qla4xxx_get_sys_info(struct scsi_qla_host *ha); +int qla4xxx_iospace_config(struct scsi_qla_host *ha); +void qla4xxx_pci_config(struct scsi_qla_host *ha); +int qla4xxx_start_firmware(struct scsi_qla_host *ha); +irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); +uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha); +uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); +int qla4xxx_request_irqs(struct scsi_qla_host *ha); +void qla4xxx_free_irqs(struct scsi_qla_host *ha); +void qla4xxx_process_response_queue(struct scsi_qla_host *ha); +void qla4xxx_wake_dpc(struct scsi_qla_host *ha); +void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); + +void qla4_8xxx_pci_config(struct scsi_qla_host *); +int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); +int qla4_8xxx_load_risc(struct scsi_qla_host *); +irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id); +void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha); +void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha); + +int qla4_8xxx_crb_win_lock(struct scsi_qla_host *); +void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *); +int qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *); +void qla4_8xxx_wr_32(struct scsi_qla_host *, ulong, u32); +int qla4_8xxx_rd_32(struct scsi_qla_host *, ulong); +int qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *, u64, void *, int); +int qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, u64, void *, int); +int qla4_8xxx_isp_reset(struct scsi_qla_host *ha); +void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha, + uint32_t intr_status); +uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha); +uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); +int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha); +void qla4_8xxx_watchdog(struct scsi_qla_host *ha); +int qla4_8xxx_stop_firmware(struct scsi_qla_host *ha); +int qla4_8xxx_get_flash_info(struct scsi_qla_host *ha); +void qla4_8xxx_enable_intrs(struct scsi_qla_host *ha); +void qla4_8xxx_disable_intrs(struct scsi_qla_host *ha); +int qla4_8xxx_enable_msix(struct scsi_qla_host *ha); +void qla4_8xxx_disable_msix(struct scsi_qla_host *ha); +irqreturn_t qla4_8xxx_msi_handler(int irq, void *dev_id); +irqreturn_t qla4_8xxx_default_intr_handler(int irq, void *dev_id); +irqreturn_t qla4_8xxx_msix_rsp_q(int irq, void *dev_id); +void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha); +void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha); +int qla4_8xxx_idc_lock(struct scsi_qla_host *ha); +void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha); +int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha); +void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha); +void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); + extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; extern int ql4xdontresethba; -extern int ql4_mod_unload; +extern int ql4xenablemsix; + #endif /* _QLA4x_GBL_H */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 4a332c32d71..539546df037 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -11,8 +11,8 @@ #include "ql4_dbg.h" #include "ql4_inline.h" -static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, - uint32_t fw_ddb_index); +static struct ddb_entry *qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + uint32_t fw_ddb_index); static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) { @@ -51,8 +51,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) * This routine deallocates and unlinks the specified ddb_entry from the * adapter's **/ -static void qla4xxx_free_ddb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) +void qla4xxx_free_ddb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) { /* Remove device entry from list */ list_del_init(&ddb_entry->list); @@ -85,6 +85,25 @@ void qla4xxx_free_ddb_list(struct scsi_qla_host *ha) } } +/** + * qla4xxx_init_response_q_entries() - Initializes response queue entries. + * @ha: HA context + * + * Beginning of request ring has initialization control block already built + * by nvram config routine. + **/ +static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) +{ + uint16_t cnt; + struct response *pkt; + + pkt = (struct response *)ha->response_ptr; + for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) { + pkt->signature = RESPONSE_PROCESSED; + pkt++; + } +} + /** * qla4xxx_init_rings - initialize hw queues * @ha: pointer to host adapter structure. @@ -109,19 +128,31 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) ha->response_out = 0; ha->response_ptr = &ha->response_ring[ha->response_out]; - /* - * Initialize DMA Shadow registers. The firmware is really supposed to - * take care of this, but on some uniprocessor systems, the shadow - * registers aren't cleared-- causing the interrupt_handler to think - * there are responses to be processed when there aren't. - */ - ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0); - ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0); - wmb(); + if (is_qla8022(ha)) { + writel(0, + (unsigned long __iomem *)&ha->qla4_8xxx_reg->req_q_out); + writel(0, + (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_in); + writel(0, + (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_out); + } else { + /* + * Initialize DMA Shadow registers. The firmware is really + * supposed to take care of this, but on some uniprocessor + * systems, the shadow registers aren't cleared-- causing + * the interrupt_handler to think there are responses to be + * processed when there aren't. + */ + ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0); + ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0); + wmb(); - writel(0, &ha->reg->req_q_in); - writel(0, &ha->reg->rsp_q_out); - readl(&ha->reg->rsp_q_out); + writel(0, &ha->reg->req_q_in); + writel(0, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); + } + + qla4xxx_init_response_q_entries(ha); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -129,11 +160,11 @@ int qla4xxx_init_rings(struct scsi_qla_host *ha) } /** - * qla4xxx_validate_mac_address - validate adapter MAC address(es) + * qla4xxx_get_sys_info - validate adapter MAC address(es) * @ha: pointer to host adapter structure. * **/ -static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) +int qla4xxx_get_sys_info(struct scsi_qla_host *ha) { struct flash_sys_info *sys_info; dma_addr_t sys_info_dma; @@ -145,7 +176,7 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", ha->host_no, __func__)); - goto exit_validate_mac_no_free; + goto exit_get_sys_info_no_free; } memset(sys_info, 0, sizeof(*sys_info)); @@ -155,7 +186,7 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO " "failed\n", ha->host_no, __func__)); - goto exit_validate_mac; + goto exit_get_sys_info; } /* Save M.A.C. address & serial_number */ @@ -168,11 +199,11 @@ static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha) status = QLA_SUCCESS; - exit_validate_mac: +exit_get_sys_info: dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, sys_info_dma); - exit_validate_mac_no_free: +exit_get_sys_info_no_free: return status; } @@ -584,21 +615,19 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, min(sizeof(ddb_entry->link_local_ipv6_addr), sizeof(fw_ddb_entry->link_local_ipv6_addr))); - DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " - "State %04x ConnErr %08x IP %pI6 " + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x" + " ConnErr %08x IP %pI6 " ":%04d \"%s\"\n", __func__, fw_ddb_index, - ddb_entry->os_target_id, ddb_entry->fw_ddb_device_state, conn_err, fw_ddb_entry->ip_addr, le16_to_cpu(fw_ddb_entry->port), fw_ddb_entry->iscsi_name)); } else - DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d " - "State %04x ConnErr %08x IP %pI4 " + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB[%d] State %04x" + " ConnErr %08x IP %pI4 " ":%04d \"%s\"\n", __func__, fw_ddb_index, - ddb_entry->os_target_id, ddb_entry->fw_ddb_device_state, conn_err, fw_ddb_entry->ip_addr, le16_to_cpu(fw_ddb_entry->port), @@ -984,7 +1013,7 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) } /** - * qla4xxx_update_ddb_list - update the driver ddb list + * qla4xxx_reinitialize_ddb_list - update the driver ddb list * @ha: pointer to host adapter structure. * * This routine obtains device information from the F/W database after @@ -1028,7 +1057,7 @@ int qla4xxx_relogin_device(struct scsi_qla_host *ha, (uint16_t)RELOGIN_TOV); atomic_set(&ddb_entry->relogin_timer, relogin_timer); - DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, + DEBUG2(printk("scsi%ld: Relogin ddb [%d]. TOV=%d\n", ha->host_no, ddb_entry->fw_ddb_index, relogin_timer)); qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0); @@ -1085,7 +1114,16 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha) return QLA_SUCCESS; } -static void qla4x00_pci_config(struct scsi_qla_host *ha) +/** + * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers. + * @ha: HA context + */ +void qla4_8xxx_pci_config(struct scsi_qla_host *ha) +{ + pci_set_master(ha->pdev); +} + +void qla4xxx_pci_config(struct scsi_qla_host *ha) { uint16_t w; int status; @@ -1216,7 +1254,7 @@ int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) * This routine performs the necessary steps to start the firmware for * the QLA4010 adapter. **/ -static int qla4xxx_start_firmware(struct scsi_qla_host *ha) +int qla4xxx_start_firmware(struct scsi_qla_host *ha) { unsigned long flags = 0; uint32_t mbox_status; @@ -1295,7 +1333,8 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) if (soft_reset) { DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no, __func__)); - status = qla4xxx_soft_reset(ha); + status = qla4xxx_soft_reset(ha); /* NOTE: acquires drvr + * lock again, but ok */ if (status == QLA_ERROR) { DEBUG(printk("scsi%d: %s: Soft Reset failed!\n", ha->host_no, __func__)); @@ -1316,7 +1355,6 @@ static int qla4xxx_start_firmware(struct scsi_qla_host *ha) ql4xxx_unlock_drvr(ha); if (status == QLA_SUCCESS) { - qla4xxx_get_fw_version(ha); if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) qla4xxx_get_crash_record(ha); } else { @@ -1343,18 +1381,21 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int status = QLA_ERROR; int8_t ip_address[IP_ADDR_LEN] = {0} ; - clear_bit(AF_ONLINE, &ha->flags); ha->eeprom_cmd_data = 0; - qla4x00_pci_config(ha); + ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); + ha->isp_ops->pci_config(ha); - qla4xxx_disable_intrs(ha); + ha->isp_ops->disable_intrs(ha); /* Initialize the Host adapter request/response queues and firmware */ - if (qla4xxx_start_firmware(ha) == QLA_ERROR) + if (ha->isp_ops->start_firmware(ha) == QLA_ERROR) + goto exit_init_hba; + + if (qla4xxx_get_fw_version(ha) == QLA_ERROR) goto exit_init_hba; - if (qla4xxx_validate_mac_address(ha) == QLA_ERROR) + if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR) goto exit_init_hba; if (qla4xxx_init_local_data(ha) == QLA_ERROR) @@ -1407,6 +1448,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, exit_init_online: set_bit(AF_ONLINE, &ha->flags); exit_init_hba: + DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no, + status == QLA_ERROR ? "FAILED" : "SUCCEDED")); return status; } @@ -1558,9 +1601,20 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, atomic_set(&ddb_entry->relogin_timer, 0); atomic_set(&ddb_entry->retry_relogin_timer, ddb_entry->default_time2wait + 4); + DEBUG(printk("scsi%ld: %s: ddb[%d] " + "initiate relogin after %d seconds\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index, + ddb_entry->default_time2wait + 4)); + } else { + DEBUG(printk("scsi%ld: %s: ddb[%d] " + "relogin not initiated, state = %d, " + "ddb_entry->flags = 0x%lx\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index, + ddb_entry->fw_ddb_device_state, + ddb_entry->flags)); } } - return QLA_SUCCESS; } - diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h index 6375eb017dd..9471ac75500 100644 --- a/drivers/scsi/qla4xxx/ql4_inline.h +++ b/drivers/scsi/qla4xxx/ql4_inline.h @@ -29,7 +29,7 @@ qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; } - DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n", + DEBUG3(printk("scsi%d: %s: ddb [%d], ddb_entry = %p\n", ha->host_no, __func__, fw_ddb_index, ddb_entry)); return ddb_entry; diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index e66f3f263f4..f89973deac5 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -108,8 +108,7 @@ int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, wmb(); /* Tell ISP it's got a new I/O request */ - writel(ha->request_in, &ha->reg->req_q_in); - readl(&ha->reg->req_q_in); + ha->isp_ops->queue_iocb(ha); exit_send_marker: spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -193,6 +192,72 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb, } } +/** + * qla4_8xxx_queue_iocb - Tell ISP it's got new request(s) + * @ha: pointer to host adapter structure. + * + * This routine notifies the ISP that one or more new request + * queue entries have been placed on the request queue. + **/ +void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha) +{ + uint32_t dbval = 0; + unsigned long wtime; + + dbval = 0x14 | (ha->func_num << 5); + dbval = dbval | (0 << 8) | (ha->request_in << 16); + writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr); + wmb(); + + wtime = jiffies + (2 * HZ); + while (readl((void __iomem *)ha->nx_db_rd_ptr) != dbval && + !time_after_eq(jiffies, wtime)) { + writel(dbval, (unsigned long __iomem *)ha->nx_db_wr_ptr); + wmb(); + } +} + +/** + * qla4_8xxx_complete_iocb - Tell ISP we're done with response(s) + * @ha: pointer to host adapter structure. + * + * This routine notifies the ISP that one or more response/completion + * queue entries have been processed by the driver. + * This also clears the interrupt. + **/ +void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha) +{ + writel(ha->response_out, &ha->qla4_8xxx_reg->rsp_q_out); + readl(&ha->qla4_8xxx_reg->rsp_q_out); +} + +/** + * qla4xxx_queue_iocb - Tell ISP it's got new request(s) + * @ha: pointer to host adapter structure. + * + * This routine is notifies the ISP that one or more new request + * queue entries have been placed on the request queue. + **/ +void qla4xxx_queue_iocb(struct scsi_qla_host *ha) +{ + writel(ha->request_in, &ha->reg->req_q_in); + readl(&ha->reg->req_q_in); +} + +/** + * qla4xxx_complete_iocb - Tell ISP we're done with response(s) + * @ha: pointer to host adapter structure. + * + * This routine is notifies the ISP that one or more response/completion + * queue entries have been processed by the driver. + * This also clears the interrupt. + **/ +void qla4xxx_complete_iocb(struct scsi_qla_host *ha) +{ + writel(ha->response_out, &ha->reg->rsp_q_out); + readl(&ha->reg->rsp_q_out); +} + /** * qla4xxx_send_command_to_isp - issues command to HBA * @ha: pointer to host adapter structure. @@ -310,9 +375,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) srb->iocb_cnt = req_cnt; ha->req_q_count -= req_cnt; - /* Debug print statements */ - writel(ha->request_in, &ha->reg->req_q_in); - readl(&ha->reg->req_q_in); + ha->isp_ops->queue_iocb(ha); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 596c3031483..68d7942bf2e 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -118,7 +118,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); if (!srb) { - /* FIXMEdg: Don't we need to reset ISP in this case??? */ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid " "handle 0x%x, sp=%p. This cmd may have already " "been completed.\n", ha->host_no, __func__, @@ -293,6 +292,10 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, case SCS_DEVICE_LOGGED_OUT: case SCS_DEVICE_UNAVAILABLE: + DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: SCS_DEVICE " + "state: 0x%x\n", ha->host_no, + cmd->device->channel, cmd->device->id, + cmd->device->lun, sts_entry->completionStatus)); /* * Mark device missing so that we won't continue to * send I/O to this device. We should get a ddb @@ -339,16 +342,14 @@ status_entry_exit: * This routine process response queue completions in interrupt context. * Hardware_lock locked upon entry **/ -static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) +void qla4xxx_process_response_queue(struct scsi_qla_host *ha) { uint32_t count = 0; struct srb *srb = NULL; struct status_entry *sts_entry; /* Process all responses from response queue */ - while ((ha->response_in = - (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) != - ha->response_out) { + while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) { sts_entry = (struct status_entry *) ha->response_ptr; count++; @@ -413,14 +414,14 @@ static void qla4xxx_process_response_queue(struct scsi_qla_host * ha) sts_entry->hdr.entryType)); goto exit_prq_error; } + ((struct response *)sts_entry)->signature = RESPONSE_PROCESSED; + wmb(); } /* - * Done with responses, update the ISP For QLA4010, this also clears - * the interrupt. + * Tell ISP we're done with response(s). This also clears the interrupt. */ - writel(ha->response_out, &ha->reg->rsp_q_out); - readl(&ha->reg->rsp_q_out); + ha->isp_ops->complete_iocb(ha); return; @@ -430,9 +431,7 @@ exit_prq_invalid_handle: sts_entry->completionStatus)); exit_prq_error: - writel(ha->response_out, &ha->reg->rsp_q_out); - readl(&ha->reg->rsp_q_out); - + ha->isp_ops->complete_iocb(ha); set_bit(DPC_RESET_HA, &ha->dpc_flags); } @@ -448,7 +447,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, uint32_t mbox_status) { int i; - uint32_t mbox_stat2, mbox_stat3; + uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; if ((mbox_status == MBOX_STS_BUSY) || (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || @@ -460,27 +459,37 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, * Copy all mailbox registers to a temporary * location and set mailbox command done flag */ - for (i = 1; i < ha->mbox_status_count; i++) - ha->mbox_status[i] = - readl(&ha->reg->mailbox[i]); + for (i = 0; i < ha->mbox_status_count; i++) + ha->mbox_status[i] = is_qla8022(ha) + ? readl(&ha->qla4_8xxx_reg->mailbox_out[i]) + : readl(&ha->reg->mailbox[i]); set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + + if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) + complete(&ha->mbx_intr_comp); } } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { + for (i = 0; i < MBOX_AEN_REG_COUNT; i++) + mbox_sts[i] = is_qla8022(ha) + ? readl(&ha->qla4_8xxx_reg->mailbox_out[i]) + : readl(&ha->reg->mailbox[i]); + /* Immediately process the AENs that don't require much work. * Only queue the database_changed AENs */ if (ha->aen_log.count < MAX_AEN_ENTRIES) { for (i = 0; i < MBOX_AEN_REG_COUNT; i++) ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] = - readl(&ha->reg->mailbox[i]); + mbox_sts[i]; ha->aen_log.count++; } switch (mbox_status) { case MBOX_ASTS_SYSTEM_ERROR: /* Log Mailbox registers */ + ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); if (ql4xdontresethba) { - DEBUG2(printk("%s:Dont Reset HBA\n", - __func__)); + DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", + ha->host_no, __func__)); } else { set_bit(AF_GET_CRASH_RECORD, &ha->flags); set_bit(DPC_RESET_HA, &ha->dpc_flags); @@ -502,18 +511,15 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, if (test_bit(AF_INIT_DONE, &ha->flags)) set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); - DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" - " LINK UP\n", ha->host_no, - mbox_status)); + ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__); break; case MBOX_ASTS_LINK_DOWN: clear_bit(AF_LINK_UP, &ha->flags); - set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); + if (test_bit(AF_INIT_DONE, &ha->flags)) + set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); - DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x Adapter" - " LINK DOWN\n", ha->host_no, - mbox_status)); + ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__); break; case MBOX_ASTS_HEARTBEAT: @@ -539,12 +545,17 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, break; case MBOX_ASTS_IP_ADDR_STATE_CHANGED: - mbox_stat2 = readl(&ha->reg->mailbox[2]); - mbox_stat3 = readl(&ha->reg->mailbox[3]); - - if ((mbox_stat3 == 5) && (mbox_stat2 == 3)) + printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, " + "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0], + mbox_sts[2], mbox_sts[3]); + + /* mbox_sts[2] = Old ACB state + * mbox_sts[3] = new ACB state */ + if ((mbox_sts[3] == ACB_STATE_VALID) && + (mbox_sts[2] == ACB_STATE_TENTATIVE)) set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); - else if ((mbox_stat3 == 2) && (mbox_stat2 == 5)) + else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && + (mbox_sts[2] == ACB_STATE_VALID)) set_bit(DPC_RESET_HA, &ha->dpc_flags); break; @@ -553,9 +564,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, /* No action */ DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, " "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n", - ha->host_no, mbox_status, - readl(&ha->reg->mailbox[1]), - readl(&ha->reg->mailbox[2]))); + ha->host_no, mbox_sts[0], + mbox_sts[1], mbox_sts[2])); break; case MBOX_ASTS_SELF_TEST_FAILED: @@ -563,10 +573,8 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, /* No action */ DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, " "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n", - ha->host_no, mbox_status, - readl(&ha->reg->mailbox[1]), - readl(&ha->reg->mailbox[2]), - readl(&ha->reg->mailbox[3]))); + ha->host_no, mbox_sts[0], mbox_sts[1], + mbox_sts[2], mbox_sts[3])); break; case MBOX_ASTS_DATABASE_CHANGED: @@ -577,21 +585,17 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, /* decrement available counter */ ha->aen_q_count--; - for (i = 1; i < MBOX_AEN_REG_COUNT; i++) + for (i = 0; i < MBOX_AEN_REG_COUNT; i++) ha->aen_q[ha->aen_in].mbox_sts[i] = - readl(&ha->reg->mailbox[i]); - - ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status; + mbox_sts[i]; /* print debug message */ DEBUG2(printk("scsi%ld: AEN[%d] %04x queued" - " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n", - ha->host_no, ha->aen_in, - mbox_status, - ha->aen_q[ha->aen_in].mbox_sts[1], - ha->aen_q[ha->aen_in].mbox_sts[2], - ha->aen_q[ha->aen_in].mbox_sts[3], - ha->aen_q[ha->aen_in]. mbox_sts[4])); + " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n", + ha->host_no, ha->aen_in, mbox_sts[0], + mbox_sts[1], mbox_sts[2], mbox_sts[3], + mbox_sts[4])); + /* advance pointer */ ha->aen_in++; if (ha->aen_in == MAX_AEN_ENTRIES) @@ -603,18 +607,16 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, DEBUG2(printk("scsi%ld: %s: aen %04x, queue " "overflowed! AEN LOST!!\n", ha->host_no, __func__, - mbox_status)); + mbox_sts[0])); DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n", ha->host_no)); for (i = 0; i < MAX_AEN_ENTRIES; i++) { DEBUG2(printk("AEN[%d] %04x %04x %04x " - "%04x\n", i, - ha->aen_q[i].mbox_sts[0], - ha->aen_q[i].mbox_sts[1], - ha->aen_q[i].mbox_sts[2], - ha->aen_q[i].mbox_sts[3])); + "%04x\n", i, mbox_sts[0], + mbox_sts[1], mbox_sts[2], + mbox_sts[3])); } } break; @@ -622,7 +624,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, default: DEBUG2(printk(KERN_WARNING "scsi%ld: AEN %04x UNKNOWN\n", - ha->host_no, mbox_status)); + ha->host_no, mbox_sts[0])); break; } } else { @@ -633,6 +635,30 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, } } +/** + * qla4_8xxx_interrupt_service_routine - isr + * @ha: pointer to host adapter structure. + * + * This is the main interrupt service routine. + * hardware_lock locked upon entry. runs in interrupt context. + **/ +void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha, + uint32_t intr_status) +{ + /* Process response queue interrupt. */ + if (intr_status & HSRX_RISC_IOCB_INT) + qla4xxx_process_response_queue(ha); + + /* Process mailbox/asynch event interrupt.*/ + if (intr_status & HSRX_RISC_MB_INT) + qla4xxx_isr_decode_mailbox(ha, + readl(&ha->qla4_8xxx_reg->mailbox_out[0])); + + /* clear the interrupt */ + writel(0, &ha->qla4_8xxx_reg->host_int); + readl(&ha->qla4_8xxx_reg->host_int); +} + /** * qla4xxx_interrupt_service_routine - isr * @ha: pointer to host adapter structure. @@ -659,6 +685,28 @@ void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, } } +/** + * qla4_8xxx_spurious_interrupt - processes spurious interrupt + * @ha: pointer to host adapter structure. + * @reqs_count: . + * + **/ +static void qla4_8xxx_spurious_interrupt(struct scsi_qla_host *ha, + uint8_t reqs_count) +{ + if (reqs_count) + return; + + DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n")); + if (is_qla8022(ha)) { + writel(0, &ha->qla4_8xxx_reg->host_int); + if (test_bit(AF_INTx_ENABLED, &ha->flags)) + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, + 0xfbff); + } + ha->spurious_int_count++; +} + /** * qla4xxx_intr_handler - hardware interrupt handler. * @irq: Unused @@ -689,15 +737,14 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) /* * Read interrupt status */ - if (le32_to_cpu(ha->shadow_regs->rsp_q_in) != + if (ha->isp_ops->rd_shdw_rsp_q_in(ha) != ha->response_out) intr_status = CSR_SCSI_COMPLETION_INTR; else intr_status = readl(&ha->reg->ctrl_status); if ((intr_status & - (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == - 0) { + (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) { if (reqs_count == 0) ha->spurious_int_count++; break; @@ -739,22 +786,159 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); - if (!ql4_mod_unload) + if (!test_bit(AF_HBA_GOING_AWAY, &ha->flags)) set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); break; } else if (intr_status & INTR_PENDING) { - qla4xxx_interrupt_service_routine(ha, intr_status); + ha->isp_ops->interrupt_service_routine(ha, intr_status); ha->total_io_count++; if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) break; + } + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + return IRQ_HANDLED; +} + +/** + * qla4_8xxx_intr_handler - hardware interrupt handler. + * @irq: Unused + * @dev_id: Pointer to host adapter structure + **/ +irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id) +{ + struct scsi_qla_host *ha = dev_id; + uint32_t intr_status; + uint32_t status; + unsigned long flags = 0; + uint8_t reqs_count = 0; + + ha->isr_count++; + status = qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); + if (!(status & ha->nx_legacy_intr.int_vec_bit)) + return IRQ_NONE; + + status = qla4_8xxx_rd_32(ha, ISR_INT_STATE_REG); + if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s legacy Int not triggered\n", __func__)); + return IRQ_NONE; + } + + /* clear the interrupt */ + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); + + /* read twice to ensure write is flushed */ + qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); + qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); + + spin_lock_irqsave(&ha->hardware_lock, flags); + while (1) { + if (!(readl(&ha->qla4_8xxx_reg->host_int) & + ISRX_82XX_RISC_INT)) { + qla4_8xxx_spurious_interrupt(ha, reqs_count); + break; + } + intr_status = readl(&ha->qla4_8xxx_reg->host_status); + if ((intr_status & + (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { + qla4_8xxx_spurious_interrupt(ha, reqs_count); + break; + } + + ha->isp_ops->interrupt_service_routine(ha, intr_status); + + /* Enable Interrupt */ + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); - intr_status = 0; + if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) + break; + } + + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return IRQ_HANDLED; +} + +irqreturn_t +qla4_8xxx_msi_handler(int irq, void *dev_id) +{ + struct scsi_qla_host *ha; + + ha = (struct scsi_qla_host *) dev_id; + if (!ha) { + DEBUG2(printk(KERN_INFO + "qla4xxx: MSIX: Interrupt with NULL host ptr\n")); + return IRQ_NONE; + } + + ha->isr_count++; + /* clear the interrupt */ + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); + + /* read twice to ensure write is flushed */ + qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); + qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); + + return qla4_8xxx_default_intr_handler(irq, dev_id); +} + +/** + * qla4_8xxx_default_intr_handler - hardware interrupt handler. + * @irq: Unused + * @dev_id: Pointer to host adapter structure + * + * This interrupt handler is called directly for MSI-X, and + * called indirectly for MSI. + **/ +irqreturn_t +qla4_8xxx_default_intr_handler(int irq, void *dev_id) +{ + struct scsi_qla_host *ha = dev_id; + unsigned long flags; + uint32_t intr_status; + uint8_t reqs_count = 0; + + spin_lock_irqsave(&ha->hardware_lock, flags); + while (1) { + if (!(readl(&ha->qla4_8xxx_reg->host_int) & + ISRX_82XX_RISC_INT)) { + qla4_8xxx_spurious_interrupt(ha, reqs_count); + break; + } + + intr_status = readl(&ha->qla4_8xxx_reg->host_status); + if ((intr_status & + (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { + qla4_8xxx_spurious_interrupt(ha, reqs_count); + break; } + + ha->isp_ops->interrupt_service_routine(ha, intr_status); + + if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) + break; } + ha->isr_count++; spin_unlock_irqrestore(&ha->hardware_lock, flags); + return IRQ_HANDLED; +} +irqreturn_t +qla4_8xxx_msix_rsp_q(int irq, void *dev_id) +{ + struct scsi_qla_host *ha = dev_id; + unsigned long flags; + + spin_lock_irqsave(&ha->hardware_lock, flags); + qla4xxx_process_response_queue(ha); + writel(0, &ha->qla4_8xxx_reg->host_int); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + ha->isr_count++; return IRQ_HANDLED; } @@ -825,7 +1009,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) ((ddb_entry->default_time2wait + 4) * HZ); - DEBUG2(printk("scsi%ld: ddb index [%d] initate" + DEBUG2(printk("scsi%ld: ddb [%d] initate" " RELOGIN after %d seconds\n", ha->host_no, ddb_entry->fw_ddb_index, @@ -847,3 +1031,81 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) spin_unlock_irqrestore(&ha->hardware_lock, flags); } +int qla4xxx_request_irqs(struct scsi_qla_host *ha) +{ + int ret; + + if (!is_qla8022(ha)) + goto try_intx; + + if (ql4xenablemsix == 2) + goto try_msi; + + if (ql4xenablemsix == 0 || ql4xenablemsix != 1) + goto try_intx; + + /* Trying MSI-X */ + ret = qla4_8xxx_enable_msix(ha); + if (!ret) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "MSI-X: Enabled (0x%X).\n", ha->revision_id)); + goto irq_attached; + } + + ql4_printk(KERN_WARNING, ha, + "MSI-X: Falling back-to MSI mode -- %d.\n", ret); + +try_msi: + /* Trying MSI */ + ret = pci_enable_msi(ha->pdev); + if (!ret) { + ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler, + IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha); + if (!ret) { + DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n")); + set_bit(AF_MSI_ENABLED, &ha->flags); + goto irq_attached; + } else { + ql4_printk(KERN_WARNING, ha, + "MSI: Failed to reserve interrupt %d " + "already in use.\n", ha->pdev->irq); + pci_disable_msi(ha->pdev); + } + } + ql4_printk(KERN_WARNING, ha, + "MSI: Falling back-to INTx mode -- %d.\n", ret); + +try_intx: + /* Trying INTx */ + ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, + IRQF_DISABLED|IRQF_SHARED, DRIVER_NAME, ha); + if (!ret) { + DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n")); + set_bit(AF_INTx_ENABLED, &ha->flags); + goto irq_attached; + + } else { + ql4_printk(KERN_WARNING, ha, + "INTx: Failed to reserve interrupt %d already in" + " use.\n", ha->pdev->irq); + return ret; + } + +irq_attached: + set_bit(AF_IRQ_ATTACHED, &ha->flags); + ha->host->irq = ha->pdev->irq; + ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n", + __func__, ha->pdev->irq); + return ret; +} + +void qla4xxx_free_irqs(struct scsi_qla_host *ha) +{ + if (test_bit(AF_MSIX_ENABLED, &ha->flags)) + qla4_8xxx_disable_msix(ha); + else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) { + free_irq(ha->pdev->irq, ha); + pci_disable_msi(ha->pdev); + } else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags)) + free_irq(ha->pdev->irq, ha); +} diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 54db6cbbd94..0d3a6526841 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -19,13 +19,13 @@ * @mbx_cmd: data pointer for mailbox in registers. * @mbx_sts: data pointer for mailbox out registers. * - * This routine sssue mailbox commands and waits for completion. + * This routine isssue mailbox commands and waits for completion. * If outCount is 0, this routine completes successfully WITHOUT waiting * for the mailbox command to complete. **/ -static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, - uint8_t outCount, uint32_t *mbx_cmd, - uint32_t *mbx_sts) +int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, + uint32_t *mbx_sts) { int status = QLA_ERROR; uint8_t i; @@ -59,32 +59,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, } /* To prevent overwriting mailbox registers for a command that has - * not yet been serviced, check to see if a previously issued - * mailbox command is interrupting. + * not yet been serviced, check to see if an active command + * (AEN, IOCB, etc.) is interrupting, then service it. * ----------------------------------------------------------------- */ spin_lock_irqsave(&ha->hardware_lock, flags); - intr_status = readl(&ha->reg->ctrl_status); - if (intr_status & CSR_SCSI_PROCESSOR_INTR) { - /* Service existing interrupt */ - qla4xxx_interrupt_service_routine(ha, intr_status); - clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + + if (is_qla8022(ha)) { + intr_status = readl(&ha->qla4_8xxx_reg->host_int); + if (intr_status & ISRX_82XX_RISC_INT) { + /* Service existing interrupt */ + DEBUG2(printk("scsi%ld: %s: " + "servicing existing interrupt\n", + ha->host_no, __func__)); + intr_status = readl(&ha->qla4_8xxx_reg->host_status); + ha->isp_ops->interrupt_service_routine(ha, intr_status); + clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + if (test_bit(AF_INTERRUPTS_ON, &ha->flags) && + test_bit(AF_INTx_ENABLED, &ha->flags)) + qla4_8xxx_wr_32(ha, + ha->nx_legacy_intr.tgt_mask_reg, + 0xfbff); + } + } else { + intr_status = readl(&ha->reg->ctrl_status); + if (intr_status & CSR_SCSI_PROCESSOR_INTR) { + /* Service existing interrupt */ + ha->isp_ops->interrupt_service_routine(ha, intr_status); + clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); + } } - /* Send the mailbox command to the firmware */ ha->mbox_status_count = outCount; for (i = 0; i < outCount; i++) ha->mbox_status[i] = 0; - /* Load all mailbox registers, except mailbox 0. */ - for (i = 1; i < inCount; i++) - writel(mbx_cmd[i], &ha->reg->mailbox[i]); + if (is_qla8022(ha)) { + /* Load all mailbox registers, except mailbox 0. */ + DEBUG5( + printk("scsi%ld: %s: Cmd ", ha->host_no, __func__); + for (i = 0; i < inCount; i++) + printk("mb%d=%04x ", i, mbx_cmd[i]); + printk("\n")); + + for (i = 1; i < inCount; i++) + writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]); + writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]); + readl(&ha->qla4_8xxx_reg->mailbox_in[0]); + writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint); + } else { + /* Load all mailbox registers, except mailbox 0. */ + for (i = 1; i < inCount; i++) + writel(mbx_cmd[i], &ha->reg->mailbox[i]); + + /* Wakeup firmware */ + writel(mbx_cmd[0], &ha->reg->mailbox[0]); + readl(&ha->reg->mailbox[0]); + writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); + readl(&ha->reg->ctrl_status); + } - /* Wakeup firmware */ - writel(mbx_cmd[0], &ha->reg->mailbox[0]); - readl(&ha->reg->mailbox[0]); - writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for completion */ @@ -98,26 +132,66 @@ static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, status = QLA_SUCCESS; goto mbox_exit; } - /* Wait for command to complete */ - wait_count = jiffies + MBOX_TOV * HZ; - while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { - if (time_after_eq(jiffies, wait_count)) - break; - spin_lock_irqsave(&ha->hardware_lock, flags); - intr_status = readl(&ha->reg->ctrl_status); - if (intr_status & INTR_PENDING) { + /* + * Wait for completion: Poll or completion queue + */ + if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && + test_bit(AF_INTERRUPTS_ON, &ha->flags) && + test_bit(AF_ONLINE, &ha->flags) && + !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { + /* Do not poll for completion. Use completion queue */ + set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); + wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); + clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); + } else { + /* Poll for command to complete */ + wait_count = jiffies + MBOX_TOV * HZ; + while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { + if (time_after_eq(jiffies, wait_count)) + break; /* * Service the interrupt. * The ISR will save the mailbox status registers * to a temporary storage location in the adapter * structure. */ - ha->mbox_status_count = outCount; - qla4xxx_interrupt_service_routine(ha, intr_status); + + spin_lock_irqsave(&ha->hardware_lock, flags); + if (is_qla8022(ha)) { + intr_status = + readl(&ha->qla4_8xxx_reg->host_int); + if (intr_status & ISRX_82XX_RISC_INT) { + ha->mbox_status_count = outCount; + intr_status = + readl(&ha->qla4_8xxx_reg->host_status); + ha->isp_ops->interrupt_service_routine( + ha, intr_status); + if (test_bit(AF_INTERRUPTS_ON, + &ha->flags) && + test_bit(AF_INTx_ENABLED, + &ha->flags)) + qla4_8xxx_wr_32(ha, + ha->nx_legacy_intr.tgt_mask_reg, + 0xfbff); + } + } else { + intr_status = readl(&ha->reg->ctrl_status); + if (intr_status & INTR_PENDING) { + /* + * Service the interrupt. + * The ISR will save the mailbox status + * registers to a temporary storage + * location in the adapter structure. + */ + ha->mbox_status_count = outCount; + ha->isp_ops->interrupt_service_routine( + ha, intr_status); + } + } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + msleep(10); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - msleep(10); } /* Check for mailbox timeout. */ @@ -172,7 +246,7 @@ mbox_exit: return status; } -uint8_t +static uint8_t qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) { @@ -196,7 +270,7 @@ qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, return QLA_SUCCESS; } -uint8_t +static uint8_t qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) { @@ -218,7 +292,7 @@ qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, return QLA_SUCCESS; } -void +static void qla4xxx_update_local_ip(struct scsi_qla_host *ha, struct addr_ctrl_blk *init_fw_cb) { @@ -256,7 +330,7 @@ qla4xxx_update_local_ip(struct scsi_qla_host *ha, } } -uint8_t +static uint8_t qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, uint32_t *mbox_sts, @@ -445,7 +519,7 @@ int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", ha->host_no, __func__, ha->firmware_state);) - return QLA_SUCCESS; + return QLA_SUCCESS; } /** @@ -470,6 +544,10 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) mbox_sts[0])); return QLA_ERROR; } + + ql4_printk(KERN_INFO, ha, "%ld firmare IOCBs available (%d).\n", + ha->host_no, mbox_cmd[2]); + return QLA_SUCCESS; } @@ -500,7 +578,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, /* Make sure the device index is valid */ if (fw_ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n", + DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n", ha->host_no, __func__, fw_ddb_index)); goto exit_get_fwddb; } @@ -521,7 +599,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, goto exit_get_fwddb; } if (fw_ddb_index != mbox_sts[1]) { - DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n", + DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n", ha->host_no, __func__, fw_ddb_index, mbox_sts[1])); goto exit_get_fwddb; @@ -590,6 +668,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; + int status; /* Do not wait for completion. The firmware will send us an * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. @@ -603,7 +682,12 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, mbox_cmd[3] = MSDW(fw_ddb_entry_dma); mbox_cmd[4] = sizeof(struct dev_db_entry); - return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], + &mbox_sts[0]); + DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n", + ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);) + + return status; } /** @@ -817,8 +901,8 @@ int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb) /** * qla4xxx_reset_lun - issues LUN Reset * @ha: Pointer to host adapter structure. - * @db_entry: Pointer to device database entry - * @un_entry: Pointer to lun entry structure + * @ddb_entry: Pointer to device database entry + * @lun: lun number * * This routine performs a LUN RESET on the specified target/lun. * The caller must ensure that the ddb_entry and lun_entry pointers @@ -832,7 +916,7 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, int status = QLA_SUCCESS; DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, - ddb_entry->os_target_id, lun)); + ddb_entry->fw_ddb_index, lun)); /* * Send lun reset command to ISP, so that the ISP will return all @@ -872,7 +956,7 @@ int qla4xxx_reset_target(struct scsi_qla_host *ha, int status = QLA_SUCCESS; DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, - ddb_entry->os_target_id)); + ddb_entry->fw_ddb_index)); /* * Send target reset command to ISP, so that the ISP will return all diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c index 7fe0482ecf0..f0d0fbf88aa 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.c +++ b/drivers/scsi/qla4xxx/ql4_nvram.c @@ -149,7 +149,7 @@ static int eeprom_readword(int eepromAddr, u16 * value, /* Hardware_lock must be set before calling */ u16 rd_nvram_word(struct scsi_qla_host * ha, int offset) { - u16 val; + u16 val = 0; /* NOTE: NVRAM uses half-word addresses */ eeprom_readword(offset, &val, ha); diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h index b47b4fc59d8..7a8fc66a760 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.h +++ b/drivers/scsi/qla4xxx/ql4_nvram.h @@ -8,9 +8,9 @@ #ifndef _QL4XNVRM_H_ #define _QL4XNVRM_H_ -/* +/** * AM29LV Flash definitions - */ + **/ #define FM93C56A_SIZE_8 0x100 #define FM93C56A_SIZE_16 0x80 #define FM93C66A_SIZE_8 0x200 @@ -19,7 +19,7 @@ #define FM93C56A_START 0x1 -// Commands +/* Commands */ #define FM93C56A_READ 0x2 #define FM93C56A_WEN 0x0 #define FM93C56A_WRITE 0x1 @@ -62,9 +62,9 @@ #define AUBURN_EEPROM_CLK_RISE 0x1 #define AUBURN_EEPROM_CLK_FALL 0x0 -/* */ +/**/ /* EEPROM format */ -/* */ +/**/ struct bios_params { uint16_t SpinUpDelay:1; uint16_t BIOSDisable:1; diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c new file mode 100644 index 00000000000..3e119ae7839 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -0,0 +1,2321 @@ +/* + * QLogic iSCSI HBA Driver + * Copyright (c) 2003-2009 QLogic Corporation + * + * See LICENSE.qla4xxx for copyright and licensing details. + */ +#include +#include +#include "ql4_def.h" +#include "ql4_glbl.h" + +#define MASK(n) DMA_BIT_MASK(n) +#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff)) +#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff)) +#define MS_WIN(addr) (addr & 0x0ffc0000) +#define QLA82XX_PCI_MN_2M (0) +#define QLA82XX_PCI_MS_2M (0x80000) +#define QLA82XX_PCI_OCM0_2M (0xc0000) +#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) +#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) + +/* CRB window related */ +#define CRB_BLK(off) ((off >> 20) & 0x3f) +#define CRB_SUBBLK(off) ((off >> 16) & 0xf) +#define CRB_WINDOW_2M (0x130060) +#define CRB_HI(off) ((qla4_8xxx_crb_hub_agt[CRB_BLK(off)] << 20) | \ + ((off) & 0xf0000)) +#define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL) +#define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL) +#define CRB_INDIRECT_2M (0x1e0000UL) + +static inline void __iomem * +qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off) +{ + if ((off < ha->first_page_group_end) && + (off >= ha->first_page_group_start)) + return (void __iomem *)(ha->nx_pcibase + off); + + return NULL; +} + +#define MAX_CRB_XFORM 60 +static unsigned long crb_addr_xform[MAX_CRB_XFORM]; +static int qla4_8xxx_crb_table_initialized; + +#define qla4_8xxx_crb_addr_transform(name) \ + (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \ + QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20) +static void +qla4_8xxx_crb_addr_transform_setup(void) +{ + qla4_8xxx_crb_addr_transform(XDMA); + qla4_8xxx_crb_addr_transform(TIMR); + qla4_8xxx_crb_addr_transform(SRE); + qla4_8xxx_crb_addr_transform(SQN3); + qla4_8xxx_crb_addr_transform(SQN2); + qla4_8xxx_crb_addr_transform(SQN1); + qla4_8xxx_crb_addr_transform(SQN0); + qla4_8xxx_crb_addr_transform(SQS3); + qla4_8xxx_crb_addr_transform(SQS2); + qla4_8xxx_crb_addr_transform(SQS1); + qla4_8xxx_crb_addr_transform(SQS0); + qla4_8xxx_crb_addr_transform(RPMX7); + qla4_8xxx_crb_addr_transform(RPMX6); + qla4_8xxx_crb_addr_transform(RPMX5); + qla4_8xxx_crb_addr_transform(RPMX4); + qla4_8xxx_crb_addr_transform(RPMX3); + qla4_8xxx_crb_addr_transform(RPMX2); + qla4_8xxx_crb_addr_transform(RPMX1); + qla4_8xxx_crb_addr_transform(RPMX0); + qla4_8xxx_crb_addr_transform(ROMUSB); + qla4_8xxx_crb_addr_transform(SN); + qla4_8xxx_crb_addr_transform(QMN); + qla4_8xxx_crb_addr_transform(QMS); + qla4_8xxx_crb_addr_transform(PGNI); + qla4_8xxx_crb_addr_transform(PGND); + qla4_8xxx_crb_addr_transform(PGN3); + qla4_8xxx_crb_addr_transform(PGN2); + qla4_8xxx_crb_addr_transform(PGN1); + qla4_8xxx_crb_addr_transform(PGN0); + qla4_8xxx_crb_addr_transform(PGSI); + qla4_8xxx_crb_addr_transform(PGSD); + qla4_8xxx_crb_addr_transform(PGS3); + qla4_8xxx_crb_addr_transform(PGS2); + qla4_8xxx_crb_addr_transform(PGS1); + qla4_8xxx_crb_addr_transform(PGS0); + qla4_8xxx_crb_addr_transform(PS); + qla4_8xxx_crb_addr_transform(PH); + qla4_8xxx_crb_addr_transform(NIU); + qla4_8xxx_crb_addr_transform(I2Q); + qla4_8xxx_crb_addr_transform(EG); + qla4_8xxx_crb_addr_transform(MN); + qla4_8xxx_crb_addr_transform(MS); + qla4_8xxx_crb_addr_transform(CAS2); + qla4_8xxx_crb_addr_transform(CAS1); + qla4_8xxx_crb_addr_transform(CAS0); + qla4_8xxx_crb_addr_transform(CAM); + qla4_8xxx_crb_addr_transform(C2C1); + qla4_8xxx_crb_addr_transform(C2C0); + qla4_8xxx_crb_addr_transform(SMB); + qla4_8xxx_crb_addr_transform(OCM0); + qla4_8xxx_crb_addr_transform(I2C0); + + qla4_8xxx_crb_table_initialized = 1; +} + +static struct crb_128M_2M_block_map crb_128M_2M_map[64] = { + {{{0, 0, 0, 0} } }, /* 0: PCI */ + {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ + {1, 0x0110000, 0x0120000, 0x130000}, + {1, 0x0120000, 0x0122000, 0x124000}, + {1, 0x0130000, 0x0132000, 0x126000}, + {1, 0x0140000, 0x0142000, 0x128000}, + {1, 0x0150000, 0x0152000, 0x12a000}, + {1, 0x0160000, 0x0170000, 0x110000}, + {1, 0x0170000, 0x0172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x01e0000, 0x01e0800, 0x122000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */ + {{{0, 0, 0, 0} } }, /* 3: */ + {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */ + {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */ + {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */ + {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */ + {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x08f0000, 0x08f2000, 0x172000} } }, + {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x09f0000, 0x09f2000, 0x176000} } }, + {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0af0000, 0x0af2000, 0x17a000} } }, + {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/ + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, + {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */ + {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */ + {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */ + {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */ + {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */ + {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */ + {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */ + {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */ + {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */ + {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */ + {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */ + {{{0, 0, 0, 0} } }, /* 23: */ + {{{0, 0, 0, 0} } }, /* 24: */ + {{{0, 0, 0, 0} } }, /* 25: */ + {{{0, 0, 0, 0} } }, /* 26: */ + {{{0, 0, 0, 0} } }, /* 27: */ + {{{0, 0, 0, 0} } }, /* 28: */ + {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */ + {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */ + {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */ + {{{0} } }, /* 32: PCI */ + {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */ + {1, 0x2110000, 0x2120000, 0x130000}, + {1, 0x2120000, 0x2122000, 0x124000}, + {1, 0x2130000, 0x2132000, 0x126000}, + {1, 0x2140000, 0x2142000, 0x128000}, + {1, 0x2150000, 0x2152000, 0x12a000}, + {1, 0x2160000, 0x2170000, 0x110000}, + {1, 0x2170000, 0x2172000, 0x12e000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000}, + {0, 0x0000000, 0x0000000, 0x000000} } }, + {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */ + {{{0} } }, /* 35: */ + {{{0} } }, /* 36: */ + {{{0} } }, /* 37: */ + {{{0} } }, /* 38: */ + {{{0} } }, /* 39: */ + {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */ + {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */ + {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */ + {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */ + {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */ + {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */ + {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */ + {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */ + {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */ + {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */ + {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */ + {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */ + {{{0} } }, /* 52: */ + {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */ + {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */ + {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */ + {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */ + {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */ + {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */ + {{{0} } }, /* 59: I2C0 */ + {{{0} } }, /* 60: I2C1 */ + {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },/* 61: LPC */ + {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */ + {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */ +}; + +/* + * top 12 bits of crb internal address (hub, agent) + */ +static unsigned qla4_8xxx_crb_hub_agt[64] = { + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PS, + QLA82XX_HW_CRB_HUB_AGT_ADR_MN, + QLA82XX_HW_CRB_HUB_AGT_ADR_MS, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_SRE, + QLA82XX_HW_CRB_HUB_AGT_ADR_NIU, + QLA82XX_HW_CRB_HUB_AGT_ADR_QMN, + QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0, + QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1, + QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2, + QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3, + QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, + QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, + QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4, + QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGND, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI, + QLA82XX_HW_CRB_HUB_AGT_ADR_SN, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_EG, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PS, + QLA82XX_HW_CRB_HUB_AGT_ADR_CAM, + 0, + 0, + 0, + 0, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7, + QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, + QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, + QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8, + QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9, + QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_SMB, + QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0, + QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1, + 0, + QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC, + 0, +}; + +/* Device states */ +static char *qdev_state[] = { + "Unknown", + "Cold", + "Initializing", + "Ready", + "Need Reset", + "Need Quiescent", + "Failed", + "Quiescent", +}; + +/* + * In: 'off' is offset from CRB space in 128M pci map + * Out: 'off' is 2M pci map addr + * side effect: lock crb window + */ +static void +qla4_8xxx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off) +{ + u32 win_read; + + ha->crb_win = CRB_HI(*off); + writel(ha->crb_win, + (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); + + /* Read back value to make sure write has gone through before trying + * to use it. */ + win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); + if (win_read != ha->crb_win) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: Written crbwin (0x%x) != Read crbwin (0x%x)," + " off=0x%lx\n", __func__, ha->crb_win, win_read, *off)); + } + *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; +} + +void +qla4_8xxx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data) +{ + unsigned long flags = 0; + int rv; + + rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off); + + BUG_ON(rv == -1); + + if (rv == 1) { + write_lock_irqsave(&ha->hw_lock, flags); + qla4_8xxx_crb_win_lock(ha); + qla4_8xxx_pci_set_crbwindow_2M(ha, &off); + } + + writel(data, (void __iomem *)off); + + if (rv == 1) { + qla4_8xxx_crb_win_unlock(ha); + write_unlock_irqrestore(&ha->hw_lock, flags); + } +} + +int +qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off) +{ + unsigned long flags = 0; + int rv; + u32 data; + + rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off); + + BUG_ON(rv == -1); + + if (rv == 1) { + write_lock_irqsave(&ha->hw_lock, flags); + qla4_8xxx_crb_win_lock(ha); + qla4_8xxx_pci_set_crbwindow_2M(ha, &off); + } + data = readl((void __iomem *)off); + + if (rv == 1) { + qla4_8xxx_crb_win_unlock(ha); + write_unlock_irqrestore(&ha->hw_lock, flags); + } + return data; +} + +#define CRB_WIN_LOCK_TIMEOUT 100000000 + +int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha) +{ + int i; + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore3 from PCI HW block */ + done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); + if (done == 1) + break; + if (timeout >= CRB_WIN_LOCK_TIMEOUT) + return -1; + + timeout++; + + /* Yield CPU */ + if (!in_interrupt()) + schedule(); + else { + for (i = 0; i < 20; i++) + cpu_relax(); /*This a nop instr on i386*/ + } + } + qla4_8xxx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); + return 0; +} + +void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *ha) +{ + qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +} + +#define IDC_LOCK_TIMEOUT 100000000 + +/** + * qla4_8xxx_idc_lock - hw_lock + * @ha: pointer to adapter structure + * + * General purpose lock used to synchronize access to + * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc. + **/ +int qla4_8xxx_idc_lock(struct scsi_qla_host *ha) +{ + int i; + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore5 from PCI HW block */ + done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); + if (done == 1) + break; + if (timeout >= IDC_LOCK_TIMEOUT) + return -1; + + timeout++; + + /* Yield CPU */ + if (!in_interrupt()) + schedule(); + else { + for (i = 0; i < 20; i++) + cpu_relax(); /*This a nop instr on i386*/ + } + } + return 0; +} + +void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha) +{ + qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); +} + +int +qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *ha, ulong *off) +{ + struct crb_128M_2M_sub_block_map *m; + + if (*off >= QLA82XX_CRB_MAX) + return -1; + + if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { + *off = (*off - QLA82XX_PCI_CAMQM) + + QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; + return 0; + } + + if (*off < QLA82XX_PCI_CRBSPACE) + return -1; + + *off -= QLA82XX_PCI_CRBSPACE; + /* + * Try direct map + */ + + m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; + + if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { + *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; + return 0; + } + + /* + * Not in direct map, use crb window + */ + return 1; +} + +/* PCI Windowing for DDR regions. */ +#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ + (((addr) <= (high)) && ((addr) >= (low))) + +/* +* check memory access boundary. +* used by test agent. support ddr access only for now +*/ +static unsigned long +qla4_8xxx_pci_mem_bound_check(struct scsi_qla_host *ha, + unsigned long long addr, int size) +{ + if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + QLA82XX_ADDR_DDR_NET_MAX) || + !QLA82XX_ADDR_IN_RANGE(addr + size - 1, + QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) || + ((size != 1) && (size != 2) && (size != 4) && (size != 8))) { + return 0; + } + return 1; +} + +static int qla4_8xxx_pci_set_window_warning_count; + +static unsigned long +qla4_8xxx_pci_set_window(struct scsi_qla_host *ha, unsigned long long addr) +{ + int window; + u32 win_read; + + if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + QLA82XX_ADDR_DDR_NET_MAX)) { + /* DDR network side */ + window = MN_WIN(addr); + ha->ddr_mn_window = window; + qla4_8xxx_wr_32(ha, ha->mn_win_crb | + QLA82XX_PCI_CRBSPACE, window); + win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb | + QLA82XX_PCI_CRBSPACE); + if ((win_read << 17) != window) { + ql4_printk(KERN_WARNING, ha, + "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n", + __func__, window, win_read); + } + addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET; + } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, + QLA82XX_ADDR_OCM0_MAX)) { + unsigned int temp1; + /* if bits 19:18&17:11 are on */ + if ((addr & 0x00ff800) == 0xff800) { + printk("%s: QM access not handled.\n", __func__); + addr = -1UL; + } + + window = OCM_WIN(addr); + ha->ddr_mn_window = window; + qla4_8xxx_wr_32(ha, ha->mn_win_crb | + QLA82XX_PCI_CRBSPACE, window); + win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb | + QLA82XX_PCI_CRBSPACE); + temp1 = ((window & 0x1FF) << 7) | + ((window & 0x0FFFE0000) >> 17); + if (win_read != temp1) { + printk("%s: Written OCMwin (0x%x) != Read" + " OCMwin (0x%x)\n", __func__, temp1, win_read); + } + addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M; + + } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, + QLA82XX_P3_ADDR_QDR_NET_MAX)) { + /* QDR network side */ + window = MS_WIN(addr); + ha->qdr_sn_window = window; + qla4_8xxx_wr_32(ha, ha->ms_win_crb | + QLA82XX_PCI_CRBSPACE, window); + win_read = qla4_8xxx_rd_32(ha, + ha->ms_win_crb | QLA82XX_PCI_CRBSPACE); + if (win_read != window) { + printk("%s: Written MSwin (0x%x) != Read " + "MSwin (0x%x)\n", __func__, window, win_read); + } + addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET; + + } else { + /* + * peg gdb frequently accesses memory that doesn't exist, + * this limits the chit chat so debugging isn't slowed down. + */ + if ((qla4_8xxx_pci_set_window_warning_count++ < 8) || + (qla4_8xxx_pci_set_window_warning_count%64 == 0)) { + printk("%s: Warning:%s Unknown address range!\n", + __func__, DRIVER_NAME); + } + addr = -1UL; + } + return addr; +} + +/* check if address is in the same windows as the previous access */ +static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha, + unsigned long long addr) +{ + int window; + unsigned long long qdr_max; + + qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX; + + if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + QLA82XX_ADDR_DDR_NET_MAX)) { + /* DDR network side */ + BUG(); /* MN access can not come here */ + } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, + QLA82XX_ADDR_OCM0_MAX)) { + return 1; + } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1, + QLA82XX_ADDR_OCM1_MAX)) { + return 1; + } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, + qdr_max)) { + /* QDR network side */ + window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f; + if (ha->qdr_sn_window == window) + return 1; + } + + return 0; +} + +static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha, + u64 off, void *data, int size) +{ + unsigned long flags; + void __iomem *addr; + int ret = 0; + u64 start; + void __iomem *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + write_lock_irqsave(&ha->hw_lock, flags); + + /* + * If attempting to access unknown address or straddle hw windows, + * do not access. + */ + start = qla4_8xxx_pci_set_window(ha, off); + if ((start == -1UL) || + (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) { + write_unlock_irqrestore(&ha->hw_lock, flags); + printk(KERN_ERR"%s out of bound pci memory access. " + "offset is 0x%llx\n", DRIVER_NAME, off); + return -1; + } + + addr = qla4_8xxx_pci_base_offsetfset(ha, start); + if (!addr) { + write_unlock_irqrestore(&ha->hw_lock, flags); + mem_base = pci_resource_start(ha->pdev, 0); + mem_page = start & PAGE_MASK; + /* Map two pages whenever user tries to access addresses in two + consecutive pages. + */ + if (mem_page != ((start + size - 1) & PAGE_MASK)) + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); + else + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); + + if (mem_ptr == NULL) { + *(u8 *)data = 0; + return -1; + } + addr = mem_ptr; + addr += start & (PAGE_SIZE - 1); + write_lock_irqsave(&ha->hw_lock, flags); + } + + switch (size) { + case 1: + *(u8 *)data = readb(addr); + break; + case 2: + *(u16 *)data = readw(addr); + break; + case 4: + *(u32 *)data = readl(addr); + break; + case 8: + *(u64 *)data = readq(addr); + break; + default: + ret = -1; + break; + } + write_unlock_irqrestore(&ha->hw_lock, flags); + + if (mem_ptr) + iounmap(mem_ptr); + return ret; +} + +static int +qla4_8xxx_pci_mem_write_direct(struct scsi_qla_host *ha, u64 off, + void *data, int size) +{ + unsigned long flags; + void __iomem *addr; + int ret = 0; + u64 start; + void __iomem *mem_ptr = NULL; + unsigned long mem_base; + unsigned long mem_page; + + write_lock_irqsave(&ha->hw_lock, flags); + + /* + * If attempting to access unknown address or straddle hw windows, + * do not access. + */ + start = qla4_8xxx_pci_set_window(ha, off); + if ((start == -1UL) || + (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) { + write_unlock_irqrestore(&ha->hw_lock, flags); + printk(KERN_ERR"%s out of bound pci memory access. " + "offset is 0x%llx\n", DRIVER_NAME, off); + return -1; + } + + addr = qla4_8xxx_pci_base_offsetfset(ha, start); + if (!addr) { + write_unlock_irqrestore(&ha->hw_lock, flags); + mem_base = pci_resource_start(ha->pdev, 0); + mem_page = start & PAGE_MASK; + /* Map two pages whenever user tries to access addresses in two + consecutive pages. + */ + if (mem_page != ((start + size - 1) & PAGE_MASK)) + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); + else + mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); + if (mem_ptr == NULL) + return -1; + + addr = mem_ptr; + addr += start & (PAGE_SIZE - 1); + write_lock_irqsave(&ha->hw_lock, flags); + } + + switch (size) { + case 1: + writeb(*(u8 *)data, addr); + break; + case 2: + writew(*(u16 *)data, addr); + break; + case 4: + writel(*(u32 *)data, addr); + break; + case 8: + writeq(*(u64 *)data, addr); + break; + default: + ret = -1; + break; + } + write_unlock_irqrestore(&ha->hw_lock, flags); + if (mem_ptr) + iounmap(mem_ptr); + return ret; +} + +#define MTU_FUDGE_FACTOR 100 + +static unsigned long +qla4_8xxx_decode_crb_addr(unsigned long addr) +{ + int i; + unsigned long base_addr, offset, pci_base; + + if (!qla4_8xxx_crb_table_initialized) + qla4_8xxx_crb_addr_transform_setup(); + + pci_base = ADDR_ERROR; + base_addr = addr & 0xfff00000; + offset = addr & 0x000fffff; + + for (i = 0; i < MAX_CRB_XFORM; i++) { + if (crb_addr_xform[i] == base_addr) { + pci_base = i << 20; + break; + } + } + if (pci_base == ADDR_ERROR) + return pci_base; + else + return pci_base + offset; +} + +static long rom_max_timeout = 100; +static long qla4_8xxx_rom_lock_timeout = 100; + +static int +qla4_8xxx_rom_lock(struct scsi_qla_host *ha) +{ + int i; + int done = 0, timeout = 0; + + while (!done) { + /* acquire semaphore2 from PCI HW block */ + + done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); + if (done == 1) + break; + if (timeout >= qla4_8xxx_rom_lock_timeout) + return -1; + + timeout++; + + /* Yield CPU */ + if (!in_interrupt()) + schedule(); + else { + for (i = 0; i < 20; i++) + cpu_relax(); /*This a nop instr on i386*/ + } + } + qla4_8xxx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER); + return 0; +} + +static void +qla4_8xxx_rom_unlock(struct scsi_qla_host *ha) +{ + qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); +} + +static int +qla4_8xxx_wait_rom_done(struct scsi_qla_host *ha) +{ + long timeout = 0; + long done = 0 ; + + while (done == 0) { + done = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); + done &= 2; + timeout++; + if (timeout >= rom_max_timeout) { + printk("%s: Timeout reached waiting for rom done", + DRIVER_NAME); + return -1; + } + } + return 0; +} + +static int +qla4_8xxx_do_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp) +{ + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb); + if (qla4_8xxx_wait_rom_done(ha)) { + printk("%s: Error waiting for rom done\n", DRIVER_NAME); + return -1; + } + /* reset abyte_cnt and dummy_byte_cnt */ + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); + udelay(10); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); + + *valp = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA); + return 0; +} + +static int +qla4_8xxx_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp) +{ + int ret, loops = 0; + + while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) { + udelay(100); + loops++; + } + if (loops >= 50000) { + printk("%s: qla4_8xxx_rom_lock failed\n", DRIVER_NAME); + return -1; + } + ret = qla4_8xxx_do_rom_fast_read(ha, addr, valp); + qla4_8xxx_rom_unlock(ha); + return ret; +} + +/** + * This routine does CRB initialize sequence + * to put the ISP into operational state + **/ +static int +qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) +{ + int addr, val; + int i ; + struct crb_addr_pair *buf; + unsigned long off; + unsigned offset, n; + + struct crb_addr_pair { + long addr; + long data; + }; + + /* Halt all the indiviual PEGs and other blocks of the ISP */ + qla4_8xxx_rom_lock(ha); + if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) + /* don't reset CAM block on reset */ + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); + else + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); + + qla4_8xxx_rom_unlock(ha); + + /* Read the signature value from the flash. + * Offset 0: Contain signature (0xcafecafe) + * Offset 4: Offset and number of addr/value pairs + * that present in CRB initialize sequence + */ + if (qla4_8xxx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL || + qla4_8xxx_rom_fast_read(ha, 4, &n) != 0) { + ql4_printk(KERN_WARNING, ha, + "[ERROR] Reading crb_init area: n: %08x\n", n); + return -1; + } + + /* Offset in flash = lower 16 bits + * Number of enteries = upper 16 bits + */ + offset = n & 0xffffU; + n = (n >> 16) & 0xffffU; + + /* number of addr/value pair should not exceed 1024 enteries */ + if (n >= 1024) { + ql4_printk(KERN_WARNING, ha, + "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n", + DRIVER_NAME, __func__, n); + return -1; + } + + ql4_printk(KERN_INFO, ha, + "%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n); + + buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); + if (buf == NULL) { + ql4_printk(KERN_WARNING, ha, + "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME); + return -1; + } + + for (i = 0; i < n; i++) { + if (qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 || + qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != + 0) { + kfree(buf); + return -1; + } + + buf[i].addr = addr; + buf[i].data = val; + } + + for (i = 0; i < n; i++) { + /* Translate internal CRB initialization + * address to PCI bus address + */ + off = qla4_8xxx_decode_crb_addr((unsigned long)buf[i].addr) + + QLA82XX_PCI_CRBSPACE; + /* Not all CRB addr/value pair to be written, + * some of them are skipped + */ + + /* skip if LS bit is set*/ + if (off & 0x1) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Skip CRB init replay for offset = 0x%lx\n", off)); + continue; + } + + /* skipping cold reboot MAGIC */ + if (off == QLA82XX_CAM_RAM(0x1fc)) + continue; + + /* do not reset PCI */ + if (off == (ROMUSB_GLB + 0xbc)) + continue; + + /* skip core clock, so that firmware can increase the clock */ + if (off == (ROMUSB_GLB + 0xc8)) + continue; + + /* skip the function enable register */ + if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION)) + continue; + + if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2)) + continue; + + if ((off & 0x0ff00000) == QLA82XX_CRB_SMB) + continue; + + if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET) + continue; + + if (off == ADDR_ERROR) { + ql4_printk(KERN_WARNING, ha, + "%s: [ERROR] Unknown addr: 0x%08lx\n", + DRIVER_NAME, buf[i].addr); + continue; + } + + qla4_8xxx_wr_32(ha, off, buf[i].data); + + /* ISP requires much bigger delay to settle down, + * else crb_window returns 0xffffffff + */ + if (off == QLA82XX_ROMUSB_GLB_SW_RESET) + msleep(1000); + + /* ISP requires millisec delay between + * successive CRB register updation + */ + msleep(1); + } + + kfree(buf); + + /* Resetting the data and instruction cache */ + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8); + + /* Clear all protocol processing engines */ + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0); + + return 0; +} + +static int qla4_8xxx_check_for_bad_spd(struct scsi_qla_host *ha) +{ + u32 val = 0; + val = qla4_8xxx_rd_32(ha, BOOT_LOADER_DIMM_STATUS) ; + val &= QLA82XX_BOOT_LOADER_MN_ISSUE; + if (val & QLA82XX_PEG_TUNE_MN_SPD_ZEROED) { + printk("Memory DIMM SPD not programmed. Assumed valid.\n"); + return 1; + } else if (val) { + printk("Memory DIMM type incorrect. Info:%08X.\n", val); + return 2; + } + return 0; +} + +static int +qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start) +{ + int i; + long size = 0; + long flashaddr, memaddr; + u64 data; + u32 high, low; + + flashaddr = memaddr = ha->hw.flt_region_bootload; + size = (image_start - flashaddr)/8; + + DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n", + ha->host_no, __func__, flashaddr, image_start)); + + for (i = 0; i < size; i++) { + if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) || + (qla4_8xxx_rom_fast_read(ha, flashaddr + 4, + (int *)&high))) { + return -1; + } + data = ((u64)high << 32) | low ; + qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8); + flashaddr += 8; + memaddr += 8; + + if (i%0x1000 == 0) + msleep(1); + + } + + udelay(100); + + read_lock(&ha->hw_lock); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); + read_unlock(&ha->hw_lock); + + return 0; +} + +static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start) +{ + u32 rst; + + qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0); + if (qla4_8xxx_pinit_from_rom(ha, 0) != QLA_SUCCESS) { + printk(KERN_WARNING "%s: Error during CRB Initialization\n", + __func__); + return QLA_ERROR; + } + + udelay(500); + + /* at this point, QM is in reset. This could be a problem if there are + * incoming d* transition queue messages. QM/PCIE could wedge. + * To get around this, QM is brought out of reset. + */ + + rst = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET); + /* unreset qm */ + rst &= ~(1 << 28); + qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst); + + if (qla4_8xxx_load_from_flash(ha, image_start)) { + printk("%s: Error trying to load fw from flash!\n", __func__); + return QLA_ERROR; + } + + return QLA_SUCCESS; +} + +int +qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha, + u64 off, void *data, int size) +{ + int i, j = 0, k, start, end, loop, sz[2], off0[2]; + int shift_amount; + uint32_t temp; + uint64_t off8, val, mem_crb, word[2] = {0, 0}; + + /* + * If not MN, go check for MS or invalid. + */ + + if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) + mem_crb = QLA82XX_CRB_QDR_NET; + else { + mem_crb = QLA82XX_CRB_DDR_NET; + if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0) + return qla4_8xxx_pci_mem_read_direct(ha, + off, data, size); + } + + + off8 = off & 0xfffffff0; + off0[0] = off & 0xf; + sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); + shift_amount = 4; + + loop = ((off0[0] + size - 1) >> shift_amount) + 1; + off0[1] = 0; + sz[1] = size - sz[0]; + + for (i = 0; i < loop; i++) { + temp = off8 + (i << shift_amount); + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); + temp = 0; + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); + temp = MIU_TA_CTL_ENABLE; + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); + if ((temp & MIU_TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + ql4_printk(KERN_ERR, ha, + "failed to read through agent\n"); + break; + } + + start = off0[i] >> 2; + end = (off0[i] + sz[i] - 1) >> 2; + for (k = start; k <= end; k++) { + temp = qla4_8xxx_rd_32(ha, + mem_crb + MIU_TEST_AGT_RDDATA(k)); + word[i] |= ((uint64_t)temp << (32 * (k & 1))); + } + } + + if (j >= MAX_CTL_CHECK) + return -1; + + if ((off0[0] & 7) == 0) { + val = word[0]; + } else { + val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | + ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); + } + + switch (size) { + case 1: + *(uint8_t *)data = val; + break; + case 2: + *(uint16_t *)data = val; + break; + case 4: + *(uint32_t *)data = val; + break; + case 8: + *(uint64_t *)data = val; + break; + } + return 0; +} + +int +qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, + u64 off, void *data, int size) +{ + int i, j, ret = 0, loop, sz[2], off0; + int scale, shift_amount, startword; + uint32_t temp; + uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; + + /* + * If not MN, go check for MS or invalid. + */ + if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) + mem_crb = QLA82XX_CRB_QDR_NET; + else { + mem_crb = QLA82XX_CRB_DDR_NET; + if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0) + return qla4_8xxx_pci_mem_write_direct(ha, + off, data, size); + } + + off0 = off & 0x7; + sz[0] = (size < (8 - off0)) ? size : (8 - off0); + sz[1] = size - sz[0]; + + off8 = off & 0xfffffff0; + loop = (((off & 0xf) + size - 1) >> 4) + 1; + shift_amount = 4; + scale = 2; + startword = (off & 0xf)/8; + + for (i = 0; i < loop; i++) { + if (qla4_8xxx_pci_mem_read_2M(ha, off8 + + (i << shift_amount), &word[i * scale], 8)) + return -1; + } + + switch (size) { + case 1: + tmpw = *((uint8_t *)data); + break; + case 2: + tmpw = *((uint16_t *)data); + break; + case 4: + tmpw = *((uint32_t *)data); + break; + case 8: + default: + tmpw = *((uint64_t *)data); + break; + } + + if (sz[0] == 8) + word[startword] = tmpw; + else { + word[startword] &= + ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); + word[startword] |= tmpw << (off0 * 8); + } + + if (sz[1] != 0) { + word[startword+1] &= ~(~0ULL << (sz[1] * 8)); + word[startword+1] |= tmpw >> (sz[0] * 8); + } + + for (i = 0; i < loop; i++) { + temp = off8 + (i << shift_amount); + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); + temp = 0; + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); + temp = word[i * scale] & 0xffffffff; + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); + temp = (word[i * scale] >> 32) & 0xffffffff; + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); + temp = word[i*scale + 1] & 0xffffffff; + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO, + temp); + temp = (word[i*scale + 1] >> 32) & 0xffffffff; + qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI, + temp); + + temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); + temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; + qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); + + for (j = 0; j < MAX_CTL_CHECK; j++) { + temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); + if ((temp & MIU_TA_CTL_BUSY) == 0) + break; + } + + if (j >= MAX_CTL_CHECK) { + if (printk_ratelimit()) + ql4_printk(KERN_ERR, ha, + "failed to write through agent\n"); + ret = -1; + break; + } + } + + return ret; +} + +static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val) +{ + u32 val = 0; + int retries = 60; + + if (!pegtune_val) { + do { + val = qla4_8xxx_rd_32(ha, CRB_CMDPEG_STATE); + if ((val == PHAN_INITIALIZE_COMPLETE) || + (val == PHAN_INITIALIZE_ACK)) + return 0; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(500); + + } while (--retries); + + qla4_8xxx_check_for_bad_spd(ha); + + if (!retries) { + pegtune_val = qla4_8xxx_rd_32(ha, + QLA82XX_ROMUSB_GLB_PEGTUNE_DONE); + printk(KERN_WARNING "%s: init failed, " + "pegtune_val = %x\n", __func__, pegtune_val); + return -1; + } + } + return 0; +} + +static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha) +{ + uint32_t state = 0; + int loops = 0; + + /* Window 1 call */ + read_lock(&ha->hw_lock); + state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE); + read_unlock(&ha->hw_lock); + + while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 30000)) { + udelay(100); + /* Window 1 call */ + read_lock(&ha->hw_lock); + state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE); + read_unlock(&ha->hw_lock); + + loops++; + } + + if (loops >= 30000) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Receive Peg initialization not complete: 0x%x.\n", state)); + return QLA_ERROR; + } + + return QLA_SUCCESS; +} + +static inline void +qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) +{ + uint32_t drv_active; + + drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + drv_active |= (1 << (ha->func_num * 4)); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); +} + +void +qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) +{ + uint32_t drv_active; + + drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + drv_active &= ~(1 << (ha->func_num * 4)); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); +} + +static inline int +qla4_8xxx_need_reset(struct scsi_qla_host *ha) +{ + uint32_t drv_state; + int rval; + + drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + rval = drv_state & (1 << (ha->func_num * 4)); + return rval; +} + +static inline void +qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) +{ + uint32_t drv_state; + + drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + drv_state |= (1 << (ha->func_num * 4)); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); +} + +static inline void +qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) +{ + uint32_t drv_state; + + drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + drv_state &= ~(1 << (ha->func_num * 4)); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); +} + +static inline void +qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha) +{ + uint32_t qsnt_state; + + qsnt_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + qsnt_state |= (2 << (ha->func_num * 4)); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); +} + + +static int +qla4_8xxx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start) +{ + int pcie_cap; + uint16_t lnk; + + /* scrub dma mask expansion register */ + qla4_8xxx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); + + /* Overwrite stale initialization register values */ + qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0); + qla4_8xxx_wr_32(ha, CRB_RCVPEG_STATE, 0); + qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); + qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0); + + if (qla4_8xxx_load_fw(ha, image_start) != QLA_SUCCESS) { + printk("%s: Error trying to start fw!\n", __func__); + return QLA_ERROR; + } + + /* Handshake with the card before we register the devices. */ + if (qla4_8xxx_cmdpeg_ready(ha, 0) != QLA_SUCCESS) { + printk("%s: Error during card handshake!\n", __func__); + return QLA_ERROR; + } + + /* Negotiated Link width */ + pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); + pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk); + ha->link_width = (lnk >> 4) & 0x3f; + + /* Synchronize with Receive peg */ + return qla4_8xxx_rcvpeg_ready(ha); +} + +static int +qla4_8xxx_try_start_fw(struct scsi_qla_host *ha) +{ + int rval = QLA_ERROR; + + /* + * FW Load priority: + * 1) Operational firmware residing in flash. + * 2) Fail + */ + + ql4_printk(KERN_INFO, ha, + "FW: Retrieving flash offsets from FLT/FDT ...\n"); + rval = qla4_8xxx_get_flash_info(ha); + if (rval != QLA_SUCCESS) + return rval; + + ql4_printk(KERN_INFO, ha, + "FW: Attempting to load firmware from flash...\n"); + rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw); + if (rval == QLA_SUCCESS) + return rval; + + ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash FAILED...\n"); + + return rval; +} + +/** + * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw + * @ha: pointer to adapter structure + * + * Note: IDC lock must be held upon entry + **/ +static int +qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha) +{ + int rval, i, timeout; + uint32_t old_count, count; + + if (qla4_8xxx_need_reset(ha)) + goto dev_initialize; + + old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + + for (i = 0; i < 10; i++) { + timeout = msleep_interruptible(200); + if (timeout) { + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + return QLA_ERROR; + } + + count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + if (count != old_count) + goto dev_ready; + } + +dev_initialize: + /* set to DEV_INITIALIZING */ + ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING); + + /* Driver that sets device state to initializating sets IDC version */ + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); + + qla4_8xxx_idc_unlock(ha); + rval = qla4_8xxx_try_start_fw(ha); + qla4_8xxx_idc_lock(ha); + + if (rval != QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); + qla4_8xxx_clear_drv_active(ha); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED); + return rval; + } + +dev_ready: + ql4_printk(KERN_INFO, ha, "HW State: READY\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY); + + return QLA_SUCCESS; +} + +/** + * qla4_8xxx_need_reset_handler - Code to start reset sequence + * @ha: pointer to adapter structure + * + * Note: IDC lock must be held upon entry + **/ +static void +qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) +{ + uint32_t dev_state, drv_state, drv_active; + unsigned long reset_timeout; + + ql4_printk(KERN_INFO, ha, + "Performing ISP error recovery\n"); + + if (test_and_clear_bit(AF_ONLINE, &ha->flags)) { + qla4_8xxx_idc_unlock(ha); + ha->isp_ops->disable_intrs(ha); + qla4_8xxx_idc_lock(ha); + } + + qla4_8xxx_set_rst_ready(ha); + + /* wait for 10 seconds for reset ack from all functions */ + reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); + + drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + + ql4_printk(KERN_INFO, ha, + "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", + __func__, ha->host_no, drv_state, drv_active); + + while (drv_state != drv_active) { + if (time_after_eq(jiffies, reset_timeout)) { + printk("%s: RESET TIMEOUT!\n", DRIVER_NAME); + break; + } + + qla4_8xxx_idc_unlock(ha); + msleep(1000); + qla4_8xxx_idc_lock(ha); + + drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); + drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); + } + + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + + /* Force to DEV_COLD unless someone else is starting a reset */ + if (dev_state != QLA82XX_DEV_INITIALIZING) { + ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); + } +} + +/** + * qla4_8xxx_need_qsnt_handler - Code to start qsnt + * @ha: pointer to adapter structure + **/ +void +qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha) +{ + qla4_8xxx_idc_lock(ha); + qla4_8xxx_set_qsnt_ready(ha); + qla4_8xxx_idc_unlock(ha); +} + +/** + * qla4_8xxx_device_state_handler - Adapter state machine + * @ha: pointer to host adapter structure. + * + * Note: IDC lock must be UNLOCKED upon entry + **/ +int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) +{ + uint32_t dev_state; + int rval = QLA_SUCCESS; + unsigned long dev_init_timeout; + + if (!test_bit(AF_INIT_DONE, &ha->flags)) + qla4_8xxx_set_drv_active(ha); + + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + + /* wait for 30 seconds for device to go ready */ + dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); + + while (1) { + qla4_8xxx_idc_lock(ha); + + if (time_after_eq(jiffies, dev_init_timeout)) { + ql4_printk(KERN_WARNING, ha, "Device init failed!\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + } + + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + ql4_printk(KERN_INFO, ha, + "2:Device state is 0x%x = %s\n", dev_state, + dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); + + /* NOTE: Make sure idc unlocked upon exit of switch statement */ + switch (dev_state) { + case QLA82XX_DEV_READY: + qla4_8xxx_idc_unlock(ha); + goto exit; + case QLA82XX_DEV_COLD: + rval = qla4_8xxx_device_bootstrap(ha); + qla4_8xxx_idc_unlock(ha); + goto exit; + case QLA82XX_DEV_INITIALIZING: + qla4_8xxx_idc_unlock(ha); + msleep(1000); + break; + case QLA82XX_DEV_NEED_RESET: + if (!ql4xdontresethba) { + qla4_8xxx_need_reset_handler(ha); + /* Update timeout value after need + * reset handler */ + dev_init_timeout = jiffies + + (ha->nx_dev_init_timeout * HZ); + } + qla4_8xxx_idc_unlock(ha); + break; + case QLA82XX_DEV_NEED_QUIESCENT: + qla4_8xxx_idc_unlock(ha); + /* idc locked/unlocked in handler */ + qla4_8xxx_need_qsnt_handler(ha); + qla4_8xxx_idc_lock(ha); + /* fall thru needs idc_locked */ + case QLA82XX_DEV_QUIESCENT: + qla4_8xxx_idc_unlock(ha); + msleep(1000); + break; + case QLA82XX_DEV_FAILED: + qla4_8xxx_idc_unlock(ha); + qla4xxx_dead_adapter_cleanup(ha); + rval = QLA_ERROR; + goto exit; + default: + qla4_8xxx_idc_unlock(ha); + qla4xxx_dead_adapter_cleanup(ha); + rval = QLA_ERROR; + goto exit; + } + } +exit: + return rval; +} + +int qla4_8xxx_load_risc(struct scsi_qla_host *ha) +{ + int retval; + retval = qla4_8xxx_device_state_handler(ha); + + if (retval == QLA_SUCCESS && + !test_bit(AF_INIT_DONE, &ha->flags)) { + retval = qla4xxx_request_irqs(ha); + if (retval != QLA_SUCCESS) { + ql4_printk(KERN_WARNING, ha, + "Failed to reserve interrupt %d already in use.\n", + ha->pdev->irq); + } else { + set_bit(AF_IRQ_ATTACHED, &ha->flags); + ha->host->irq = ha->pdev->irq; + ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n", + __func__, ha->pdev->irq); + } + } + return retval; +} + +/*****************************************************************************/ +/* Flash Manipulation Routines */ +/*****************************************************************************/ + +#define OPTROM_BURST_SIZE 0x1000 +#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) + +#define FARX_DATA_FLAG BIT_31 +#define FARX_ACCESS_FLASH_CONF 0x7FFD0000 +#define FARX_ACCESS_FLASH_DATA 0x7FF00000 + +static inline uint32_t +flash_conf_addr(struct ql82xx_hw_data *hw, uint32_t faddr) +{ + return hw->flash_conf_off | faddr; +} + +static inline uint32_t +flash_data_addr(struct ql82xx_hw_data *hw, uint32_t faddr) +{ + return hw->flash_data_off | faddr; +} + +static uint32_t * +qla4_8xxx_read_flash_data(struct scsi_qla_host *ha, uint32_t *dwptr, + uint32_t faddr, uint32_t length) +{ + uint32_t i; + uint32_t val; + int loops = 0; + while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) { + udelay(100); + cond_resched(); + loops++; + } + if (loops >= 50000) { + ql4_printk(KERN_WARNING, ha, "ROM lock failed\n"); + return dwptr; + } + + /* Dword reads to flash. */ + for (i = 0; i < length/4; i++, faddr += 4) { + if (qla4_8xxx_do_rom_fast_read(ha, faddr, &val)) { + ql4_printk(KERN_WARNING, ha, + "Do ROM fast read failed\n"); + goto done_read; + } + dwptr[i] = __constant_cpu_to_le32(val); + } + +done_read: + qla4_8xxx_rom_unlock(ha); + return dwptr; +} + +/** + * Address and length are byte address + **/ +static uint8_t * +qla4_8xxx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, + uint32_t offset, uint32_t length) +{ + qla4_8xxx_read_flash_data(ha, (uint32_t *)buf, offset, length); + return buf; +} + +static int +qla4_8xxx_find_flt_start(struct scsi_qla_host *ha, uint32_t *start) +{ + const char *loc, *locations[] = { "DEF", "PCI" }; + + /* + * FLT-location structure resides after the last PCI region. + */ + + /* Begin with sane defaults. */ + loc = locations[0]; + *start = FA_FLASH_LAYOUT_ADDR_82; + + DEBUG2(ql4_printk(KERN_INFO, ha, "FLTL[%s] = 0x%x.\n", loc, *start)); + return QLA_SUCCESS; +} + +static void +qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) +{ + const char *loc, *locations[] = { "DEF", "FLT" }; + uint16_t *wptr; + uint16_t cnt, chksum; + uint32_t start; + struct qla_flt_header *flt; + struct qla_flt_region *region; + struct ql82xx_hw_data *hw = &ha->hw; + + hw->flt_region_flt = flt_addr; + wptr = (uint16_t *)ha->request_ring; + flt = (struct qla_flt_header *)ha->request_ring; + region = (struct qla_flt_region *)&flt[1]; + qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, + flt_addr << 2, OPTROM_BURST_SIZE); + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + if (flt->version != __constant_cpu_to_le16(1)) { + DEBUG2(ql4_printk(KERN_INFO, ha, "Unsupported FLT detected: " + "version=0x%x length=0x%x checksum=0x%x.\n", + le16_to_cpu(flt->version), le16_to_cpu(flt->length), + le16_to_cpu(flt->checksum))); + goto no_flash_data; + } + + cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1; + for (chksum = 0; cnt; cnt--) + chksum += le16_to_cpu(*wptr++); + if (chksum) { + DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FLT detected: " + "version=0x%x length=0x%x checksum=0x%x.\n", + le16_to_cpu(flt->version), le16_to_cpu(flt->length), + chksum)); + goto no_flash_data; + } + + loc = locations[1]; + cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); + for ( ; cnt; cnt--, region++) { + /* Store addresses as DWORD offsets. */ + start = le32_to_cpu(region->start) >> 2; + + DEBUG3(ql4_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x " + "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start, + le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size))); + + switch (le32_to_cpu(region->code) & 0xff) { + case FLT_REG_FDT: + hw->flt_region_fdt = start; + break; + case FLT_REG_BOOT_CODE_82: + hw->flt_region_boot = start; + break; + case FLT_REG_FW_82: + hw->flt_region_fw = start; + break; + case FLT_REG_BOOTLOAD_82: + hw->flt_region_bootload = start; + break; + } + } + goto done; + +no_flash_data: + /* Use hardcoded defaults. */ + loc = locations[0]; + + hw->flt_region_fdt = FA_FLASH_DESCR_ADDR_82; + hw->flt_region_boot = FA_BOOT_CODE_ADDR_82; + hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82; + hw->flt_region_fw = FA_RISC_CODE_ADDR_82; +done: + DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x " + "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt, + hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload, + hw->flt_region_fw)); +} + +static void +qla4_8xxx_get_fdt_info(struct scsi_qla_host *ha) +{ +#define FLASH_BLK_SIZE_4K 0x1000 +#define FLASH_BLK_SIZE_32K 0x8000 +#define FLASH_BLK_SIZE_64K 0x10000 + const char *loc, *locations[] = { "MID", "FDT" }; + uint16_t cnt, chksum; + uint16_t *wptr; + struct qla_fdt_layout *fdt; + uint16_t mid, fid; + struct ql82xx_hw_data *hw = &ha->hw; + + hw->flash_conf_off = FARX_ACCESS_FLASH_CONF; + hw->flash_data_off = FARX_ACCESS_FLASH_DATA; + + wptr = (uint16_t *)ha->request_ring; + fdt = (struct qla_fdt_layout *)ha->request_ring; + qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, + hw->flt_region_fdt << 2, OPTROM_BURST_SIZE); + + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + + if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || + fdt->sig[3] != 'D') + goto no_flash_data; + + for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; + cnt++) + chksum += le16_to_cpu(*wptr++); + + if (chksum) { + DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FDT detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], + le16_to_cpu(fdt->version))); + goto no_flash_data; + } + + loc = locations[1]; + mid = le16_to_cpu(fdt->man_id); + fid = le16_to_cpu(fdt->id); + hw->fdt_wrt_disable = fdt->wrt_disable_bits; + hw->fdt_erase_cmd = flash_conf_addr(hw, 0x0300 | fdt->erase_cmd); + hw->fdt_block_size = le32_to_cpu(fdt->block_size); + + if (fdt->unprotect_sec_cmd) { + hw->fdt_unprotect_sec_cmd = flash_conf_addr(hw, 0x0300 | + fdt->unprotect_sec_cmd); + hw->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? + flash_conf_addr(hw, 0x0300 | fdt->protect_sec_cmd) : + flash_conf_addr(hw, 0x0336); + } + goto done; + +no_flash_data: + loc = locations[0]; + hw->fdt_block_size = FLASH_BLK_SIZE_64K; +done: + DEBUG2(ql4_printk(KERN_INFO, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid, + hw->fdt_erase_cmd, hw->fdt_protect_sec_cmd, + hw->fdt_unprotect_sec_cmd, hw->fdt_wrt_disable, + hw->fdt_block_size)); +} + +static void +qla4_8xxx_get_idc_param(struct scsi_qla_host *ha) +{ +#define QLA82XX_IDC_PARAM_ADDR 0x003e885c + uint32_t *wptr; + + if (!is_qla8022(ha)) + return; + wptr = (uint32_t *)ha->request_ring; + qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, + QLA82XX_IDC_PARAM_ADDR , 8); + + if (*wptr == __constant_cpu_to_le32(0xffffffff)) { + ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT; + ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT; + } else { + ha->nx_dev_init_timeout = le32_to_cpu(*wptr++); + ha->nx_reset_timeout = le32_to_cpu(*wptr); + } + + DEBUG2(ql4_printk(KERN_DEBUG, ha, + "ha->nx_dev_init_timeout = %d\n", ha->nx_dev_init_timeout)); + DEBUG2(ql4_printk(KERN_DEBUG, ha, + "ha->nx_reset_timeout = %d\n", ha->nx_reset_timeout)); + return; +} + +int +qla4_8xxx_get_flash_info(struct scsi_qla_host *ha) +{ + int ret; + uint32_t flt_addr; + + ret = qla4_8xxx_find_flt_start(ha, &flt_addr); + if (ret != QLA_SUCCESS) + return ret; + + qla4_8xxx_get_flt_info(ha, flt_addr); + qla4_8xxx_get_fdt_info(ha); + qla4_8xxx_get_idc_param(ha); + + return QLA_SUCCESS; +} + +/** + * qla4_8xxx_stop_firmware - stops firmware on specified adapter instance + * @ha: pointer to host adapter structure. + * + * Remarks: + * For iSCSI, throws away all I/O and AENs into bit bucket, so they will + * not be available after successful return. Driver must cleanup potential + * outstanding I/O's after calling this funcion. + **/ +int +qla4_8xxx_stop_firmware(struct scsi_qla_host *ha) +{ + int status; + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_STOP_FW; + status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, + &mbox_cmd[0], &mbox_sts[0]); + + DEBUG2(printk("scsi%ld: %s: status = %d\n", ha->host_no, + __func__, status)); + return status; +} + +/** + * qla4_8xxx_isp_reset - Resets ISP and aborts all outstanding commands. + * @ha: pointer to host adapter structure. + **/ +int +qla4_8xxx_isp_reset(struct scsi_qla_host *ha) +{ + int rval; + uint32_t dev_state; + + qla4_8xxx_idc_lock(ha); + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + + if (dev_state == QLA82XX_DEV_READY) { + ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_NEED_RESET); + } else + ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n"); + + qla4_8xxx_idc_unlock(ha); + + rval = qla4_8xxx_device_state_handler(ha); + + qla4_8xxx_idc_lock(ha); + qla4_8xxx_clear_rst_ready(ha); + qla4_8xxx_idc_unlock(ha); + + return rval; +} + +/** + * qla4_8xxx_get_sys_info - get adapter MAC address(es) and serial number + * @ha: pointer to host adapter structure. + * + **/ +int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + struct mbx_sys_info *sys_info; + dma_addr_t sys_info_dma; + int status = QLA_ERROR; + + sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), + &sys_info_dma, GFP_KERNEL); + if (sys_info == NULL) { + DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", + ha->host_no, __func__)); + return status; + } + + memset(sys_info, 0, sizeof(*sys_info)); + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_GET_SYS_INFO; + mbox_cmd[1] = LSDW(sys_info_dma); + mbox_cmd[2] = MSDW(sys_info_dma); + mbox_cmd[4] = sizeof(*sys_info); + + if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 6, &mbox_cmd[0], + &mbox_sts[0]) != QLA_SUCCESS) { + DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO failed\n", + ha->host_no, __func__)); + goto exit_validate_mac82; + } + + if (mbox_sts[4] < sizeof(*sys_info)) { + DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive" + " error (%x)\n", ha->host_no, __func__, mbox_sts[4])); + goto exit_validate_mac82; + + } + + /* Save M.A.C. address & serial_number */ + memcpy(ha->my_mac, &sys_info->mac_addr[0], + min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr))); + memcpy(ha->serial_number, &sys_info->serial_number, + min(sizeof(ha->serial_number), sizeof(sys_info->serial_number))); + + DEBUG2(printk("scsi%ld: %s: " + "mac %02x:%02x:%02x:%02x:%02x:%02x " + "serial %s\n", ha->host_no, __func__, + ha->my_mac[0], ha->my_mac[1], ha->my_mac[2], + ha->my_mac[3], ha->my_mac[4], ha->my_mac[5], + ha->serial_number)); + + status = QLA_SUCCESS; + +exit_validate_mac82: + dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, + sys_info_dma); + return status; +} + +/* Interrupt handling helpers. */ + +static int +qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__)); + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS; + mbox_cmd[1] = INTR_ENABLE; + if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], + &mbox_sts[0]) != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n", + __func__, mbox_sts[0])); + return QLA_ERROR; + } + return QLA_SUCCESS; +} + +static int +qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + + DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__)); + + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS; + mbox_cmd[1] = INTR_DISABLE; + if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], + &mbox_sts[0]) != QLA_SUCCESS) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n", + __func__, mbox_sts[0])); + return QLA_ERROR; + } + + return QLA_SUCCESS; +} + +void +qla4_8xxx_enable_intrs(struct scsi_qla_host *ha) +{ + qla4_8xxx_mbx_intr_enable(ha); + + spin_lock_irq(&ha->hardware_lock); + /* BIT 10 - reset */ + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); + spin_unlock_irq(&ha->hardware_lock); + set_bit(AF_INTERRUPTS_ON, &ha->flags); +} + +void +qla4_8xxx_disable_intrs(struct scsi_qla_host *ha) +{ + if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) + qla4_8xxx_mbx_intr_disable(ha); + + spin_lock_irq(&ha->hardware_lock); + /* BIT 10 - set */ + qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); + spin_unlock_irq(&ha->hardware_lock); + clear_bit(AF_INTERRUPTS_ON, &ha->flags); +} + +struct ql4_init_msix_entry { + uint16_t entry; + uint16_t index; + const char *name; + irq_handler_t handler; +}; + +static struct ql4_init_msix_entry qla4_8xxx_msix_entries[QLA_MSIX_ENTRIES] = { + { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, + "qla4xxx (default)", + (irq_handler_t)qla4_8xxx_default_intr_handler }, + { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, + "qla4xxx (rsp_q)", (irq_handler_t)qla4_8xxx_msix_rsp_q }, +}; + +void +qla4_8xxx_disable_msix(struct scsi_qla_host *ha) +{ + int i; + struct ql4_msix_entry *qentry; + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) { + qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index]; + if (qentry->have_irq) { + free_irq(qentry->msix_vector, ha); + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n", + __func__, qla4_8xxx_msix_entries[i].name)); + } + } + pci_disable_msix(ha->pdev); + clear_bit(AF_MSIX_ENABLED, &ha->flags); +} + +int +qla4_8xxx_enable_msix(struct scsi_qla_host *ha) +{ + int i, ret; + struct msix_entry entries[QLA_MSIX_ENTRIES]; + struct ql4_msix_entry *qentry; + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) + entries[i].entry = qla4_8xxx_msix_entries[i].entry; + + ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); + if (ret) { + ql4_printk(KERN_WARNING, ha, + "MSI-X: Failed to enable support -- %d/%d\n", + QLA_MSIX_ENTRIES, ret); + goto msix_out; + } + set_bit(AF_MSIX_ENABLED, &ha->flags); + + for (i = 0; i < QLA_MSIX_ENTRIES; i++) { + qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index]; + qentry->msix_vector = entries[i].vector; + qentry->msix_entry = entries[i].entry; + qentry->have_irq = 0; + ret = request_irq(qentry->msix_vector, + qla4_8xxx_msix_entries[i].handler, 0, + qla4_8xxx_msix_entries[i].name, ha); + if (ret) { + ql4_printk(KERN_WARNING, ha, + "MSI-X: Unable to register handler -- %x/%d.\n", + qla4_8xxx_msix_entries[i].index, ret); + qla4_8xxx_disable_msix(ha); + goto msix_out; + } + qentry->have_irq = 1; + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n", + __func__, qla4_8xxx_msix_entries[i].name)); + } +msix_out: + return ret; +} diff --git a/drivers/scsi/qla4xxx/ql4_nx.h b/drivers/scsi/qla4xxx/ql4_nx.h new file mode 100644 index 00000000000..931ad3f1e91 --- /dev/null +++ b/drivers/scsi/qla4xxx/ql4_nx.h @@ -0,0 +1,779 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2008 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#ifndef __QLA_NX_H +#define __QLA_NX_H + +/* + * Following are the states of the Phantom. Phantom will set them and + * Host will read to check if the fields are correct. +*/ +#define PHAN_INITIALIZE_FAILED 0xffff +#define PHAN_INITIALIZE_COMPLETE 0xff01 + +/* Host writes the following to notify that it has done the init-handshake */ +#define PHAN_INITIALIZE_ACK 0xf00f +#define PHAN_PEG_RCV_INITIALIZED 0xff01 + +/*CRB_RELATED*/ +#define QLA82XX_CRB_BASE QLA82XX_CAM_RAM(0x200) +#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) + +#define CRB_CMDPEG_STATE QLA82XX_REG(0x50) +#define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) +#define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54) +#define CRB_DMA_SHIFT QLA82XX_REG(0xcc) + +#define QLA82XX_HW_H0_CH_HUB_ADR 0x05 +#define QLA82XX_HW_H1_CH_HUB_ADR 0x0E +#define QLA82XX_HW_H2_CH_HUB_ADR 0x03 +#define QLA82XX_HW_H3_CH_HUB_ADR 0x01 +#define QLA82XX_HW_H4_CH_HUB_ADR 0x06 +#define QLA82XX_HW_H5_CH_HUB_ADR 0x07 +#define QLA82XX_HW_H6_CH_HUB_ADR 0x08 + +/* Hub 0 */ +#define QLA82XX_HW_MN_CRB_AGT_ADR 0x15 +#define QLA82XX_HW_MS_CRB_AGT_ADR 0x25 + +/* Hub 1 */ +#define QLA82XX_HW_PS_CRB_AGT_ADR 0x73 +#define QLA82XX_HW_QMS_CRB_AGT_ADR 0x00 +#define QLA82XX_HW_RPMX3_CRB_AGT_ADR 0x0b +#define QLA82XX_HW_SQGS0_CRB_AGT_ADR 0x01 +#define QLA82XX_HW_SQGS1_CRB_AGT_ADR 0x02 +#define QLA82XX_HW_SQGS2_CRB_AGT_ADR 0x03 +#define QLA82XX_HW_SQGS3_CRB_AGT_ADR 0x04 +#define QLA82XX_HW_C2C0_CRB_AGT_ADR 0x58 +#define QLA82XX_HW_C2C1_CRB_AGT_ADR 0x59 +#define QLA82XX_HW_C2C2_CRB_AGT_ADR 0x5a +#define QLA82XX_HW_RPMX2_CRB_AGT_ADR 0x0a +#define QLA82XX_HW_RPMX4_CRB_AGT_ADR 0x0c +#define QLA82XX_HW_RPMX7_CRB_AGT_ADR 0x0f +#define QLA82XX_HW_RPMX9_CRB_AGT_ADR 0x12 +#define QLA82XX_HW_SMB_CRB_AGT_ADR 0x18 + +/* Hub 2 */ +#define QLA82XX_HW_NIU_CRB_AGT_ADR 0x31 +#define QLA82XX_HW_I2C0_CRB_AGT_ADR 0x19 +#define QLA82XX_HW_I2C1_CRB_AGT_ADR 0x29 + +#define QLA82XX_HW_SN_CRB_AGT_ADR 0x10 +#define QLA82XX_HW_I2Q_CRB_AGT_ADR 0x20 +#define QLA82XX_HW_LPC_CRB_AGT_ADR 0x22 +#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR 0x21 +#define QLA82XX_HW_QM_CRB_AGT_ADR 0x66 +#define QLA82XX_HW_SQG0_CRB_AGT_ADR 0x60 +#define QLA82XX_HW_SQG1_CRB_AGT_ADR 0x61 +#define QLA82XX_HW_SQG2_CRB_AGT_ADR 0x62 +#define QLA82XX_HW_SQG3_CRB_AGT_ADR 0x63 +#define QLA82XX_HW_RPMX1_CRB_AGT_ADR 0x09 +#define QLA82XX_HW_RPMX5_CRB_AGT_ADR 0x0d +#define QLA82XX_HW_RPMX6_CRB_AGT_ADR 0x0e +#define QLA82XX_HW_RPMX8_CRB_AGT_ADR 0x11 + +/* Hub 3 */ +#define QLA82XX_HW_PH_CRB_AGT_ADR 0x1A +#define QLA82XX_HW_SRE_CRB_AGT_ADR 0x50 +#define QLA82XX_HW_EG_CRB_AGT_ADR 0x51 +#define QLA82XX_HW_RPMX0_CRB_AGT_ADR 0x08 + +/* Hub 4 */ +#define QLA82XX_HW_PEGN0_CRB_AGT_ADR 0x40 +#define QLA82XX_HW_PEGN1_CRB_AGT_ADR 0x41 +#define QLA82XX_HW_PEGN2_CRB_AGT_ADR 0x42 +#define QLA82XX_HW_PEGN3_CRB_AGT_ADR 0x43 +#define QLA82XX_HW_PEGNI_CRB_AGT_ADR 0x44 +#define QLA82XX_HW_PEGND_CRB_AGT_ADR 0x45 +#define QLA82XX_HW_PEGNC_CRB_AGT_ADR 0x46 +#define QLA82XX_HW_PEGR0_CRB_AGT_ADR 0x47 +#define QLA82XX_HW_PEGR1_CRB_AGT_ADR 0x48 +#define QLA82XX_HW_PEGR2_CRB_AGT_ADR 0x49 +#define QLA82XX_HW_PEGR3_CRB_AGT_ADR 0x4a +#define QLA82XX_HW_PEGN4_CRB_AGT_ADR 0x4b + +/* Hub 5 */ +#define QLA82XX_HW_PEGS0_CRB_AGT_ADR 0x40 +#define QLA82XX_HW_PEGS1_CRB_AGT_ADR 0x41 +#define QLA82XX_HW_PEGS2_CRB_AGT_ADR 0x42 +#define QLA82XX_HW_PEGS3_CRB_AGT_ADR 0x43 + +#define QLA82XX_HW_PEGSI_CRB_AGT_ADR 0x44 +#define QLA82XX_HW_PEGSD_CRB_AGT_ADR 0x45 +#define QLA82XX_HW_PEGSC_CRB_AGT_ADR 0x46 + +/* Hub 6 */ +#define QLA82XX_HW_CAS0_CRB_AGT_ADR 0x46 +#define QLA82XX_HW_CAS1_CRB_AGT_ADR 0x47 +#define QLA82XX_HW_CAS2_CRB_AGT_ADR 0x48 +#define QLA82XX_HW_CAS3_CRB_AGT_ADR 0x49 +#define QLA82XX_HW_NCM_CRB_AGT_ADR 0x16 +#define QLA82XX_HW_TMR_CRB_AGT_ADR 0x17 +#define QLA82XX_HW_XDMA_CRB_AGT_ADR 0x05 +#define QLA82XX_HW_OCM0_CRB_AGT_ADR 0x06 +#define QLA82XX_HW_OCM1_CRB_AGT_ADR 0x07 + +/* This field defines PCI/X adr [25:20] of agents on the CRB */ +/* */ +#define QLA82XX_HW_PX_MAP_CRB_PH 0 +#define QLA82XX_HW_PX_MAP_CRB_PS 1 +#define QLA82XX_HW_PX_MAP_CRB_MN 2 +#define QLA82XX_HW_PX_MAP_CRB_MS 3 +#define QLA82XX_HW_PX_MAP_CRB_SRE 5 +#define QLA82XX_HW_PX_MAP_CRB_NIU 6 +#define QLA82XX_HW_PX_MAP_CRB_QMN 7 +#define QLA82XX_HW_PX_MAP_CRB_SQN0 8 +#define QLA82XX_HW_PX_MAP_CRB_SQN1 9 +#define QLA82XX_HW_PX_MAP_CRB_SQN2 10 +#define QLA82XX_HW_PX_MAP_CRB_SQN3 11 +#define QLA82XX_HW_PX_MAP_CRB_QMS 12 +#define QLA82XX_HW_PX_MAP_CRB_SQS0 13 +#define QLA82XX_HW_PX_MAP_CRB_SQS1 14 +#define QLA82XX_HW_PX_MAP_CRB_SQS2 15 +#define QLA82XX_HW_PX_MAP_CRB_SQS3 16 +#define QLA82XX_HW_PX_MAP_CRB_PGN0 17 +#define QLA82XX_HW_PX_MAP_CRB_PGN1 18 +#define QLA82XX_HW_PX_MAP_CRB_PGN2 19 +#define QLA82XX_HW_PX_MAP_CRB_PGN3 20 +#define QLA82XX_HW_PX_MAP_CRB_PGN4 QLA82XX_HW_PX_MAP_CRB_SQS2 +#define QLA82XX_HW_PX_MAP_CRB_PGND 21 +#define QLA82XX_HW_PX_MAP_CRB_PGNI 22 +#define QLA82XX_HW_PX_MAP_CRB_PGS0 23 +#define QLA82XX_HW_PX_MAP_CRB_PGS1 24 +#define QLA82XX_HW_PX_MAP_CRB_PGS2 25 +#define QLA82XX_HW_PX_MAP_CRB_PGS3 26 +#define QLA82XX_HW_PX_MAP_CRB_PGSD 27 +#define QLA82XX_HW_PX_MAP_CRB_PGSI 28 +#define QLA82XX_HW_PX_MAP_CRB_SN 29 +#define QLA82XX_HW_PX_MAP_CRB_EG 31 +#define QLA82XX_HW_PX_MAP_CRB_PH2 32 +#define QLA82XX_HW_PX_MAP_CRB_PS2 33 +#define QLA82XX_HW_PX_MAP_CRB_CAM 34 +#define QLA82XX_HW_PX_MAP_CRB_CAS0 35 +#define QLA82XX_HW_PX_MAP_CRB_CAS1 36 +#define QLA82XX_HW_PX_MAP_CRB_CAS2 37 +#define QLA82XX_HW_PX_MAP_CRB_C2C0 38 +#define QLA82XX_HW_PX_MAP_CRB_C2C1 39 +#define QLA82XX_HW_PX_MAP_CRB_TIMR 40 +#define QLA82XX_HW_PX_MAP_CRB_RPMX1 42 +#define QLA82XX_HW_PX_MAP_CRB_RPMX2 43 +#define QLA82XX_HW_PX_MAP_CRB_RPMX3 44 +#define QLA82XX_HW_PX_MAP_CRB_RPMX4 45 +#define QLA82XX_HW_PX_MAP_CRB_RPMX5 46 +#define QLA82XX_HW_PX_MAP_CRB_RPMX6 47 +#define QLA82XX_HW_PX_MAP_CRB_RPMX7 48 +#define QLA82XX_HW_PX_MAP_CRB_XDMA 49 +#define QLA82XX_HW_PX_MAP_CRB_I2Q 50 +#define QLA82XX_HW_PX_MAP_CRB_ROMUSB 51 +#define QLA82XX_HW_PX_MAP_CRB_CAS3 52 +#define QLA82XX_HW_PX_MAP_CRB_RPMX0 53 +#define QLA82XX_HW_PX_MAP_CRB_RPMX8 54 +#define QLA82XX_HW_PX_MAP_CRB_RPMX9 55 +#define QLA82XX_HW_PX_MAP_CRB_OCM0 56 +#define QLA82XX_HW_PX_MAP_CRB_OCM1 57 +#define QLA82XX_HW_PX_MAP_CRB_SMB 58 +#define QLA82XX_HW_PX_MAP_CRB_I2C0 59 +#define QLA82XX_HW_PX_MAP_CRB_I2C1 60 +#define QLA82XX_HW_PX_MAP_CRB_LPC 61 +#define QLA82XX_HW_PX_MAP_CRB_PGNC 62 +#define QLA82XX_HW_PX_MAP_CRB_PGR0 63 +#define QLA82XX_HW_PX_MAP_CRB_PGR1 4 +#define QLA82XX_HW_PX_MAP_CRB_PGR2 30 +#define QLA82XX_HW_PX_MAP_CRB_PGR3 41 + +/* This field defines CRB adr [31:20] of the agents */ +/* */ + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ + QLA82XX_HW_MN_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PH_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ + QLA82XX_HW_MS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_QMS_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQGS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQGS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQGS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQGS3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_C2C0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_C2C1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX4_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX7_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX9_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SMB_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ + QLA82XX_HW_NIU_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ + QLA82XX_HW_I2C0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ + QLA82XX_HW_I2C1_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SRE_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_EG_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_QM_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQG0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQG1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQG2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SQG3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX5_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX6_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_RPMX8_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_CAS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_CAS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_CAS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ + QLA82XX_HW_CAS3_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGNI_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGND_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGN0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGN1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGN2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGN3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGN4_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGNC_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGR0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGR1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGR2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGR3_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGSI_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGSD_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGS0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGS1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGS2_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGS3_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ + QLA82XX_HW_PEGSC_CRB_AGT_ADR) + +#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_NCM_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_TMR_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_XDMA_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_SN_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_I2Q_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_ROMUSB_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_OCM0_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_OCM1_CRB_AGT_ADR) +#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ + QLA82XX_HW_LPC_CRB_AGT_ADR) + +#define ROMUSB_GLB (QLA82XX_CRB_ROMUSB + 0x00000) +#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c) +#define QLA82XX_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004) +#define QLA82XX_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008) +#define QLA82XX_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008) +#define QLA82XX_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c) +#define QLA82XX_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010) +#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014) +#define QLA82XX_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018) + +#define ROMUSB_ROM (QLA82XX_CRB_ROMUSB + 0x10000) +#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004) +#define QLA82XX_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038) + +/* Lock IDs for ROM lock */ +#define ROM_LOCK_DRIVER 0x0d417340 + +#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000 /* all are 1MB windows */ +#define QLA82XX_PCI_CRB_WINDOW(A) (QLA82XX_PCI_CRBSPACE + \ + (A)*QLA82XX_PCI_CRB_WINDOWSIZE) + +#define QLA82XX_CRB_C2C_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0) +#define QLA82XX_CRB_C2C_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1) +#define QLA82XX_CRB_C2C_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2) +#define QLA82XX_CRB_CAM \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM) +#define QLA82XX_CRB_CASPER \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS) +#define QLA82XX_CRB_CASPER_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0) +#define QLA82XX_CRB_CASPER_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1) +#define QLA82XX_CRB_CASPER_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2) +#define QLA82XX_CRB_DDR_MD \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS) +#define QLA82XX_CRB_DDR_NET \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN) +#define QLA82XX_CRB_EPG \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG) +#define QLA82XX_CRB_I2Q \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q) +#define QLA82XX_CRB_NIU \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU) +/* HACK upon HACK upon HACK (for PCIE builds) */ +#define QLA82XX_CRB_PCIX_HOST \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH) +#define QLA82XX_CRB_PCIX_HOST2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2) +#define QLA82XX_CRB_PCIX_MD \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS) +#define QLA82XX_CRB_PCIE QLA82XX_CRB_PCIX_MD +/* window 1 pcie slot */ +#define QLA82XX_CRB_PCIE2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2) + +#define QLA82XX_CRB_PEG_MD_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0) +#define QLA82XX_CRB_PEG_MD_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1) +#define QLA82XX_CRB_PEG_MD_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2) +#define QLA82XX_CRB_PEG_MD_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) +#define QLA82XX_CRB_PEG_MD_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) +#define QLA82XX_CRB_PEG_MD_D \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD) +#define QLA82XX_CRB_PEG_MD_I \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI) +#define QLA82XX_CRB_PEG_NET_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0) +#define QLA82XX_CRB_PEG_NET_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1) +#define QLA82XX_CRB_PEG_NET_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2) +#define QLA82XX_CRB_PEG_NET_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3) +#define QLA82XX_CRB_PEG_NET_4 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4) +#define QLA82XX_CRB_PEG_NET_D \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND) +#define QLA82XX_CRB_PEG_NET_I \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI) +#define QLA82XX_CRB_PQM_MD \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS) +#define QLA82XX_CRB_PQM_NET \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN) +#define QLA82XX_CRB_QDR_MD \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS) +#define QLA82XX_CRB_QDR_NET \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN) +#define QLA82XX_CRB_ROMUSB \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB) +#define QLA82XX_CRB_RPMX_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0) +#define QLA82XX_CRB_RPMX_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1) +#define QLA82XX_CRB_RPMX_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2) +#define QLA82XX_CRB_RPMX_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3) +#define QLA82XX_CRB_RPMX_4 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4) +#define QLA82XX_CRB_RPMX_5 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5) +#define QLA82XX_CRB_RPMX_6 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6) +#define QLA82XX_CRB_RPMX_7 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7) +#define QLA82XX_CRB_SQM_MD_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0) +#define QLA82XX_CRB_SQM_MD_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1) +#define QLA82XX_CRB_SQM_MD_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2) +#define QLA82XX_CRB_SQM_MD_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3) +#define QLA82XX_CRB_SQM_NET_0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0) +#define QLA82XX_CRB_SQM_NET_1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1) +#define QLA82XX_CRB_SQM_NET_2 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2) +#define QLA82XX_CRB_SQM_NET_3 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3) +#define QLA82XX_CRB_SRE \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE) +#define QLA82XX_CRB_TIMER \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR) +#define QLA82XX_CRB_XDMA \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA) +#define QLA82XX_CRB_I2C0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0) +#define QLA82XX_CRB_I2C1 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1) +#define QLA82XX_CRB_OCM0 \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0) +#define QLA82XX_CRB_SMB \ + QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB) + +#define QLA82XX_CRB_MAX QLA82XX_PCI_CRB_WINDOW(64) + +/* + * ====================== BASE ADDRESSES ON-CHIP ====================== + * Base addresses of major components on-chip. + * ====================== BASE ADDRESSES ON-CHIP ====================== + */ +#define QLA82XX_ADDR_DDR_NET (0x0000000000000000ULL) +#define QLA82XX_ADDR_DDR_NET_MAX (0x000000000fffffffULL) + +/* Imbus address bit used to indicate a host address. This bit is + * eliminated by the pcie bar and bar select before presentation + * over pcie. */ +/* host memory via IMBUS */ +#define QLA82XX_P2_ADDR_PCIE (0x0000000800000000ULL) +#define QLA82XX_P3_ADDR_PCIE (0x0000008000000000ULL) +#define QLA82XX_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL) +#define QLA82XX_ADDR_OCM0 (0x0000000200000000ULL) +#define QLA82XX_ADDR_OCM0_MAX (0x00000002000fffffULL) +#define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL) +#define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL) +#define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) + +#define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL) +#define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) + +#define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 +#define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 +#define QLA82XX_PCI_CAMQM (unsigned long)0x04800000 +#define QLA82XX_PCI_CAMQM_MAX (unsigned long)0x04ffffff +#define QLA82XX_PCI_DDR_NET (unsigned long)0x00000000 +#define QLA82XX_PCI_QDR_NET (unsigned long)0x04000000 +#define QLA82XX_PCI_QDR_NET_MAX (unsigned long)0x043fffff + +/* + * Register offsets for MN + */ +#define MIU_CONTROL (0x000) +#define MIU_TAG (0x004) +#define MIU_TEST_AGT_CTRL (0x090) +#define MIU_TEST_AGT_ADDR_LO (0x094) +#define MIU_TEST_AGT_ADDR_HI (0x098) +#define MIU_TEST_AGT_WRDATA_LO (0x0a0) +#define MIU_TEST_AGT_WRDATA_HI (0x0a4) +#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i))) +#define MIU_TEST_AGT_RDDATA_LO (0x0a8) +#define MIU_TEST_AGT_RDDATA_HI (0x0ac) +#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i))) +#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8 +#define MIU_TEST_AGT_UPPER_ADDR(off) (0) + +/* MIU_TEST_AGT_CTRL flags. work for SIU as well */ +#define MIU_TA_CTL_START 1 +#define MIU_TA_CTL_ENABLE 2 +#define MIU_TA_CTL_WRITE 4 +#define MIU_TA_CTL_BUSY 8 + +/*CAM RAM */ +# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000) +# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg)) + +#define QLA82XX_PEG_TUNE_MN_SPD_ZEROED 0x80000000 +#define QLA82XX_BOOT_LOADER_MN_ISSUE 0xff00ffff +#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24)) +#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8)) +#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac)) +#define QLA82XX_PEG_ALIVE_COUNTER (QLA82XX_CAM_RAM(0xb0)) + +#define HALT_STATUS_UNRECOVERABLE 0x80000000 +#define HALT_STATUS_RECOVERABLE 0x40000000 + + +#define QLA82XX_ROM_LOCK_ID (QLA82XX_CAM_RAM(0x100)) +#define QLA82XX_CRB_WIN_LOCK_ID (QLA82XX_CAM_RAM(0x124)) +#define QLA82XX_FW_VERSION_MAJOR (QLA82XX_CAM_RAM(0x150)) +#define QLA82XX_FW_VERSION_MINOR (QLA82XX_CAM_RAM(0x154)) +#define QLA82XX_FW_VERSION_SUB (QLA82XX_CAM_RAM(0x158)) +#define QLA82XX_PCIE_REG(reg) (QLA82XX_CRB_PCIE + (reg)) + +/* Driver Coexistence Defines */ +#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138)) +#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140)) +#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) +#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174)) +#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144)) +#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148)) +#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) + +/* Every driver should use these Device State */ +#define QLA82XX_DEV_COLD 1 +#define QLA82XX_DEV_INITIALIZING 2 +#define QLA82XX_DEV_READY 3 +#define QLA82XX_DEV_NEED_RESET 4 +#define QLA82XX_DEV_NEED_QUIESCENT 5 +#define QLA82XX_DEV_FAILED 6 +#define QLA82XX_DEV_QUIESCENT 7 +#define MAX_STATES 8 /* Increment if new state added */ + +#define QLA82XX_IDC_VERSION 0x1 +#define ROM_DEV_INIT_TIMEOUT 30 +#define ROM_DRV_RESET_ACK_TIMEOUT 10 + +#define PCIE_SETUP_FUNCTION (0x12040) +#define PCIE_SETUP_FUNCTION2 (0x12048) + +#define QLA82XX_PCIX_PS_REG(reg) (QLA82XX_CRB_PCIX_MD + (reg)) +#define QLA82XX_PCIX_PS2_REG(reg) (QLA82XX_CRB_PCIE2 + (reg)) + +#define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */ +#define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */ +#define PCIE_SEM5_LOCK (0x1c028) /* Coexistence lock */ +#define PCIE_SEM5_UNLOCK (0x1c02c) /* Coexistence unlock */ +#define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */ +#define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/ + +/* + * The PCI VendorID and DeviceID for our board. + */ +#define QLA82XX_MSIX_TBL_SPACE 8192 +#define QLA82XX_PCI_REG_MSIX_TBL 0x44 +#define QLA82XX_PCI_MSIX_CONTROL 0x40 + +struct crb_128M_2M_sub_block_map { + unsigned valid; + unsigned start_128M; + unsigned end_128M; + unsigned start_2M; +}; + +struct crb_128M_2M_block_map { + struct crb_128M_2M_sub_block_map sub_block[16]; +}; + +struct crb_addr_pair { + long addr; + long data; +}; + +#define ADDR_ERROR ((unsigned long) 0xffffffff) +#define MAX_CTL_CHECK 1000 + +/*************************************************************************** + * PCI related defines. + **************************************************************************/ + +/* + * Interrupt related defines. + */ +#define PCIX_TARGET_STATUS (0x10118) +#define PCIX_TARGET_STATUS_F1 (0x10160) +#define PCIX_TARGET_STATUS_F2 (0x10164) +#define PCIX_TARGET_STATUS_F3 (0x10168) +#define PCIX_TARGET_STATUS_F4 (0x10360) +#define PCIX_TARGET_STATUS_F5 (0x10364) +#define PCIX_TARGET_STATUS_F6 (0x10368) +#define PCIX_TARGET_STATUS_F7 (0x1036c) + +#define PCIX_TARGET_MASK (0x10128) +#define PCIX_TARGET_MASK_F1 (0x10170) +#define PCIX_TARGET_MASK_F2 (0x10174) +#define PCIX_TARGET_MASK_F3 (0x10178) +#define PCIX_TARGET_MASK_F4 (0x10370) +#define PCIX_TARGET_MASK_F5 (0x10374) +#define PCIX_TARGET_MASK_F6 (0x10378) +#define PCIX_TARGET_MASK_F7 (0x1037c) + +/* + * Message Signaled Interrupts + */ +#define PCIX_MSI_F0 (0x13000) +#define PCIX_MSI_F1 (0x13004) +#define PCIX_MSI_F2 (0x13008) +#define PCIX_MSI_F3 (0x1300c) +#define PCIX_MSI_F4 (0x13010) +#define PCIX_MSI_F5 (0x13014) +#define PCIX_MSI_F6 (0x13018) +#define PCIX_MSI_F7 (0x1301c) +#define PCIX_MSI_F(FUNC) (0x13000 + ((FUNC) * 4)) + +/* + * + */ +#define PCIX_INT_VECTOR (0x10100) +#define PCIX_INT_MASK (0x10104) + +/* + * Interrupt state machine and other bits. + */ +#define PCIE_MISCCFG_RC (0x1206c) + + +#define ISR_INT_TARGET_STATUS \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS)) +#define ISR_INT_TARGET_STATUS_F1 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) +#define ISR_INT_TARGET_STATUS_F2 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) +#define ISR_INT_TARGET_STATUS_F3 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) +#define ISR_INT_TARGET_STATUS_F4 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) +#define ISR_INT_TARGET_STATUS_F5 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) +#define ISR_INT_TARGET_STATUS_F6 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) +#define ISR_INT_TARGET_STATUS_F7 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) + +#define ISR_INT_TARGET_MASK \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK)) +#define ISR_INT_TARGET_MASK_F1 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) +#define ISR_INT_TARGET_MASK_F2 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) +#define ISR_INT_TARGET_MASK_F3 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) +#define ISR_INT_TARGET_MASK_F4 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) +#define ISR_INT_TARGET_MASK_F5 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) +#define ISR_INT_TARGET_MASK_F6 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) +#define ISR_INT_TARGET_MASK_F7 \ + (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) + +#define ISR_INT_VECTOR (QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR)) +#define ISR_INT_MASK (QLA82XX_PCIX_PS_REG(PCIX_INT_MASK)) +#define ISR_INT_STATE_REG (QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC)) + +#define ISR_MSI_INT_TRIGGER(FUNC) (QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC))) + + +#define ISR_IS_LEGACY_INTR_IDLE(VAL) (((VAL) & 0x300) == 0) +#define ISR_IS_LEGACY_INTR_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) + +/* + * PCI Interrupt Vector Values. + */ +#define PCIX_INT_VECTOR_BIT_F0 0x0080 +#define PCIX_INT_VECTOR_BIT_F1 0x0100 +#define PCIX_INT_VECTOR_BIT_F2 0x0200 +#define PCIX_INT_VECTOR_BIT_F3 0x0400 +#define PCIX_INT_VECTOR_BIT_F4 0x0800 +#define PCIX_INT_VECTOR_BIT_F5 0x1000 +#define PCIX_INT_VECTOR_BIT_F6 0x2000 +#define PCIX_INT_VECTOR_BIT_F7 0x4000 + +/* struct qla4_8xxx_legacy_intr_set defined in ql4_def.h */ + +#define QLA82XX_LEGACY_INTR_CONFIG \ +{ \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \ + \ + { \ + .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \ + .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \ + .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \ + .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ +} + +/* Magic number to let user know flash is programmed */ +#define QLA82XX_BDINFO_MAGIC 0x12345678 +#define FW_SIZE_OFFSET (0x3e840c) + +/* QLA82XX additions */ +#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) +#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) + +#endif diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 38b1d38afca..64a1288e06b 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -30,22 +30,29 @@ static struct kmem_cache *srb_cachep; * Module parameter information and variables */ int ql4xdiscoverywait = 60; -module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR); +module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time"); + int ql4xdontresethba = 0; -module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR); +module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, - "Dont reset the HBA when the driver gets 0x8002 AEN " - " default it will reset hba :0" - " set to 1 to avoid resetting HBA"); + "Don't reset the HBA for driver recovery \n" + " 0 - It will reset HBA (Default)\n" + " 1 - It will NOT reset HBA"); int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */ -module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR); +module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging"); -int ql4_mod_unload = 0; +int ql4xenablemsix = 1; +module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ql4xenablemsix, + "Set to enable MSI or MSI-X interrupt mechanism.\n" + " 0 = enable INTx interrupt mechanism.\n" + " 1 = enable MSI-X interrupt mechanism (Default).\n" + " 2 = enable MSI interrupt mechanism."); #define QL4_DEF_QDEPTH 32 @@ -83,6 +90,9 @@ static int qla4xxx_slave_configure(struct scsi_device *device); static void qla4xxx_slave_destroy(struct scsi_device *sdev); static void qla4xxx_scan_start(struct Scsi_Host *shost); +static struct qla4_8xxx_legacy_intr_set legacy_intr[] = + QLA82XX_LEGACY_INTR_CONFIG; + static struct scsi_host_template qla4xxx_driver_template = { .module = THIS_MODULE, .name = DRIVER_NAME, @@ -152,15 +162,12 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { atomic_set(&ddb_entry->state, DDB_STATE_DEAD); - DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count " + DEBUG2(printk("scsi%ld: %s: ddb [%d] port down retry count " "of (%d) secs exhausted, marking device DEAD.\n", ha->host_no, __func__, ddb_entry->fw_ddb_index, ha->port_down_retry_count)); - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc " - "flags = 0x%lx\n", - ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); + qla4xxx_wake_dpc(ha); } } @@ -362,19 +369,37 @@ static void qla4xxx_stop_timer(struct scsi_qla_host *ha) * @ha: Pointer to host adapter structure. * @ddb_entry: Pointer to device database entry * - * This routine marks a device missing and resets the relogin retry count. + * This routine marks a device missing and close connection. **/ void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { - atomic_set(&ddb_entry->state, DDB_STATE_MISSING); - DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", - ha->host_no, ddb_entry->bus, ddb_entry->target, - ddb_entry->fw_ddb_index)); + if ((atomic_read(&ddb_entry->state) != DDB_STATE_DEAD)) { + atomic_set(&ddb_entry->state, DDB_STATE_MISSING); + DEBUG2(printk("scsi%ld: ddb [%d] marked MISSING\n", + ha->host_no, ddb_entry->fw_ddb_index)); + } else + DEBUG2(printk("scsi%ld: ddb [%d] DEAD\n", ha->host_no, + ddb_entry->fw_ddb_index)) + iscsi_block_session(ddb_entry->sess); iscsi_conn_error_event(ddb_entry->conn, ISCSI_ERR_CONN_FAILED); } +/** + * qla4xxx_mark_all_devices_missing - mark all devices as missing. + * @ha: Pointer to host adapter structure. + * + * This routine marks a device missing and resets the relogin retry count. + **/ +void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry, *ddbtemp; + list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) { + qla4xxx_mark_device_missing(ha, ddb_entry); + } +} + static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, struct scsi_cmnd *cmd, @@ -463,7 +488,13 @@ static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, return SCSI_MLQUEUE_TARGET_BUSY; } - if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || + test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || + test_bit(DPC_RESET_HA, &ha->dpc_flags) || + test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || + test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || + !test_bit(AF_ONLINE, &ha->flags) || + test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) goto qc_host_busy; spin_unlock_irq(ha->host->host_lock); @@ -524,7 +555,15 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) ha->srb_mempool = NULL; /* release io space registers */ - if (ha->reg) + if (is_qla8022(ha)) { + if (ha->nx_pcibase) + iounmap( + (struct device_reg_82xx __iomem *)ha->nx_pcibase); + + if (ha->nx_db_wr_ptr) + iounmap( + (struct device_reg_82xx __iomem *)ha->nx_db_wr_ptr); + } else if (ha->reg) iounmap(ha->reg); pci_release_regions(ha->pdev); } @@ -599,6 +638,74 @@ mem_alloc_error_exit: return QLA_ERROR; } +/** + * qla4_8xxx_check_fw_alive - Check firmware health + * @ha: Pointer to host adapter structure. + * + * Context: Interrupt + **/ +static void qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) +{ + uint32_t fw_heartbeat_counter, halt_status; + + fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); + + if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { + ha->seconds_since_last_heartbeat++; + /* FW not alive after 2 seconds */ + if (ha->seconds_since_last_heartbeat == 2) { + ha->seconds_since_last_heartbeat = 0; + halt_status = qla4_8xxx_rd_32(ha, + QLA82XX_PEG_HALT_STATUS1); + /* Since we cannot change dev_state in interrupt + * context, set appropriate DPC flag then wakeup + * DPC */ + if (halt_status & HALT_STATUS_UNRECOVERABLE) + set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); + else { + printk("scsi%ld: %s: detect abort needed!\n", + ha->host_no, __func__); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + qla4xxx_wake_dpc(ha); + } + } + ha->fw_heartbeat_counter = fw_heartbeat_counter; +} + +/** + * qla4_8xxx_watchdog - Poll dev state + * @ha: Pointer to host adapter structure. + * + * Context: Interrupt + **/ +void qla4_8xxx_watchdog(struct scsi_qla_host *ha) +{ + uint32_t dev_state; + + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + + /* don't poll if reset is going on */ + if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags)) { + if (dev_state == QLA82XX_DEV_NEED_RESET && + !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + printk("scsi%ld: %s: HW State: NEED RESET!\n", + ha->host_no, __func__); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + qla4xxx_wake_dpc(ha); + } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && + !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { + printk("scsi%ld: %s: HW State: NEED QUIES!\n", + ha->host_no, __func__); + set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); + qla4xxx_wake_dpc(ha); + } else { + /* Check firmware health */ + qla4_8xxx_check_fw_alive(ha); + } + } +} + /** * qla4xxx_timer - checks every second for work to do. * @ha: Pointer to host adapter structure. @@ -608,6 +715,16 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) struct ddb_entry *ddb_entry, *dtemp; int start_dpc = 0; + if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { + DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n", + __func__)); + return; + } + + if (is_qla8022(ha)) { + qla4_8xxx_watchdog(ha); + } + /* Search for relogin's to time-out and port down retry. */ list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { /* Count down time between sending relogins */ @@ -624,7 +741,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); set_bit(DF_RELOGIN, &ddb_entry->flags); - DEBUG2(printk("scsi%ld: %s: index [%d]" + DEBUG2(printk("scsi%ld: %s: ddb [%d]" " login device\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); @@ -647,7 +764,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) DDB_DS_SESSION_FAILED) { /* Reset retry relogin timer */ atomic_inc(&ddb_entry->relogin_retry_count); - DEBUG2(printk("scsi%ld: index[%d] relogin" + DEBUG2(printk("scsi%ld: ddb [%d] relogin" " timed out-retrying" " relogin (%d)\n", ha->host_no, @@ -656,7 +773,7 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) relogin_retry_count)) ); start_dpc++; - DEBUG(printk("scsi%ld:%d:%d: index [%d] " + DEBUG(printk("scsi%ld:%d:%d: ddb [%d] " "initate relogin after" " %d seconds\n", ha->host_no, ddb_entry->bus, @@ -671,31 +788,35 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) } } - /* Check for heartbeat interval. */ - if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && - ha->heartbeat_interval != 0) { - ha->seconds_since_last_heartbeat++; - if (ha->seconds_since_last_heartbeat > - ha->heartbeat_interval + 2) - set_bit(DPC_RESET_HA, &ha->dpc_flags); + if (!is_qla8022(ha)) { + /* Check for heartbeat interval. */ + if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && + ha->heartbeat_interval != 0) { + ha->seconds_since_last_heartbeat++; + if (ha->seconds_since_last_heartbeat > + ha->heartbeat_interval + 2) + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } } - /* Wakeup the dpc routine for this adapter, if needed. */ if ((start_dpc || test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || + test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || + test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || + test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || test_bit(DPC_AEN, &ha->dpc_flags)) && + !test_bit(AF_DPC_SCHEDULED, &ha->flags) && ha->dpc_thread) { DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" " - dpc flags = 0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); - queue_work(ha->dpc_thread, &ha->dpc_work); + qla4xxx_wake_dpc(ha); } /* Reschedule timer thread to call us back in one second */ @@ -714,16 +835,15 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) { uint32_t index = 0; - int stat = QLA_SUCCESS; unsigned long flags; struct scsi_cmnd *cmd; - int wait_cnt = WAIT_CMD_TOV; /* - * Initialized for 30 seconds as we - * expect all commands to retuned - * ASAP. - */ - while (wait_cnt) { + unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); + + DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " + "complete\n", WAIT_CMD_TOV)); + + while (!time_after_eq(jiffies, wtime)) { spin_lock_irqsave(&ha->hardware_lock, flags); /* Find a command that hasn't completed. */ for (index = 0; index < ha->host->can_queue; index++) { @@ -734,31 +854,26 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* If No Commands are pending, wait is complete */ - if (index == ha->host->can_queue) { - break; - } - - /* If we timed out on waiting for commands to come back - * return ERROR. - */ - wait_cnt--; - if (wait_cnt == 0) - stat = QLA_ERROR; - else { - msleep(1000); - } - } /* End of While (wait_cnt) */ + if (index == ha->host->can_queue) + return QLA_SUCCESS; - return stat; + msleep(1000); + } + /* If we timed out on waiting for commands to come back + * return ERROR. */ + return QLA_ERROR; } -void qla4xxx_hw_reset(struct scsi_qla_host *ha) +int qla4xxx_hw_reset(struct scsi_qla_host *ha) { uint32_t ctrl_status; unsigned long flags = 0; DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); + if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) + return QLA_ERROR; + spin_lock_irqsave(&ha->hardware_lock, flags); /* @@ -774,6 +889,7 @@ void qla4xxx_hw_reset(struct scsi_qla_host *ha) readl(&ha->reg->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); + return QLA_SUCCESS; } /** @@ -872,15 +988,16 @@ int qla4xxx_soft_reset(struct scsi_qla_host *ha) } /** - * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S. + * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. * @ha: Pointer to host adapter structure. + * @res: returned scsi status * * This routine is called just prior to a HARD RESET to return all * outstanding commands back to the Operating System. * Caller should make sure that the following locks are released * before this calling routine: Hardware lock, and io_request_lock. **/ -static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) +static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) { struct srb *srb; int i; @@ -890,74 +1007,116 @@ static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha) for (i = 0; i < ha->host->can_queue; i++) { srb = qla4xxx_del_from_active_array(ha, i); if (srb != NULL) { - srb->cmd->result = DID_RESET << 16; + srb->cmd->result = res; kref_put(&srb->srb_ref, qla4xxx_srb_compl); } } spin_unlock_irqrestore(&ha->hardware_lock, flags); } +void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) +{ + clear_bit(AF_ONLINE, &ha->flags); + + /* Disable the board */ + ql4_printk(KERN_INFO, ha, "Disabling the board\n"); + set_bit(AF_HBA_GOING_AWAY, &ha->flags); + + qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); + qla4xxx_mark_all_devices_missing(ha); + clear_bit(AF_INIT_DONE, &ha->flags); +} + /** * qla4xxx_recover_adapter - recovers adapter after a fatal error * @ha: Pointer to host adapter structure. - * @renew_ddb_list: Indicates what to do with the adapter's ddb list - * - * renew_ddb_list value can be 0=preserve ddb list, 1=destroy and rebuild - * ddb list. **/ -static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, - uint8_t renew_ddb_list) +static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) { - int status; + int status = QLA_ERROR; + uint8_t reset_chip = 0; /* Stall incoming I/O until we are done */ + scsi_block_requests(ha->host); clear_bit(AF_ONLINE, &ha->flags); - DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no, - __func__)); + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); - /* Wait for outstanding commands to complete. - * Stalls the driver for max 30 secs - */ - status = qla4xxx_cmd_wait(ha); + set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); - qla4xxx_disable_intrs(ha); + if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) + reset_chip = 1; - /* Flush any pending ddb changed AENs */ - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) + * do not reset adapter, jump to initialize_adapter */ + if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { + status = QLA_SUCCESS; + goto recover_ha_init_adapter; + } - qla4xxx_flush_active_srbs(ha); + /* For the ISP-82xx adapter, issue a stop_firmware if invoked + * from eh_host_reset or ioctl module */ + if (is_qla8022(ha) && !reset_chip && + test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { + + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: %s - Performing stop_firmware...\n", + ha->host_no, __func__)); + status = ha->isp_ops->reset_firmware(ha); + if (status == QLA_SUCCESS) { + qla4xxx_cmd_wait(ha); + ha->isp_ops->disable_intrs(ha); + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + qla4xxx_abort_active_cmds(ha, DID_RESET << 16); + } else { + /* If the stop_firmware fails then + * reset the entire chip */ + reset_chip = 1; + clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } + } - /* Reset the firmware. If successful, function - * returns with ISP interrupts enabled. - */ - DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n", - ha->host_no, __func__)); - if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) - status = qla4xxx_soft_reset(ha); - else - status = QLA_ERROR; + /* Issue full chip reset if recovering from a catastrophic error, + * or if stop_firmware fails for ISP-82xx. + * This is the default case for ISP-4xxx */ + if (!is_qla8022(ha) || reset_chip) { + qla4xxx_cmd_wait(ha); + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + qla4xxx_abort_active_cmds(ha, DID_RESET << 16); + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: %s - Performing chip reset..\n", + ha->host_no, __func__)); + status = ha->isp_ops->reset_chip(ha); + } /* Flush any pending ddb changed AENs */ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - /* Re-initialize firmware. If successful, function returns - * with ISP interrupts enabled */ +recover_ha_init_adapter: + /* Upon successful firmware/chip reset, re-initialize the adapter */ if (status == QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n", - ha->host_no, __func__)); - - /* If successful, AF_ONLINE flag set in - * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha, renew_ddb_list); + /* For ISP-4xxx, force function 1 to always initialize + * before function 3 to prevent both funcions from + * stepping on top of the other */ + if (!is_qla8022(ha) && (ha->mac_index == 3)) + ssleep(6); + + /* NOTE: AF_ONLINE flag set upon successful completion of + * qla4xxx_initialize_adapter */ + status = qla4xxx_initialize_adapter(ha, PRESERVE_DDB_LIST); } - /* Failed adapter initialization? - * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */ - if ((test_bit(AF_ONLINE, &ha->flags) == 0) && - (test_bit(DPC_RESET_HA, &ha->dpc_flags))) { + /* Retry failed adapter initialization, if necessary + * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) + * case to prevent ping-pong resets between functions */ + if (!test_bit(AF_ONLINE, &ha->flags) && + !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { /* Adapter initialization failed, see if we can retry - * resetting the ha */ + * resetting the ha. + * Since we don't want to block the DPC for too long + * with multiple resets in the same thread, + * utilize DPC to retry */ if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; DEBUG2(printk("scsi%ld: recover adapter - retrying " @@ -982,29 +1141,43 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha, DEBUG2(printk("scsi%ld: recover adapter " "failed - board disabled\n", ha->host_no)); - qla4xxx_flush_active_srbs(ha); + qla4xxx_dead_adapter_cleanup(ha); clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, + clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); status = QLA_ERROR; } } } else { clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); } ha->adapter_error_count++; - if (status == QLA_SUCCESS) - qla4xxx_enable_intrs(ha); + if (test_bit(AF_ONLINE, &ha->flags)) + ha->isp_ops->enable_intrs(ha); + + scsi_unblock_requests(ha->host); + + clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); + DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, + status == QLA_ERROR ? "FAILED" : "SUCCEDED")); - DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no)); return status; } +void qla4xxx_wake_dpc(struct scsi_qla_host *ha) +{ + if (ha->dpc_thread && + !test_bit(AF_DPC_SCHEDULED, &ha->flags)) { + set_bit(AF_DPC_SCHEDULED, &ha->flags); + queue_work(ha->dpc_thread, &ha->dpc_work); + } +} + /** * qla4xxx_do_dpc - dpc routine * @data: in our case pointer to adapter structure @@ -1024,21 +1197,47 @@ static void qla4xxx_do_dpc(struct work_struct *work) int status = QLA_ERROR; DEBUG2(printk("scsi%ld: %s: DPC handler waking up." - "flags = 0x%08lx, dpc_flags = 0x%08lx ctrl_stat = 0x%08x\n", - ha->host_no, __func__, ha->flags, ha->dpc_flags, - readw(&ha->reg->ctrl_status))); + "flags = 0x%08lx, dpc_flags = 0x%08lx\n", + ha->host_no, __func__, ha->flags, ha->dpc_flags)) /* Initialization not yet finished. Don't do anything yet. */ if (!test_bit(AF_INIT_DONE, &ha->flags)) return; - if (adapter_up(ha) || - test_bit(DPC_RESET_HA, &ha->dpc_flags) || + /* HBA is in the process of being permanently disabled. + * Don't process anything */ + if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) + return; + + if (is_qla8022(ha)) { + if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { + qla4_8xxx_idc_lock(ha); + qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, + QLA82XX_DEV_FAILED); + qla4_8xxx_idc_unlock(ha); + ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); + qla4_8xxx_device_state_handler(ha); + } + if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { + qla4_8xxx_need_qsnt_handler(ha); + } + } + + if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && + (test_bit(DPC_RESET_HA, &ha->dpc_flags) || test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) { - if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags)) - qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST); + test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { + if (ql4xdontresethba) { + DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", + ha->host_no, __func__)); + clear_bit(DPC_RESET_HA, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); + clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); + goto dpc_post_reset_ha; + } + if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || + test_bit(DPC_RESET_HA, &ha->dpc_flags)) + qla4xxx_recover_adapter(ha); if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { uint8_t wait_time = RESET_INTR_TOV; @@ -1053,18 +1252,18 @@ static void qla4xxx_do_dpc(struct work_struct *work) DEBUG2(printk("scsi%ld: %s: SR|FSR " "bit not cleared-- resetting\n", ha->host_no, __func__)); - qla4xxx_flush_active_srbs(ha); + qla4xxx_abort_active_cmds(ha, DID_RESET << 16); if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - status = qla4xxx_initialize_adapter(ha, - PRESERVE_DDB_LIST); + status = qla4xxx_recover_adapter(ha); } clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); if (status == QLA_SUCCESS) - qla4xxx_enable_intrs(ha); + ha->isp_ops->enable_intrs(ha); } } +dpc_post_reset_ha: /* ---- process AEN? --- */ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) qla4xxx_process_aen(ha, PROCESS_ALL_AENS); @@ -1104,11 +1303,9 @@ static void qla4xxx_do_dpc(struct work_struct *work) DDB_STATE_ONLINE); dev_info(&ha->pdev->dev, "scsi%ld: %s: ddb[%d]" - " os[%d] marked" - " ONLINE\n", + " marked ONLINE\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index, - ddb_entry->os_target_id); + ddb_entry->fw_ddb_index); iscsi_unblock_session( ddb_entry->sess); @@ -1144,6 +1341,7 @@ static void qla4xxx_do_dpc(struct work_struct *work) } } } + clear_bit(AF_DPC_SCHEDULED, &ha->flags); } /** @@ -1155,30 +1353,99 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { /* Turn-off interrupts on the card. */ - qla4xxx_disable_intrs(ha); + ha->isp_ops->disable_intrs(ha); } + /* Remove timer thread, if present */ + if (ha->timer_active) + qla4xxx_stop_timer(ha); + /* Kill the kernel thread for this host */ if (ha->dpc_thread) destroy_workqueue(ha->dpc_thread); - /* Issue Soft Reset to put firmware in unknown state */ - if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) - qla4xxx_hw_reset(ha); + /* Put firmware in known state */ + ha->isp_ops->reset_firmware(ha); - /* Remove timer thread, if present */ - if (ha->timer_active) - qla4xxx_stop_timer(ha); + if (is_qla8022(ha)) { + qla4_8xxx_idc_lock(ha); + qla4_8xxx_clear_drv_active(ha); + qla4_8xxx_idc_unlock(ha); + } /* Detach interrupts */ if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) - free_irq(ha->pdev->irq, ha); + qla4xxx_free_irqs(ha); /* free extra memory */ qla4xxx_mem_free(ha); +} + +int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) +{ + int status = 0; + uint8_t revision_id; + unsigned long mem_base, mem_len, db_base, db_len; + struct pci_dev *pdev = ha->pdev; + + status = pci_request_regions(pdev, DRIVER_NAME); + if (status) { + printk(KERN_WARNING + "scsi(%ld) Failed to reserve PIO regions (%s) " + "status=%d\n", ha->host_no, pci_name(pdev), status); + goto iospace_error_exit; + } + + pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); + DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", + __func__, revision_id)); + ha->revision_id = revision_id; - pci_disable_device(ha->pdev); + /* remap phys address */ + mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ + mem_len = pci_resource_len(pdev, 0); + DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", + __func__, mem_base, mem_len)); + /* mapping of pcibase pointer */ + ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); + if (!ha->nx_pcibase) { + printk(KERN_ERR + "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); + pci_release_regions(ha->pdev); + goto iospace_error_exit; + } + + /* Mapping of IO base pointer, door bell read and write pointer */ + + /* mapping of IO base pointer */ + ha->qla4_8xxx_reg = + (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + + 0xbc000 + (ha->pdev->devfn << 11)); + + db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ + db_len = pci_resource_len(pdev, 4); + + /* mapping of doorbell write pointer */ + ha->nx_db_wr_ptr = (unsigned long)ioremap(db_base + + (ha->pdev->devfn << 12), 4); + if (!ha->nx_db_wr_ptr) { + printk(KERN_ERR + "cannot remap MMIO doorbell-write (%s), aborting\n", + pci_name(pdev)); + goto iospace_error_exit; + } + /* mapping of doorbell read pointer */ + ha->nx_db_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) + + (ha->pdev->devfn * 8); + if (!ha->nx_db_rd_ptr) + printk(KERN_ERR + "cannot remap MMIO doorbell-read (%s), aborting\n", + pci_name(pdev)); + return 0; + +iospace_error_exit: + return -ENOMEM; } /*** @@ -1188,7 +1455,7 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha) * This routines maps HBA's registers from the pci address space * into the kernel virtual address space for memory mapped i/o. **/ -static int qla4xxx_iospace_config(struct scsi_qla_host *ha) +int qla4xxx_iospace_config(struct scsi_qla_host *ha) { unsigned long pio, pio_len, pio_flags; unsigned long mmio, mmio_len, mmio_flags; @@ -1247,6 +1514,60 @@ iospace_error_exit: return -ENOMEM; } +static struct isp_operations qla4xxx_isp_ops = { + .iospace_config = qla4xxx_iospace_config, + .pci_config = qla4xxx_pci_config, + .disable_intrs = qla4xxx_disable_intrs, + .enable_intrs = qla4xxx_enable_intrs, + .start_firmware = qla4xxx_start_firmware, + .intr_handler = qla4xxx_intr_handler, + .interrupt_service_routine = qla4xxx_interrupt_service_routine, + .reset_chip = qla4xxx_soft_reset, + .reset_firmware = qla4xxx_hw_reset, + .queue_iocb = qla4xxx_queue_iocb, + .complete_iocb = qla4xxx_complete_iocb, + .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, + .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, + .get_sys_info = qla4xxx_get_sys_info, +}; + +static struct isp_operations qla4_8xxx_isp_ops = { + .iospace_config = qla4_8xxx_iospace_config, + .pci_config = qla4_8xxx_pci_config, + .disable_intrs = qla4_8xxx_disable_intrs, + .enable_intrs = qla4_8xxx_enable_intrs, + .start_firmware = qla4_8xxx_load_risc, + .intr_handler = qla4_8xxx_intr_handler, + .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, + .reset_chip = qla4_8xxx_isp_reset, + .reset_firmware = qla4_8xxx_stop_firmware, + .queue_iocb = qla4_8xxx_queue_iocb, + .complete_iocb = qla4_8xxx_complete_iocb, + .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, + .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, + .get_sys_info = qla4_8xxx_get_sys_info, +}; + +uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); +} + +uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); +} + +uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); +} + +uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) +{ + return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); +} + /** * qla4xxx_probe_adapter - callback function to probe HBA * @pdev: pointer to pci_dev structure @@ -1264,6 +1585,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, struct scsi_qla_host *ha; uint8_t init_retry_count = 0; char buf[34]; + struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; if (pci_enable_device(pdev)) return -1; @@ -1284,10 +1606,28 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host = host; ha->host_no = host->host_no; + /* Setup Runtime configurable options */ + if (is_qla8022(ha)) { + ha->isp_ops = &qla4_8xxx_isp_ops; + rwlock_init(&ha->hw_lock); + ha->qdr_sn_window = -1; + ha->ddr_mn_window = -1; + ha->curr_window = 255; + ha->func_num = PCI_FUNC(ha->pdev->devfn); + nx_legacy_intr = &legacy_intr[ha->func_num]; + ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; + ha->nx_legacy_intr.tgt_status_reg = + nx_legacy_intr->tgt_status_reg; + ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; + ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; + } else { + ha->isp_ops = &qla4xxx_isp_ops; + } + /* Configure PCI I/O space. */ - ret = qla4xxx_iospace_config(ha); + ret = ha->isp_ops->iospace_config(ha); if (ret) - goto probe_failed; + goto probe_failed_ioconfig; dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, ha->reg); @@ -1299,6 +1639,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, INIT_LIST_HEAD(&ha->free_srb_q); mutex_init(&ha->mbox_sem); + init_completion(&ha->mbx_intr_comp); spin_lock_init(&ha->hardware_lock); @@ -1311,19 +1652,27 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, goto probe_failed; } + if (is_qla8022(ha)) + (void) qla4_8xxx_get_flash_info(ha); + /* * Initialize the Host adapter request/response queues and * firmware * NOTE: interrupts enabled upon successful completion */ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); - while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) { + while ((!test_bit(AF_ONLINE, &ha->flags)) && + init_retry_count++ < MAX_INIT_RETRIES) { DEBUG2(printk("scsi: %s: retrying adapter initialization " "(%d)\n", __func__, init_retry_count)); - qla4xxx_soft_reset(ha); + + if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) + continue; + status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); } - if (status == QLA_ERROR) { + + if (!test_bit(AF_ONLINE, &ha->flags)) { dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n"); ret = -ENODEV; @@ -1356,18 +1705,21 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - ret = request_irq(pdev->irq, qla4xxx_intr_handler, - IRQF_DISABLED | IRQF_SHARED, "qla4xxx", ha); - if (ret) { - dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d" - " already in use.\n", pdev->irq); - goto probe_failed; + /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc + * (which is called indirectly by qla4xxx_initialize_adapter), + * so that irqs will be registered after crbinit but before + * mbx_intr_enable. + */ + if (!is_qla8022(ha)) { + ret = qla4xxx_request_irqs(ha); + if (ret) { + ql4_printk(KERN_WARNING, ha, "Failed to reserve " + "interrupt %d already in use.\n", pdev->irq); + goto probe_failed; + } } - set_bit(AF_IRQ_ATTACHED, &ha->flags); - host->irq = pdev->irq; - DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq)); - qla4xxx_enable_intrs(ha); + ha->isp_ops->enable_intrs(ha); /* Start timer thread. */ qla4xxx_start_timer(ha, qla4xxx_timer, 1); @@ -1391,6 +1743,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, probe_failed: qla4xxx_free_adapter(ha); + +probe_failed_ioconfig: scsi_host_put(ha->host); probe_disable_device: @@ -1409,10 +1763,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) ha = pci_get_drvdata(pdev); - qla4xxx_disable_intrs(ha); - - while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) - ssleep(1); + set_bit(AF_HBA_GOING_AWAY, &ha->flags); /* remove devs from iscsi_sessions to scsi_devices */ qla4xxx_free_ddb_list(ha); @@ -1423,6 +1774,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) scsi_host_put(ha->host); + pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); } @@ -1479,7 +1831,8 @@ static void qla4xxx_slave_destroy(struct scsi_device *sdev) * * This routine removes and returns the srb at the specified index **/ -struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index) +struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, + uint32_t index) { struct srb *srb = NULL; struct scsi_cmnd *cmd = NULL; @@ -1769,6 +2122,12 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) ha = (struct scsi_qla_host *) cmd->device->host->hostdata; + if (ql4xdontresethba) { + DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", + ha->host_no, __func__)); + return FAILED; + } + dev_info(&ha->pdev->dev, "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -1781,11 +2140,14 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return FAILED; } - /* make sure the dpc thread is stopped while we reset the hba */ - clear_bit(AF_ONLINE, &ha->flags); - flush_workqueue(ha->dpc_thread); + if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { + if (is_qla8022(ha)) + set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); + else + set_bit(DPC_RESET_HA, &ha->dpc_flags); + } - if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) + if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) return_status = SUCCESS; dev_info(&ha->pdev->dev, "HOST RESET %s.\n", @@ -1794,7 +2156,6 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return return_status; } - static struct pci_device_id qla4xxx_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_QLOGIC, @@ -1814,6 +2175,12 @@ static struct pci_device_id qla4xxx_pci_tbl[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP8022, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, {0, 0}, }; MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); @@ -1869,7 +2236,6 @@ no_srp_cache: static void __exit qla4xxx_module_exit(void) { - ql4_mod_unload = 1; pci_unregister_driver(&qla4xxx_pci_driver); iscsi_unregister_transport(&qla4xxx_iscsi_transport); kmem_cache_destroy(srb_cachep); -- cgit v1.2.3-70-g09d2 From c2660df310a3c445194748b54f51b7224639e742 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:51:02 +0530 Subject: [SCSI] qla4xxx: replace all dev_info, dev_warn, dev_err with ql4_printk Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 50 ++++++++++++++++----------------- drivers/scsi/qla4xxx/ql4_isr.c | 8 +++--- drivers/scsi/qla4xxx/ql4_mbx.c | 4 +-- drivers/scsi/qla4xxx/ql4_os.c | 62 +++++++++++++++++++++-------------------- 4 files changed, 63 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 539546df037..5fc19c44bad 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -297,7 +297,7 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) uint32_t timeout_count; int ready = 0; - DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n")); + DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n")); for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0; timeout_count--) { if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) @@ -370,29 +370,29 @@ static int qla4xxx_fw_ready(struct scsi_qla_host *ha) if (!qla4xxx_wait_for_ip_config(ha) || timeout_count == 1) { - DEBUG2(dev_info(&ha->pdev->dev, - "Firmware Ready..\n")); + DEBUG2(ql4_printk(KERN_INFO, ha, + "Firmware Ready..\n")); /* The firmware is ready to process SCSI commands. */ - DEBUG2(dev_info(&ha->pdev->dev, + DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: %s: MEDIA TYPE" " - %s\n", ha->host_no, __func__, (ha->addl_fw_state & FW_ADDSTATE_OPTICAL_MEDIA) != 0 ? "OPTICAL" : "COPPER")); - DEBUG2(dev_info(&ha->pdev->dev, + DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: %s: DHCPv4 STATE" " Enabled %s\n", ha->host_no, __func__, (ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? "YES" : "NO")); - DEBUG2(dev_info(&ha->pdev->dev, + DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: %s: LINK %s\n", ha->host_no, __func__, (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) != 0 ? "UP" : "DOWN")); - DEBUG2(dev_info(&ha->pdev->dev, + DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: %s: iSNS Service " "Started %s\n", ha->host_no, __func__, @@ -445,7 +445,7 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha) { int status = QLA_ERROR; - dev_info(&ha->pdev->dev, "Initializing firmware..\n"); + ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " "control block\n", ha->host_no, __func__)); @@ -694,18 +694,18 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) err_code = ((conn_err & 0x00ff0000) >> 16); login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8); if (err_code == 0x1c || err_code == 0x06) { - DEBUG2(dev_info(&ha->pdev->dev, - ": conn_err=0x%08x, send target completed" - " or access denied failure\n", conn_err)); + DEBUG2(ql4_printk(KERN_INFO, ha, + ": conn_err=0x%08x, send target completed" + " or access denied failure\n", conn_err)); relogin = 0; } if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) { /* Login Response PDU returned an error. Login Response Status in Error Code Detail indicates login should not be retried.*/ - DEBUG2(dev_info(&ha->pdev->dev, - ": conn_err=0x%08x, do not retry relogin\n", - conn_err)); + DEBUG2(ql4_printk(KERN_INFO, ha, + ": conn_err=0x%08x, do not retry relogin\n", + conn_err)); relogin = 0; } @@ -736,13 +736,13 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (fw_ddb_entry == NULL) { - DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n", + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DMA alloc failed\n", __func__)); goto exit_build_ddb_list_no_free; } - dev_info(&ha->pdev->dev, "Initializing DDBs ...\n"); + ql4_printk(KERN_INFO, ha, "Initializing DDBs ...\n"); for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index = next_fw_ddb_index) { /* First, let's see if a device exists here */ @@ -826,7 +826,7 @@ next_one: } status = QLA_SUCCESS; - dev_info(&ha->pdev->dev, "DDB list done..\n"); + ql4_printk(KERN_INFO, ha, "DDB list done..\n"); exit_build_ddb_list: dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry, @@ -1080,17 +1080,17 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha) } /* Get EEPRom Parameters from NVRAM and validate */ - dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n"); + ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n"); if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { spin_lock_irqsave(&ha->hardware_lock, flags); extHwConfig.Asuint32_t = rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha)); spin_unlock_irqrestore(&ha->hardware_lock, flags); } else { - dev_warn(&ha->pdev->dev, - "scsi%ld: %s: EEProm checksum invalid. " - "Please update your EEPROM\n", ha->host_no, - __func__); + ql4_printk(KERN_WARNING, ha, + "scsi%ld: %s: EEProm checksum invalid. " + "Please update your EEPROM\n", ha->host_no, + __func__); /* Attempt to set defaults */ if (is_qla4010(ha)) @@ -1128,7 +1128,7 @@ void qla4xxx_pci_config(struct scsi_qla_host *ha) uint16_t w; int status; - dev_info(&ha->pdev->dev, "Configuring PCI space...\n"); + ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); pci_set_master(ha->pdev); status = pci_set_mwi(ha->pdev); @@ -1150,7 +1150,7 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) unsigned long flags; uint32_t mbox_status; - dev_info(&ha->pdev->dev, "Starting firmware ...\n"); + ql4_printk(KERN_INFO, ha, "Starting firmware ...\n"); /* * Start firmware from flash ROM @@ -1569,7 +1569,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, } else { /* Device went away, mark device missing */ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { - DEBUG2(dev_info(&ha->pdev->dev, "%s mark missing " + DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing " "ddb_entry 0x%p sess 0x%p conn 0x%p\n", __func__, ddb_entry, ddb_entry->sess, ddb_entry->conn)); diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 68d7942bf2e..aa65697a86b 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -122,8 +122,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, "handle 0x%x, sp=%p. This cmd may have already " "been completed.\n", ha->host_no, __func__, le32_to_cpu(sts_entry->handle), srb)); - dev_warn(&ha->pdev->dev, "%s invalid status entry:" - " handle=0x%0x\n", __func__, sts_entry->handle); + ql4_printk(KERN_WARNING, ha, "%s invalid status entry:" + " handle=0x%0x\n", __func__, sts_entry->handle); set_bit(DPC_RESET_HA, &ha->dpc_flags); return; } @@ -134,8 +134,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, "OS pkt->handle=%d srb=%p srb->state:%d\n", ha->host_no, __func__, sts_entry->handle, srb, srb->state)); - dev_warn(&ha->pdev->dev, "Command is NULL:" - " already returned to OS (srb=%p)\n", srb); + ql4_printk(KERN_WARNING, ha, "Command is NULL:" + " already returned to OS (srb=%p)\n", srb); return; } diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 0d3a6526841..940ee561ee0 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -607,7 +607,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, if (fw_ddb_entry) { options = le16_to_cpu(fw_ddb_entry->options); if (options & DDB_OPT_IPV6_DEVICE) { - dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " + ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " "Next %d State %04x ConnErr %08x %pI6 " ":%04d \"%s\"\n", __func__, fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], @@ -616,7 +616,7 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, le16_to_cpu(fw_ddb_entry->port), fw_ddb_entry->iscsi_name); } else { - dev_info(&ha->pdev->dev, "%s: DDB[%d] MB0 %04x Tot %d " + ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " "Next %d State %04x ConnErr %08x %pI4 " ":%04d \"%s\"\n", __func__, fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 64a1288e06b..daf5a4bf9b0 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -588,8 +588,8 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, &ha->queues_dma, GFP_KERNEL); if (ha->queues == NULL) { - dev_warn(&ha->pdev->dev, - "Memory Allocation failed - queues.\n"); + ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed - queues.\n"); goto mem_alloc_error_exit; } @@ -625,8 +625,8 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, mempool_free_slab, srb_cachep); if (ha->srb_mempool == NULL) { - dev_warn(&ha->pdev->dev, - "Memory Allocation failed - SRB Pool.\n"); + ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed - SRB Pool.\n"); goto mem_alloc_error_exit; } @@ -1301,7 +1301,7 @@ dpc_post_reset_ha: DDB_DS_SESSION_ACTIVE) { atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" " marked ONLINE\n", ha->host_no, __func__, @@ -1465,12 +1465,12 @@ int qla4xxx_iospace_config(struct scsi_qla_host *ha) pio_flags = pci_resource_flags(ha->pdev, 0); if (pio_flags & IORESOURCE_IO) { if (pio_len < MIN_IOBASE_LEN) { - dev_warn(&ha->pdev->dev, + ql4_printk(KERN_WARNING, ha, "Invalid PCI I/O region size\n"); pio = 0; } } else { - dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n"); + ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); pio = 0; } @@ -1480,20 +1480,21 @@ int qla4xxx_iospace_config(struct scsi_qla_host *ha) mmio_flags = pci_resource_flags(ha->pdev, 1); if (!(mmio_flags & IORESOURCE_MEM)) { - dev_err(&ha->pdev->dev, - "region #0 not an MMIO resource, aborting\n"); + ql4_printk(KERN_ERR, ha, + "region #0 not an MMIO resource, aborting\n"); goto iospace_error_exit; } + if (mmio_len < MIN_IOBASE_LEN) { - dev_err(&ha->pdev->dev, - "Invalid PCI mem region size, aborting\n"); + ql4_printk(KERN_ERR, ha, + "Invalid PCI mem region size, aborting\n"); goto iospace_error_exit; } if (pci_request_regions(ha->pdev, DRIVER_NAME)) { - dev_warn(&ha->pdev->dev, - "Failed to reserve PIO/MMIO regions\n"); + ql4_printk(KERN_WARNING, ha, + "Failed to reserve PIO/MMIO regions\n"); goto iospace_error_exit; } @@ -1502,8 +1503,8 @@ int qla4xxx_iospace_config(struct scsi_qla_host *ha) ha->pio_length = pio_len; ha->reg = ioremap(mmio, MIN_IOBASE_LEN); if (!ha->reg) { - dev_err(&ha->pdev->dev, - "cannot remap MMIO, aborting\n"); + ql4_printk(KERN_ERR, ha, + "cannot remap MMIO, aborting\n"); goto iospace_error_exit; } @@ -1629,7 +1630,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ret) goto probe_failed_ioconfig; - dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n", + ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", pdev->device, pdev->irq, ha->reg); qla4xxx_config_dma_addressing(ha); @@ -1645,8 +1646,8 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, /* Allocate dma buffers */ if (qla4xxx_mem_alloc(ha)) { - dev_warn(&ha->pdev->dev, - "[ERROR] Failed to allocate memory for adapter\n"); + ql4_printk(KERN_WARNING, ha, + "[ERROR] Failed to allocate memory for adapter\n"); ret = -ENOMEM; goto probe_failed; @@ -1673,7 +1674,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, } if (!test_bit(AF_ONLINE, &ha->flags)) { - dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n"); + ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); ret = -ENODEV; goto probe_failed; @@ -1689,8 +1690,9 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ret = scsi_init_shared_tag_map(host, MAX_SRBS); if (ret) { - dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed\n"); - goto probe_failed; + ql4_printk(KERN_WARNING, ha, + "scsi_init_shared_tag_map failed\n"); + goto probe_failed; } /* Startup the kernel thread for this host adapter. */ @@ -1699,7 +1701,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); ha->dpc_thread = create_singlethread_workqueue(buf); if (!ha->dpc_thread) { - dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n"); + ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); ret = -ENODEV; goto probe_failed; } @@ -1958,7 +1960,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) int ret = SUCCESS; int wait = 0; - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Abort command issued cmd=%p, pid=%ld\n", ha->host_no, id, lun, cmd, serial); @@ -1990,7 +1992,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) } } - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Abort command - %s\n", ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed"); @@ -2013,7 +2015,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) if (!ddb_entry) return ret; - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -2026,13 +2028,13 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) /* FIXME: wait for hba to go online */ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); if (stat != QLA_SUCCESS) { - dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat); + ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); goto eh_dev_reset_done; } if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), cmd->device)) { - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED - waiting for " "commands.\n"); goto eh_dev_reset_done; @@ -2043,7 +2045,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) MM_LUN_RESET) != QLA_SUCCESS) goto eh_dev_reset_done; - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -2128,7 +2130,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return FAILED; } - dev_info(&ha->pdev->dev, + ql4_printk(KERN_INFO, ha, "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -2150,7 +2152,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) return_status = SUCCESS; - dev_info(&ha->pdev->dev, "HOST RESET %s.\n", + ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", return_status == FAILED ? "FAILED" : "SUCCEDED"); return return_status; -- cgit v1.2.3-70-g09d2 From bb6f7d5b71356be560ea84dd5a721f083d3a9e8e Mon Sep 17 00:00:00 2001 From: Karen Higgins Date: Sat, 10 Jul 2010 14:51:17 +0530 Subject: [SCSI] qla4xxx: wait for device_ready before device discovery Signed-off-by: Karen Higgins Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 5fc19c44bad..e6b73b9fcc5 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -991,6 +991,9 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) qla4xxx_flush_AENS(ha); + /* Wait for an AEN */ + qla4xxx_devices_ready(ha); + /* * First perform device discovery for active * fw ddb indexes and build @@ -999,9 +1002,6 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) return status; - /* Wait for an AEN */ - qla4xxx_devices_ready(ha); - /* * Targets can come online after the inital discovery, so processing * the aens here will catch them. -- cgit v1.2.3-70-g09d2 From 3b2bef1fc85f127a99ad6b90a94b033fdc57341c Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:51:30 +0530 Subject: [SCSI] iscsi_transport: added new iscsi_param to display target alias in sysfs Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 3 +++ drivers/scsi/qla4xxx/ql4_os.c | 7 ++++++- drivers/scsi/scsi_transport_iscsi.c | 6 ++++-- include/scsi/iscsi_if.h | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index e6b73b9fcc5..266ebd45396 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -594,6 +594,9 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], min(sizeof(ddb_entry->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); + memcpy(&ddb_entry->iscsi_alias[0], &fw_ddb_entry->iscsi_alias[0], + min(sizeof(ddb_entry->iscsi_alias), + sizeof(fw_ddb_entry->iscsi_alias))); memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0], min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr))); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index daf5a4bf9b0..821384147a4 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -126,7 +126,8 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD | CAP_DATA_PATH_OFFLOAD, .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | - ISCSI_TARGET_NAME | ISCSI_TPGT, + ISCSI_TARGET_NAME | ISCSI_TPGT | + ISCSI_TARGET_ALIAS, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME, @@ -210,6 +211,10 @@ static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, case ISCSI_PARAM_TPGT: len = sprintf(buf, "%u\n", ddb_entry->tpgt); break; + case ISCSI_PARAM_TARGET_ALIAS: + len = snprintf(buf, PAGE_SIZE - 1, "%s\n", + ddb_entry->iscsi_alias); + break; default: return -ENOSYS; } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 1e6d4793542..b9aec304872 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -31,7 +31,7 @@ #include #include -#define ISCSI_SESSION_ATTRS 22 +#define ISCSI_SESSION_ATTRS 23 #define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 @@ -1763,7 +1763,8 @@ iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0); iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); -iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0) +iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0); +iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0); static ssize_t show_priv_session_state(struct device *dev, struct device_attribute *attr, @@ -2006,6 +2007,7 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO); SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME); + SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); SETUP_PRIV_SESSION_RD_ATTR(state); diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 66d377b9c72..a8631acd37c 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -313,6 +313,7 @@ enum iscsi_param { ISCSI_PARAM_INITIATOR_NAME, ISCSI_PARAM_TGT_RESET_TMO, + ISCSI_PARAM_TARGET_ALIAS, /* must always be last */ ISCSI_PARAM_MAX, }; @@ -353,6 +354,7 @@ enum iscsi_param { #define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID) #define ISCSI_INITIATOR_NAME (1ULL << ISCSI_PARAM_INITIATOR_NAME) #define ISCSI_TGT_RESET_TMO (1ULL << ISCSI_PARAM_TGT_RESET_TMO) +#define ISCSI_TARGET_ALIAS (1ULL << ISCSI_PARAM_TARGET_ALIAS) /* iSCSI HBA params */ enum iscsi_host_param { -- cgit v1.2.3-70-g09d2 From 4b6c83f57874c2ac10b450ba0f57db0a0f22db67 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Sat, 10 Jul 2010 14:51:47 +0530 Subject: [SCSI] qla4xxx: Update driver version to 5.02.00-k2 Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 28a6c494a2e..c905dbd7533 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k1" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k2" -- cgit v1.2.3-70-g09d2 From 660bdddb52843d361e47c30294366ae0deac821b Mon Sep 17 00:00:00 2001 From: Cyril Jayaprakash Date: Mon, 12 Jul 2010 00:42:00 +0530 Subject: [SCSI] pmcraid : Remove unnecessary casts for void * pointers Signed-off-by: Cyril Jayaprakash Acked-by: Anil Ravindranath Signed-off-by: James Bottomley --- drivers/scsi/pmcraid.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 9ebcea3643b..ecc45c8b4e6 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3599,8 +3599,7 @@ static int pmcraid_chr_open(struct inode *inode, struct file *filep) */ static int pmcraid_chr_release(struct inode *inode, struct file *filep) { - struct pmcraid_instance *pinstance = - ((struct pmcraid_instance *)filep->private_data); + struct pmcraid_instance *pinstance = filep->private_data; filep->private_data = NULL; fasync_helper(-1, filep, 0, &pinstance->aen_queue); @@ -3619,7 +3618,7 @@ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) struct pmcraid_instance *pinstance; int rc; - pinstance = (struct pmcraid_instance *)filep->private_data; + pinstance = filep->private_data; mutex_lock(&pinstance->aen_queue_lock); rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); mutex_unlock(&pinstance->aen_queue_lock); @@ -4110,7 +4109,7 @@ static long pmcraid_chr_ioctl( return retval; } - pinstance = (struct pmcraid_instance *)filep->private_data; + pinstance = filep->private_data; if (!pinstance) { pmcraid_info("adapter instance is not found\n"); -- cgit v1.2.3-70-g09d2 From 48813cf989eb8695fe84df30207fc8ff5f15783c Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Wed, 14 Jul 2010 13:12:57 +0300 Subject: [SCSI] aic7xxx: Remove OS utility wrappers This patch removes malloc(), free(), and printf() wrappers from the aic7xxx SCSI driver. I didn't use pr_debug for printf because of some 'clever' uses of printf don't compile with the pr_debug. I didn't fix the overeager uses of GFP_ATOMIC either because I wanted to keep this patch as simple as possible. [jejb:fixed up checkpatch errors and fixed up missed conversion] Signed-off-by: Pekka Enberg Acked-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7770.c | 12 +- drivers/scsi/aic7xxx/aic7770_osm.c | 2 +- drivers/scsi/aic7xxx/aic79xx_core.c | 624 ++++++++++++++++----------------- drivers/scsi/aic7xxx/aic79xx_osm.c | 108 +++--- drivers/scsi/aic7xxx/aic79xx_osm.h | 7 - drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 8 +- drivers/scsi/aic7xxx/aic79xx_pci.c | 56 +-- drivers/scsi/aic7xxx/aic79xx_proc.c | 13 +- drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 10 +- drivers/scsi/aic7xxx/aic7xxx_core.c | 430 +++++++++++------------ drivers/scsi/aic7xxx/aic7xxx_osm.c | 76 ++-- drivers/scsi/aic7xxx/aic7xxx_osm.h | 7 - drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 8 +- drivers/scsi/aic7xxx/aic7xxx_pci.c | 74 ++-- drivers/scsi/aic7xxx/aic7xxx_proc.c | 15 +- 15 files changed, 712 insertions(+), 738 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 6d86a9be538..5000bd69c13 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -170,7 +170,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) case 15: break; default: - printf("aic7770_config: invalid irq setting %d\n", intdef); + printk("aic7770_config: invalid irq setting %d\n", intdef); return (ENXIO); } @@ -221,7 +221,7 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) break; } if (have_seeprom == 0) { - free(ahc->seep_config, M_DEVBUF); + kfree(ahc->seep_config); ahc->seep_config = NULL; } @@ -293,7 +293,7 @@ aha2840_load_seeprom(struct ahc_softc *ahc) sc = ahc->seep_config; if (bootverbose) - printf("%s: Reading SEEPROM...", ahc_name(ahc)); + printk("%s: Reading SEEPROM...", ahc_name(ahc)); have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc, /*start_addr*/0, sizeof(*sc)/2); @@ -301,16 +301,16 @@ aha2840_load_seeprom(struct ahc_softc *ahc) if (ahc_verify_cksum(sc) == 0) { if(bootverbose) - printf ("checksum error\n"); + printk ("checksum error\n"); have_seeprom = 0; } else if (bootverbose) { - printf("done.\n"); + printk("done.\n"); } } if (!have_seeprom) { if (bootverbose) - printf("%s: No SEEPROM available\n", ahc_name(ahc)); + printk("%s: No SEEPROM available\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; } else { /* diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index f220e5e436a..0cb8ef64b5c 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -85,7 +85,7 @@ aic7770_probe(struct device *dev) int error; sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); if (name == NULL) return (ENOMEM); strcpy(name, buf); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 78971db5b60..3233bf56443 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -289,7 +289,7 @@ ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) || ahd->dst_mode == AHD_MODE_UNKNOWN) panic("Setting mode prior to saving it.\n"); if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) - printf("%s: Setting mode 0x%x\n", ahd_name(ahd), + printk("%s: Setting mode 0x%x\n", ahd_name(ahd), ahd_build_mode_state(ahd, src, dst)); #endif ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); @@ -307,7 +307,7 @@ ahd_update_modes(struct ahd_softc *ahd) mode_ptr = ahd_inb(ahd, MODE_PTR); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) - printf("Reading mode 0x%x\n", mode_ptr); + printk("Reading mode 0x%x\n", mode_ptr); #endif ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); ahd_known_modes(ahd, src, dst); @@ -877,7 +877,7 @@ ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) uint64_t host_dataptr; host_dataptr = ahd_le64toh(scb->hscb->dataptr); - printf("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", + printk("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", ahd_name(ahd), SCB_GET_TAG(scb), scb->hscb->scsiid, ahd_le32toh(scb->hscb->hscb_busaddr), @@ -1174,7 +1174,7 @@ ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_FIFOS) != 0) - printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo); + printk("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo); #endif saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, fifo, fifo); @@ -1215,7 +1215,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd) scbid = ahd_inw(ahd, GSFIFO); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Warning - GSFIFO SCB %d invalid\n", + printk("%s: Warning - GSFIFO SCB %d invalid\n", ahd_name(ahd), scbid); continue; } @@ -1339,7 +1339,7 @@ rescan_fifos: next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Warning - DMA-up and complete " + printk("%s: Warning - DMA-up and complete " "SCB %d invalid\n", ahd_name(ahd), scbid); continue; } @@ -1360,7 +1360,7 @@ rescan_fifos: next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Warning - Complete Qfrz SCB %d invalid\n", + printk("%s: Warning - Complete Qfrz SCB %d invalid\n", ahd_name(ahd), scbid); continue; } @@ -1377,7 +1377,7 @@ rescan_fifos: next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Warning - Complete SCB %d invalid\n", + printk("%s: Warning - Complete SCB %d invalid\n", ahd_name(ahd), scbid); continue; } @@ -1682,7 +1682,7 @@ ahd_run_qoutfifo(struct ahd_softc *ahd) scb_index = ahd_le16toh(completion->tag); scb = ahd_lookup_scb(ahd, scb_index); if (scb == NULL) { - printf("%s: WARNING no command for scb %d " + printk("%s: WARNING no command for scb %d " "(cmdcmplt)\nQOUTPOS = %d\n", ahd_name(ahd), scb_index, ahd->qoutfifonext); @@ -1714,7 +1714,7 @@ ahd_handle_hwerrint(struct ahd_softc *ahd) error = ahd_inb(ahd, ERROR); for (i = 0; i < num_errors; i++) { if ((error & ahd_hard_errors[i].errno) != 0) - printf("%s: hwerrint, %s\n", + printk("%s: hwerrint, %s\n", ahd_name(ahd), ahd_hard_errors[i].errmesg); } @@ -1747,7 +1747,7 @@ ahd_dump_sglist(struct scb *scb) addr = ahd_le64toh(sg_list[i].addr); len = ahd_le32toh(sg_list[i].len); - printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", + printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, (uint32_t)((addr >> 32) & 0xFFFFFFFF), (uint32_t)(addr & 0xFFFFFFFF), @@ -1763,7 +1763,7 @@ ahd_dump_sglist(struct scb *scb) uint32_t len; len = ahd_le32toh(sg_list[i].len); - printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", + printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, (len & AHD_SG_HIGH_ADDR_MASK) >> 24, ahd_le32toh(sg_list[i].addr), @@ -1802,7 +1802,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ahd_update_modes(ahd); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: Handle Seqint Called for code %d\n", + printk("%s: Handle Seqint Called for code %d\n", ahd_name(ahd), seqintcode); #endif switch (seqintcode) { @@ -1836,18 +1836,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s: Assuming LQIPHASE_NLQ with " + printk("%s: Assuming LQIPHASE_NLQ with " "P0 assertion\n", ahd_name(ahd)); #endif } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s: Entering NONPACK\n", ahd_name(ahd)); + printk("%s: Entering NONPACK\n", ahd_name(ahd)); #endif break; } case INVALID_SEQINT: - printf("%s: Invalid Sequencer interrupt occurred, " + printk("%s: Invalid Sequencer interrupt occurred, " "resetting channel.\n", ahd_name(ahd)); #ifdef AHD_DEBUG @@ -1866,8 +1866,8 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) if (scb != NULL) ahd_print_path(ahd, scb); else - printf("%s: ", ahd_name(ahd)); - printf("SCB %d Packetized Status Overrun", scbid); + printk("%s: ", ahd_name(ahd)); + printk("SCB %d Packetized Status Overrun", scbid); ahd_dump_card_state(ahd); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); break; @@ -1881,7 +1881,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { ahd_dump_card_state(ahd); - printf("CFG4ISTAT: Free SCB %d referenced", scbid); + printk("CFG4ISTAT: Free SCB %d referenced", scbid); panic("For safety"); } ahd_outq(ahd, HADDR, scb->sense_busaddr); @@ -1896,7 +1896,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) u_int bus_phase; bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; - printf("%s: ILLEGAL_PHASE 0x%x\n", + printk("%s: ILLEGAL_PHASE 0x%x\n", ahd_name(ahd), bus_phase); switch (bus_phase) { @@ -1908,7 +1908,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) case P_STATUS: case P_MESGIN: ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - printf("%s: Issued Bus Reset.\n", ahd_name(ahd)); + printk("%s: Issued Bus Reset.\n", ahd_name(ahd)); break; case P_COMMAND: { @@ -1933,7 +1933,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("Invalid phase with no valid SCB. " + printk("Invalid phase with no valid SCB. " "Resetting bus.\n"); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); @@ -1997,7 +1997,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { ahd_print_path(ahd, scb); - printf("Unexpected command phase from " + printk("Unexpected command phase from " "packetized target\n"); } #endif @@ -2013,7 +2013,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), + printk("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), ahd_inb(ahd, MODE_PTR)); } #endif @@ -2049,7 +2049,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printf("%s: PDATA_REINIT - DFCNTRL = 0x%x " + printk("%s: PDATA_REINIT - DFCNTRL = 0x%x " "SG_CACHE_SHADOW = 0x%x\n", ahd_name(ahd), ahd_inb(ahd, DFCNTRL), ahd_inb(ahd, SG_CACHE_SHADOW)); @@ -2082,7 +2082,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; if (bus_phase != P_MESGIN && bus_phase != P_MESGOUT) { - printf("ahd_intr: HOST_MSG_LOOP bad " + printk("ahd_intr: HOST_MSG_LOOP bad " "phase 0x%x\n", bus_phase); /* * Probably transitioned to bus free before @@ -2131,29 +2131,29 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); - printf("%s:%c:%d: no active SCB for reconnecting " + printk("%s:%c:%d: no active SCB for reconnecting " "target - issuing BUS DEVICE RESET\n", ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4); - printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " "REG0 == 0x%x ACCUM = 0x%x\n", ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN), ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM)); - printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " "SINDEX == 0x%x\n", ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd), ahd_find_busy_tcl(ahd, BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN))), ahd_inw(ahd, SINDEX)); - printf("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + printk("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " "SCB_CONTROL == 0x%x\n", ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID), ahd_inb_scbram(ahd, SCB_LUN), ahd_inb_scbram(ahd, SCB_CONTROL)); - printf("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n", + printk("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n", ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI)); - printf("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0)); - printf("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0)); + printk("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0)); + printk("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0)); ahd_dump_card_state(ahd); ahd->msgout_buf[0] = MSG_BUS_DEV_RESET; ahd->msgout_len = 1; @@ -2181,7 +2181,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) u_int lastphase; lastphase = ahd_inb(ahd, LASTPHASE); - printf("%s:%c:%d: unknown scsi bus phase %x, " + printk("%s:%c:%d: unknown scsi bus phase %x, " "lastphase = 0x%x. Attempting to continue\n", ahd_name(ahd), 'A', SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), @@ -2193,7 +2193,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) u_int lastphase; lastphase = ahd_inb(ahd, LASTPHASE); - printf("%s:%c:%d: Missed busfree. " + printk("%s:%c:%d: Missed busfree. " "Lastphase = 0x%x, Curphase = 0x%x\n", ahd_name(ahd), 'A', SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), @@ -2223,11 +2223,11 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) lastphase = ahd_inb(ahd, LASTPHASE); if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { ahd_print_path(ahd, scb); - printf("data overrun detected %s. Tag == 0x%x.\n", + printk("data overrun detected %s. Tag == 0x%x.\n", ahd_lookup_phase_entry(lastphase)->phasemsg, SCB_GET_TAG(scb)); ahd_print_path(ahd, scb); - printf("%s seen Data Phase. Length = %ld. " + printk("%s seen Data Phase. Length = %ld. " "NumSGs = %d.\n", ahd_inb(ahd, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", @@ -2252,7 +2252,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) u_int scbid; ahd_fetch_devinfo(ahd, &devinfo); - printf("%s:%c:%d:%d: Attempt to issue message failed\n", + printk("%s:%c:%d:%d: Attempt to issue message failed\n", ahd_name(ahd), devinfo.channel, devinfo.target, devinfo.lun); scbid = ahd_get_scbptr(ahd); @@ -2285,7 +2285,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) cam_status error; ahd_print_path(ahd, scb); - printf("Task Management Func 0x%x Complete\n", + printk("Task Management Func 0x%x Complete\n", scb->hscb->task_management); lun = CAM_LUN_WILDCARD; tag = SCB_LIST_NULL; @@ -2341,7 +2341,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * the QINFIFO if it is still there. */ ahd_print_path(ahd, scb); - printf("SCB completes before TMF\n"); + printk("SCB completes before TMF\n"); /* * Handle losing the race. Wait until any * current selection completes. We will then @@ -2366,7 +2366,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) case TRACEPOINT1: case TRACEPOINT2: case TRACEPOINT3: - printf("%s: Tracepoint %d\n", ahd_name(ahd), + printk("%s: Tracepoint %d\n", ahd_name(ahd), seqintcode - TRACEPOINT0); break; case NO_SEQINT: @@ -2375,7 +2375,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ahd_handle_hwerrint(ahd); break; default: - printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), + printk("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), seqintcode); break; } @@ -2440,7 +2440,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) u_int now_lvd; now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40; - printf("%s: Transceiver State Has Changed to %s mode\n", + printk("%s: Transceiver State Has Changed to %s mode\n", ahd_name(ahd), now_lvd ? "LVD" : "SE"); ahd_outb(ahd, CLRSINT0, CLRIOERR); /* @@ -2452,12 +2452,12 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_unpause(ahd); } else if ((status0 & OVERRUN) != 0) { - printf("%s: SCSI offset overrun detected. Resetting bus.\n", + printk("%s: SCSI offset overrun detected. Resetting bus.\n", ahd_name(ahd)); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); } else if ((status & SCSIRSTI) != 0) { - printf("%s: Someone reset channel A\n", ahd_name(ahd)); + printk("%s: Someone reset channel A\n", ahd_name(ahd)); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE); } else if ((status & SCSIPERR) != 0) { @@ -2467,7 +2467,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_handle_transmission_error(ahd); } else if (lqostat0 != 0) { - printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0); + printk("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0); ahd_outb(ahd, CLRLQOINT0, lqostat0); if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) ahd_outb(ahd, CLRLQOINT1, 0); @@ -2497,7 +2497,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) scbid = ahd_inw(ahd, WAITING_TID_HEAD); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: ahd_intr - referenced scb not " + printk("%s: ahd_intr - referenced scb not " "valid during SELTO scb(0x%x)\n", ahd_name(ahd), scbid); ahd_dump_card_state(ahd); @@ -2506,7 +2506,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_SELTO) != 0) { ahd_print_path(ahd, scb); - printf("Saw Selection Timeout for SCB 0x%x\n", + printk("Saw Selection Timeout for SCB 0x%x\n", scbid); } #endif @@ -2534,7 +2534,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_iocell_first_selection(ahd); ahd_unpause(ahd); } else if (status3 != 0) { - printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n", + printk("%s: SCSI Cell parity error SSTAT3 == 0x%x\n", ahd_name(ahd), status3); ahd_outb(ahd, CLRSINT3, status3); } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { @@ -2587,7 +2587,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Invalid SCB %d in DFF%d " + printk("%s: Invalid SCB %d in DFF%d " "during unexpected busfree\n", ahd_name(ahd), scbid, mode); packetized = 0; @@ -2620,7 +2620,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("Saw Busfree. Busfreetime = 0x%x.\n", + printk("Saw Busfree. Busfreetime = 0x%x.\n", busfreetime); #endif /* @@ -2661,7 +2661,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_unpause(ahd); } } else { - printf("%s: Missing case in ahd_handle_scsiint. status = %x\n", + printk("%s: Missing case in ahd_handle_scsiint. status = %x\n", ahd_name(ahd), status); ahd_dump_card_state(ahd); ahd_clear_intstat(ahd); @@ -2697,7 +2697,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) || (lqistate == 0x29)) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printf("%s: NLQCRC found via LQISTATE\n", + printk("%s: NLQCRC found via LQISTATE\n", ahd_name(ahd)); } #endif @@ -2729,18 +2729,18 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) cur_col = 0; if (silent == FALSE) { - printf("%s: Transmission error detected\n", ahd_name(ahd)); + printk("%s: Transmission error detected\n", ahd_name(ahd)); ahd_lqistat1_print(lqistat1, &cur_col, 50); ahd_lastphase_print(lastphase, &cur_col, 50); ahd_scsisigi_print(curphase, &cur_col, 50); ahd_perrdiag_print(perrdiag, &cur_col, 50); - printf("\n"); + printk("\n"); ahd_dump_card_state(ahd); } if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) { if (silent == FALSE) { - printf("%s: Gross protocol error during incoming " + printk("%s: Gross protocol error during incoming " "packet. lqistat1 == 0x%x. Resetting bus.\n", ahd_name(ahd), lqistat1); } @@ -2769,7 +2769,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) * (SPI4R09 10.7.3.3.3) */ ahd_outb(ahd, LQCTL2, LQIRETRY); - printf("LQIRetry for LQICRCI_LQ to release ACK\n"); + printk("LQIRetry for LQICRCI_LQ to release ACK\n"); } else if ((lqistat1 & LQICRCI_NLQ) != 0) { /* * We detected a CRC error in a NON-LQ packet. @@ -2817,22 +2817,22 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) * Busfree detection is enabled. */ if (silent == FALSE) - printf("LQICRC_NLQ\n"); + printk("LQICRC_NLQ\n"); if (scb == NULL) { - printf("%s: No SCB valid for LQICRC_NLQ. " + printk("%s: No SCB valid for LQICRC_NLQ. " "Resetting bus\n", ahd_name(ahd)); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); return; } } else if ((lqistat1 & LQIBADLQI) != 0) { - printf("Need to handle BADLQI!\n"); + printk("Need to handle BADLQI!\n"); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); return; } else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) { if ((curphase & ~P_DATAIN_DT) != 0) { /* Ack the byte. So we can continue. */ if (silent == FALSE) - printf("Acking %s to clear perror\n", + printk("Acking %s to clear perror\n", ahd_lookup_phase_entry(curphase)->phasemsg); ahd_inb(ahd, SCSIDAT); } @@ -2877,10 +2877,10 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0 && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) { if ((lqistat1 & LQIPHASE_LQ) != 0) { - printf("LQIRETRY for LQIPHASE_LQ\n"); + printk("LQIRETRY for LQIPHASE_LQ\n"); ahd_outb(ahd, LQCTL2, LQIRETRY); } else if ((lqistat1 & LQIPHASE_NLQ) != 0) { - printf("LQIRETRY for LQIPHASE_NLQ\n"); + printk("LQIRETRY for LQIPHASE_NLQ\n"); ahd_outb(ahd, LQCTL2, LQIRETRY); } else panic("ahd_handle_lqiphase_error: No phase errors\n"); @@ -2888,7 +2888,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) ahd_outb(ahd, CLRINT, CLRSCSIINT); ahd_unpause(ahd); } else { - printf("Reseting Channel for LQI Phase error\n"); + printk("Reseting Channel for LQI Phase error\n"); ahd_dump_card_state(ahd); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); } @@ -2976,7 +2976,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) { if (SCB_IS_SILENT(scb) == FALSE) { ahd_print_path(ahd, scb); - printf("Probable outgoing LQ CRC error. " + printk("Probable outgoing LQ CRC error. " "Retrying command\n"); } scb->crc_retry_count++; @@ -2998,7 +2998,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0) - printf("%s: Parity on last REQ detected " + printk("%s: Parity on last REQ detected " "during busfree phase.\n", ahd_name(ahd)); #endif @@ -3012,7 +3012,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); ahd_print_path(ahd, scb); - printf("Unexpected PKT busfree condition\n"); + printk("Unexpected PKT busfree condition\n"); ahd_dump_card_state(ahd); ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A', SCB_GET_LUN(scb), SCB_GET_TAG(scb), @@ -3021,7 +3021,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) /* Return restarting the sequencer. */ return (1); } - printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd)); + printk("%s: Unexpected PKT busfree condition\n", ahd_name(ahd)); ahd_dump_card_state(ahd); /* Restart the sequencer. */ return (1); @@ -3076,14 +3076,14 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) if (scb == NULL) { ahd_print_devinfo(ahd, &devinfo); - printf("Abort for unidentified " + printk("Abort for unidentified " "connection completed.\n"); /* restart the sequencer. */ return (1); } sent_msg = ahd->msgout_buf[ahd->msgout_index - 1]; ahd_print_path(ahd, scb); - printf("SCB %d - Abort%s Completed.\n", + printk("SCB %d - Abort%s Completed.\n", SCB_GET_TAG(scb), sent_msg == MSG_ABORT_TAG ? "" : " Tag"); @@ -3109,7 +3109,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) found = ahd_abort_scbs(ahd, target, 'A', saved_lun, tag, ROLE_INITIATOR, CAM_REQ_ABORTED); - printf("found == 0x%x\n", found); + printk("found == 0x%x\n", found); printerror = 0; } else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_BUS_DEV_RESET, TRUE)) { @@ -3147,7 +3147,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("PPR negotiation rejected busfree.\n"); + printk("PPR negotiation rejected busfree.\n"); #endif tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, devinfo.our_scsiid, @@ -3191,7 +3191,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("WDTR negotiation rejected busfree.\n"); + printk("WDTR negotiation rejected busfree.\n"); #endif ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, @@ -3216,7 +3216,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("SDTR negotiation rejected busfree.\n"); + printk("SDTR negotiation rejected busfree.\n"); #endif ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, @@ -3240,7 +3240,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("Expected IDE Busfree\n"); + printk("Expected IDE Busfree\n"); #endif printerror = 0; } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE) @@ -3249,7 +3249,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("Expected QAS Reject Busfree\n"); + printk("Expected QAS Reject Busfree\n"); #endif printerror = 0; } @@ -3275,7 +3275,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) } else { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("PPR Negotiation Busfree.\n"); + printk("PPR Negotiation Busfree.\n"); #endif ahd_done(ahd, scb); } @@ -3302,9 +3302,9 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) * We had not fully identified this connection, * so we cannot abort anything. */ - printf("%s: ", ahd_name(ahd)); + printk("%s: ", ahd_name(ahd)); } - printf("Unexpected busfree %s, %d SCBs aborted, " + printk("Unexpected busfree %s, %d SCBs aborted, " "PRGMCNT == 0x%x\n", ahd_lookup_phase_entry(lastphase)->phasemsg, aborted, @@ -3342,7 +3342,7 @@ ahd_handle_proto_violation(struct ahd_softc *ahd) * to match. */ ahd_print_devinfo(ahd, &devinfo); - printf("Target did not send an IDENTIFY message. " + printk("Target did not send an IDENTIFY message. " "LASTPHASE = 0x%x.\n", lastphase); scb = NULL; } else if (scb == NULL) { @@ -3351,13 +3351,13 @@ ahd_handle_proto_violation(struct ahd_softc *ahd) * transaction. Print an error and reset the bus. */ ahd_print_devinfo(ahd, &devinfo); - printf("No SCB found during protocol violation\n"); + printk("No SCB found during protocol violation\n"); goto proto_violation_reset; } else { ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL); if ((seq_flags & NO_CDB_SENT) != 0) { ahd_print_path(ahd, scb); - printf("No or incomplete CDB sent to device.\n"); + printk("No or incomplete CDB sent to device.\n"); } else if ((ahd_inb_scbram(ahd, SCB_CONTROL) & STATUS_RCVD) == 0) { /* @@ -3368,10 +3368,10 @@ ahd_handle_proto_violation(struct ahd_softc *ahd) * message. */ ahd_print_path(ahd, scb); - printf("Completed command without status.\n"); + printk("Completed command without status.\n"); } else { ahd_print_path(ahd, scb); - printf("Unknown protocol violation.\n"); + printk("Unknown protocol violation.\n"); ahd_dump_card_state(ahd); } } @@ -3385,7 +3385,7 @@ proto_violation_reset: * it away with a bus reset. */ found = ahd_reset_channel(ahd, 'A', TRUE); - printf("%s: Issued Channel %c Bus Reset. " + printk("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahd_name(ahd), 'A', found); } else { /* @@ -3407,7 +3407,7 @@ proto_violation_reset: ahd_print_path(ahd, scb); scb->flags |= SCB_ABORT; } - printf("Protocol violation %s. Attempting to abort.\n", + printk("Protocol violation %s. Attempting to abort.\n", ahd_lookup_phase_entry(curphase)->phasemsg); } } @@ -3425,7 +3425,7 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { ahd_print_devinfo(ahd, devinfo); - printf("Forcing renegotiation\n"); + printk("Forcing renegotiation\n"); } #endif targ_info = ahd_fetch_transinfo(ahd, @@ -3486,7 +3486,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd) break; if (steps > AHD_MAX_STEPS) { - printf("%s: Infinite loop in critical section\n" + printk("%s: Infinite loop in critical section\n" "%s: First Instruction 0x%x now 0x%x\n", ahd_name(ahd), ahd_name(ahd), first_instr, seqaddr); @@ -3497,7 +3497,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd) steps++; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: Single stepping at 0x%x\n", ahd_name(ahd), + printk("%s: Single stepping at 0x%x\n", ahd_name(ahd), seqaddr); #endif if (stepping == FALSE) { @@ -3601,16 +3601,16 @@ ahd_print_scb(struct scb *scb) int i; hscb = scb->hscb; - printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", + printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", (void *)scb, hscb->control, hscb->scsiid, hscb->lun, hscb->cdb_len); - printf("Shared Data: "); + printk("Shared Data: "); for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++) - printf("%#02x", hscb->shared_data.idata.cdb[i]); - printf(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", + printk("%#02x", hscb->shared_data.idata.cdb[i]); + printk(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF), ahd_le32toh(hscb->datacnt), @@ -3637,7 +3637,7 @@ ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel) && ahd->enabled_targets[scsi_id] != master_tstate) panic("%s: ahd_alloc_tstate - Target already allocated", ahd_name(ahd)); - tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); + tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); if (tstate == NULL) return (NULL); @@ -3682,7 +3682,7 @@ ahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force) tstate = ahd->enabled_targets[scsi_id]; if (tstate != NULL) - free(tstate, M_DEVBUF); + kfree(tstate); ahd->enabled_targets[scsi_id] = NULL; } #endif @@ -3942,37 +3942,37 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if (offset != 0) { int options; - printf("%s: target %d synchronous with " + printk("%s: target %d synchronous with " "period = 0x%x, offset = 0x%x", ahd_name(ahd), devinfo->target, period, offset); options = 0; if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { - printf("(RDSTRM"); + printk("(RDSTRM"); options++; } if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - printf("%s", options ? "|DT" : "(DT"); + printk("%s", options ? "|DT" : "(DT"); options++; } if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - printf("%s", options ? "|IU" : "(IU"); + printk("%s", options ? "|IU" : "(IU"); options++; } if ((ppr_options & MSG_EXT_PPR_RTI) != 0) { - printf("%s", options ? "|RTI" : "(RTI"); + printk("%s", options ? "|RTI" : "(RTI"); options++; } if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { - printf("%s", options ? "|QAS" : "(QAS"); + printk("%s", options ? "|QAS" : "(QAS"); options++; } if (options != 0) - printf(")\n"); + printk(")\n"); else - printf("\n"); + printk("\n"); } else { - printf("%s: target %d using " + printk("%s: target %d using " "asynchronous transfers%s\n", ahd_name(ahd), devinfo->target, (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0 @@ -4000,7 +4000,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { ahd_print_devinfo(ahd, devinfo); - printf("Expecting IU Change busfree\n"); + printk("Expecting IU Change busfree\n"); } #endif ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE @@ -4009,7 +4009,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("PPR with IU_REQ outstanding\n"); + printk("PPR with IU_REQ outstanding\n"); #endif ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE; } @@ -4061,7 +4061,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_send_async(ahd, devinfo->channel, devinfo->target, CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { - printf("%s: target %d using %dbit transfers\n", + printk("%s: target %d using %dbit transfers\n", ahd_name(ahd), devinfo->target, 8 * (0x01 << width)); } @@ -4337,7 +4337,7 @@ ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) void ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { - printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A', + printk("%s:%c:%d:%d: ", ahd_name(ahd), 'A', devinfo->target, devinfo->lun); } @@ -4419,11 +4419,11 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("Setting up for Parity Error delivery\n"); + printk("Setting up for Parity Error delivery\n"); #endif return; } else if (scb == NULL) { - printf("%s: WARNING. No pending message for " + printk("%s: WARNING. No pending message for " "I_T msgin. Issuing NO-OP\n", ahd_name(ahd)); ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP; ahd->msgout_len++; @@ -4454,7 +4454,7 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET; ahd->msgout_len++; ahd_print_path(ahd, scb); - printf("Bus Device Reset Message Sent\n"); + printk("Bus Device Reset Message Sent\n"); /* * Clear our selection hardware in advance of * the busfree. We may have an entry in the waiting @@ -4472,7 +4472,7 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, } ahd->msgout_len++; ahd_print_path(ahd, scb); - printf("Abort%s Message Sent\n", + printk("Abort%s Message Sent\n", (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); /* * Clear our selection hardware in advance of @@ -4493,9 +4493,9 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, */ ahd_outb(ahd, SCSISEQ0, 0); } else { - printf("ahd_intr: AWAITING_MSG for an SCB that " + printk("ahd_intr: AWAITING_MSG for an SCB that " "does not have a waiting message\n"); - printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, + printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, devinfo->target_mask); panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x " "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control, @@ -4577,7 +4577,7 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) if (bootverbose) { ahd_print_devinfo(ahd, devinfo); - printf("Ensuring async\n"); + printk("Ensuring async\n"); } } /* Target initiated PPR is not allowed in the SCSI spec */ @@ -4624,7 +4624,7 @@ ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd->msgout_buf + ahd->msgout_index, period, offset); ahd->msgout_len += 5; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", + printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, period, offset); } @@ -4642,7 +4642,7 @@ ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd->msgout_buf + ahd->msgout_index, bus_width); ahd->msgout_len += 4; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending WDTR %x\n", + printk("(%s:%c:%d:%d): Sending WDTR %x\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, bus_width); } @@ -4671,7 +4671,7 @@ ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, bus_width, ppr_options); ahd->msgout_len += 8; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " + printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " "offset %x, ppr_options %x\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, bus_width, period, offset, ppr_options); @@ -4721,7 +4721,7 @@ ahd_handle_message_phase(struct ahd_softc *ahd) bus_phase = ahd_inb(ahd, LASTPHASE); if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) { - printf("LQIRETRY for LQIPHASE_OUTPKT\n"); + printk("LQIRETRY for LQIPHASE_OUTPKT\n"); ahd_outb(ahd, LQCTL2, LQIRETRY); } reswitch: @@ -4738,14 +4738,14 @@ reswitch: #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { ahd_print_devinfo(ahd, &devinfo); - printf("INITIATOR_MSG_OUT"); + printk("INITIATOR_MSG_OUT"); } #endif phasemis = bus_phase != P_MESGOUT; if (phasemis) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - printf(" PHASEMIS %s\n", + printk(" PHASEMIS %s\n", ahd_lookup_phase_entry(bus_phase) ->phasemsg); } @@ -4772,7 +4772,7 @@ reswitch: ahd_outb(ahd, CLRSINT1, CLRREQINIT); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", ahd->send_msg_perror); + printk(" byte 0x%x\n", ahd->send_msg_perror); #endif /* * If we are notifying the target of a CRC error @@ -4813,7 +4813,7 @@ reswitch: ahd_outb(ahd, CLRSINT1, CLRREQINIT); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", + printk(" byte 0x%x\n", ahd->msgout_buf[ahd->msgout_index]); #endif ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]); @@ -4828,14 +4828,14 @@ reswitch: #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { ahd_print_devinfo(ahd, &devinfo); - printf("INITIATOR_MSG_IN"); + printk("INITIATOR_MSG_IN"); } #endif phasemis = bus_phase != P_MESGIN; if (phasemis) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - printf(" PHASEMIS %s\n", + printk(" PHASEMIS %s\n", ahd_lookup_phase_entry(bus_phase) ->phasemsg); } @@ -4856,7 +4856,7 @@ reswitch: ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", + printk(" byte 0x%x\n", ahd->msgin_buf[ahd->msgin_index]); #endif @@ -4878,7 +4878,7 @@ reswitch: #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { ahd_print_devinfo(ahd, &devinfo); - printf("Asserting ATN for response\n"); + printk("Asserting ATN for response\n"); } #endif ahd_assert_atn(ahd); @@ -5026,7 +5026,7 @@ reswitch: if (end_session) { if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) { - printf("%s: Returning to Idle Loop\n", + printk("%s: Returning to Idle Loop\n", ahd_name(ahd)); ahd_clear_msg_state(ahd); @@ -5178,7 +5178,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_validate_offset(ahd, tinfo, period, &offset, tinfo->curr.width, devinfo->role); if (bootverbose) { - printf("(%s:%c:%d:%d): Received " + printk("(%s:%c:%d:%d): Received " "SDTR period %x, offset %x\n\t" "Filtered to period %x, offset %x\n", ahd_name(ahd), devinfo->channel, @@ -5208,7 +5208,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) */ if (bootverbose && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5250,7 +5250,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_validate_width(ahd, tinfo, &bus_width, devinfo->role); if (bootverbose) { - printf("(%s:%c:%d:%d): Received WDTR " + printk("(%s:%c:%d:%d): Received WDTR " "%x filtered to %x\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, @@ -5266,7 +5266,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) */ if (saved_width > bus_width) { reject = TRUE; - printf("(%s:%c:%d:%d): requested %dBit " + printk("(%s:%c:%d:%d): requested %dBit " "transfers. Rejecting...\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, @@ -5279,7 +5279,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) */ if (bootverbose && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5391,12 +5391,12 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) } } else { if (devinfo->role != ROLE_TARGET) - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated PPR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); else - printf("(%s:%c:%d:%d): Initiator " + printk("(%s:%c:%d:%d): Initiator " "Initiated PPR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5408,7 +5408,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) response = TRUE; } if (bootverbose) { - printf("(%s:%c:%d:%d): Received PPR width %x, " + printk("(%s:%c:%d:%d): Received PPR width %x, " "period %x, offset %x,options %x\n" "\tFiltered to width %x, period %x, " "offset %x, options %x\n", @@ -5484,7 +5484,7 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) case MSG_QAS_REQUEST: #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("%s: QAS request. SCSISIGI == 0x%x\n", + printk("%s: QAS request. SCSISIGI == 0x%x\n", ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); #endif ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE; @@ -5549,7 +5549,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) * off these options. */ if (bootverbose) { - printf("(%s:%c:%d:%d): PPR Rejected. " + printk("(%s:%c:%d:%d): PPR Rejected. " "Trying simple U160 PPR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5564,7 +5564,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) * Attempt to negotiate SPI-2 style. */ if (bootverbose) { - printf("(%s:%c:%d:%d): PPR Rejected. " + printk("(%s:%c:%d:%d): PPR Rejected. " "Trying WDTR/SDTR\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5581,7 +5581,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { /* note 8bit xfers */ - printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " + printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using " "8bit transfers\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, @@ -5609,7 +5609,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) /*offset*/0, /*ppr_options*/0, AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, /*paused*/TRUE); - printf("(%s:%c:%d:%d): refuses synchronous negotiation. " + printk("(%s:%c:%d:%d): refuses synchronous negotiation. " "Using asynchronous transfers\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); @@ -5620,13 +5620,13 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); if (tag_type == MSG_SIMPLE_TASK) { - printf("(%s:%c:%d:%d): refuses tagged commands. " + printk("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); mask = ~0x23; } else { - printf("(%s:%c:%d:%d): refuses %s tagged commands. " + printk("(%s:%c:%d:%d): refuses %s tagged commands. " "Performing simple queue tagged I/O only\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK @@ -5677,7 +5677,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) /* * Otherwise, we ignore it. */ - printf("%s:%c:%d: Message reject for %x -- ignored\n", + printk("%s:%c:%d: Message reject for %x -- ignored\n", ahd_name(ahd), devinfo->channel, devinfo->target, last_msg); } @@ -5864,7 +5864,7 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd) ahd_delay(100); if (wait == 0) { ahd_print_path(ahd, scb); - printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); + printk("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); } saved_modes = ahd_save_modes(ahd); @@ -5978,7 +5978,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && bootverbose) - printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), + printk("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), message, devinfo->channel, devinfo->target, found); } @@ -6074,23 +6074,22 @@ ahd_alloc(void *platform_arg, char *name) struct ahd_softc *ahd; #ifndef __FreeBSD__ - ahd = malloc(sizeof(*ahd), M_DEVBUF, M_NOWAIT); + ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC); if (!ahd) { - printf("aic7xxx: cannot malloc softc!\n"); - free(name, M_DEVBUF); + printk("aic7xxx: cannot malloc softc!\n"); + kfree(name); return NULL; } #else ahd = device_get_softc((device_t)platform_arg); #endif memset(ahd, 0, sizeof(*ahd)); - ahd->seep_config = malloc(sizeof(*ahd->seep_config), - M_DEVBUF, M_NOWAIT); + ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); if (ahd->seep_config == NULL) { #ifndef __FreeBSD__ - free(ahd, M_DEVBUF); + kfree(ahd); #endif - free(name, M_DEVBUF); + kfree(name); return (NULL); } LIST_INIT(&ahd->pending_scbs); @@ -6120,7 +6119,7 @@ ahd_alloc(void *platform_arg, char *name) } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MEMORY) != 0) { - printf("%s: scb size = 0x%x, hscb size = 0x%x\n", + printk("%s: scb size = 0x%x, hscb size = 0x%x\n", ahd_name(ahd), (u_int)sizeof(struct scb), (u_int)sizeof(struct hardware_scb)); } @@ -6147,7 +6146,7 @@ void ahd_set_name(struct ahd_softc *ahd, char *name) { if (ahd->name != NULL) - free(ahd->name, M_DEVBUF); + kfree(ahd->name); ahd->name = name; } @@ -6201,27 +6200,27 @@ ahd_free(struct ahd_softc *ahd) lstate = tstate->enabled_luns[j]; if (lstate != NULL) { xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); + kfree(lstate); } } #endif - free(tstate, M_DEVBUF); + kfree(tstate); } } #ifdef AHD_TARGET_MODE if (ahd->black_hole != NULL) { xpt_free_path(ahd->black_hole->path); - free(ahd->black_hole, M_DEVBUF); + kfree(ahd->black_hole); } #endif if (ahd->name != NULL) - free(ahd->name, M_DEVBUF); + kfree(ahd->name); if (ahd->seep_config != NULL) - free(ahd->seep_config, M_DEVBUF); + kfree(ahd->seep_config); if (ahd->saved_stack != NULL) - free(ahd->saved_stack, M_DEVBUF); + kfree(ahd->saved_stack); #ifndef __FreeBSD__ - free(ahd, M_DEVBUF); + kfree(ahd); #endif return; } @@ -6300,7 +6299,7 @@ ahd_reset(struct ahd_softc *ahd, int reinit) } while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK)); if (wait == 0) { - printf("%s: WARNING - Failed chip reset! " + printk("%s: WARNING - Failed chip reset! " "Trying to initialize anyway.\n", ahd_name(ahd)); } ahd_outb(ahd, HCNTRL, ahd->pause); @@ -6422,7 +6421,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) /* Determine the number of hardware SCBs and initialize them */ scb_data->maxhscbs = ahd_probe_scbs(ahd); if (scb_data->maxhscbs == 0) { - printf("%s: No SCB space found\n", ahd_name(ahd)); + printk("%s: No SCB space found\n", ahd_name(ahd)); return (ENXIO); } @@ -6465,7 +6464,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MEMORY) != 0) - printf("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd), + printk("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd), ahd_sglist_allocsize(ahd)); #endif @@ -6489,7 +6488,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) ahd_alloc_scbs(ahd); if (scb_data->numscbs == 0) { - printf("%s: ahd_init_scbdata - " + printk("%s: ahd_init_scbdata - " "Unable to allocate initial scbs\n", ahd_name(ahd)); goto error_exit; @@ -6564,7 +6563,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd) sns_map->dmamap); ahd_dmamem_free(ahd, scb_data->sense_dmat, sns_map->vaddr, sns_map->dmamap); - free(sns_map, M_DEVBUF); + kfree(sns_map); } ahd_dma_tag_destroy(ahd, scb_data->sense_dmat); /* FALLTHROUGH */ @@ -6579,7 +6578,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd) sg_map->dmamap); ahd_dmamem_free(ahd, scb_data->sg_dmat, sg_map->vaddr, sg_map->dmamap); - free(sg_map, M_DEVBUF); + kfree(sg_map); } ahd_dma_tag_destroy(ahd, scb_data->sg_dmat); /* FALLTHROUGH */ @@ -6594,7 +6593,7 @@ ahd_fini_scbdata(struct ahd_softc *ahd) hscb_map->dmamap); ahd_dmamem_free(ahd, scb_data->hscb_dmat, hscb_map->vaddr, hscb_map->dmamap); - free(hscb_map, M_DEVBUF); + kfree(hscb_map); } ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat); /* FALLTHROUGH */ @@ -6624,7 +6623,7 @@ ahd_setup_iocell_workaround(struct ahd_softc *ahd) ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI)); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: Setting up iocell workaround\n", ahd_name(ahd)); + printk("%s: Setting up iocell workaround\n", ahd_name(ahd)); #endif ahd_restore_modes(ahd, saved_modes); ahd->flags &= ~AHD_HAD_FIRST_SEL; @@ -6644,14 +6643,14 @@ ahd_iocell_first_selection(struct ahd_softc *ahd) ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: iocell first selection\n", ahd_name(ahd)); + printk("%s: iocell first selection\n", ahd_name(ahd)); #endif if ((sblkctl & ENAB40) != 0) { ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: BYPASS now disabled\n", ahd_name(ahd)); + printk("%s: BYPASS now disabled\n", ahd_name(ahd)); #endif } ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); @@ -6833,7 +6832,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb)); } else { - hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT); + hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC); if (hscb_map == NULL) return; @@ -6842,7 +6841,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat, (void **)&hscb_map->vaddr, BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) { - free(hscb_map, M_DEVBUF); + kfree(hscb_map); return; } @@ -6866,7 +6865,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) segs = sg_map->vaddr + offset; sg_busaddr = sg_map->physaddr + offset; } else { - sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); + sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); if (sg_map == NULL) return; @@ -6875,7 +6874,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat, (void **)&sg_map->vaddr, BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) { - free(sg_map, M_DEVBUF); + kfree(sg_map); return; } @@ -6891,7 +6890,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd); #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_MEMORY) - printf("Mapped SG data\n"); + printk("Mapped SG data\n"); #endif } @@ -6903,7 +6902,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) sense_data = sense_map->vaddr + offset; sense_busaddr = sense_map->physaddr + offset; } else { - sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT); + sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC); if (sense_map == NULL) return; @@ -6912,7 +6911,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat, (void **)&sense_map->vaddr, BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { - free(sense_map, M_DEVBUF); + kfree(sense_map); return; } @@ -6927,7 +6926,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE; #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_MEMORY) - printf("Mapped sense data\n"); + printk("Mapped sense data\n"); #endif } @@ -6941,15 +6940,13 @@ ahd_alloc_scbs(struct ahd_softc *ahd) int error; #endif - next_scb = (struct scb *)malloc(sizeof(*next_scb), - M_DEVBUF, M_NOWAIT); + next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC); if (next_scb == NULL) break; - pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), - M_DEVBUF, M_NOWAIT); + pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); if (pdata == NULL) { - free(next_scb, M_DEVBUF); + kfree(next_scb); break; } next_scb->platform_data = pdata; @@ -6979,8 +6976,8 @@ ahd_alloc_scbs(struct ahd_softc *ahd) error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, &next_scb->dmamap); if (error != 0) { - free(next_scb, M_DEVBUF); - free(pdata, M_DEVBUF); + kfree(next_scb); + kfree(pdata); break; } #endif @@ -7077,8 +7074,7 @@ ahd_init(struct ahd_softc *ahd) AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); ahd->stack_size = ahd_probe_stack_size(ahd); - ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t), - M_DEVBUF, M_NOWAIT); + ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC); if (ahd->saved_stack == NULL) return (ENOMEM); @@ -7224,20 +7220,20 @@ ahd_init(struct ahd_softc *ahd) error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, CURSENSE_ENB); if (error != 0) { - printf("%s: current sensing timeout 1\n", ahd_name(ahd)); + printk("%s: current sensing timeout 1\n", ahd_name(ahd)); goto init_done; } for (i = 20, fstat = FLX_FSTAT_BUSY; (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) { error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat); if (error != 0) { - printf("%s: current sensing timeout 2\n", + printk("%s: current sensing timeout 2\n", ahd_name(ahd)); goto init_done; } } if (i == 0) { - printf("%s: Timedout during current-sensing test\n", + printk("%s: Timedout during current-sensing test\n", ahd_name(ahd)); goto init_done; } @@ -7245,7 +7241,7 @@ ahd_init(struct ahd_softc *ahd) /* Latch Current Sensing status. */ error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, ¤t_sensing); if (error != 0) { - printf("%s: current sensing timeout 3\n", ahd_name(ahd)); + printk("%s: current sensing timeout 3\n", ahd_name(ahd)); goto init_done; } @@ -7254,7 +7250,7 @@ ahd_init(struct ahd_softc *ahd) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) { - printf("%s: current_sensing == 0x%x\n", + printk("%s: current_sensing == 0x%x\n", ahd_name(ahd), current_sensing); } #endif @@ -7271,13 +7267,13 @@ ahd_init(struct ahd_softc *ahd) case FLX_CSTAT_OKAY: if (warn_user == 0 && bootverbose == 0) break; - printf("%s: %s Channel %s\n", ahd_name(ahd), + printk("%s: %s Channel %s\n", ahd_name(ahd), channel_strings[i], termstat_strings[term_stat]); break; } } if (warn_user) { - printf("%s: WARNING. Termination is not configured correctly.\n" + printk("%s: WARNING. Termination is not configured correctly.\n" "%s: WARNING. SCSI bus operations may FAIL.\n", ahd_name(ahd), ahd_name(ahd)); } @@ -7393,7 +7389,7 @@ ahd_chip_init(struct ahd_softc *ahd) } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), + printk("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), WRTBIASCTL_HP_DEFAULT); #endif } @@ -7622,9 +7618,9 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, NEGCONOPTS, negodat3); negodat3 = ahd_inb(ahd, NEGCONOPTS); if (!(negodat3 & ENSLOWCRC)) - printf("aic79xx: failed to set the SLOWCRC bit\n"); + printk("aic79xx: failed to set the SLOWCRC bit\n"); else - printf("aic79xx: SLOWCRC bit set\n"); + printk("aic79xx: SLOWCRC bit set\n"); } } @@ -7646,7 +7642,7 @@ ahd_default_config(struct ahd_softc *ahd) * data for any target mode initiator. */ if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { - printf("%s: unable to allocate ahd_tmode_tstate. " + printk("%s: unable to allocate ahd_tmode_tstate. " "Failing attach\n", ahd_name(ahd)); return (ENOMEM); } @@ -7725,7 +7721,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) * data for any target mode initiator. */ if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { - printf("%s: unable to allocate ahd_tmode_tstate. " + printk("%s: unable to allocate ahd_tmode_tstate. " "Failing attach\n", ahd_name(ahd)); return (ENOMEM); } @@ -7795,7 +7791,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) - printf("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width, + printk("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width, user_tinfo->period, user_tinfo->offset, user_tinfo->ppr_options); #endif @@ -7951,7 +7947,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)); if (maxloops == 0) { - printf("Infinite interrupt loop, INTSTAT = %x", + printk("Infinite interrupt loop, INTSTAT = %x", ahd_inb(ahd, INTSTAT)); } ahd->qfreeze_cnt++; @@ -8241,7 +8237,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, prev_scb = NULL; if (action == SEARCH_PRINT) { - printf("qinstart = %d qinfifonext = %d\nQINFIFO:", + printk("qinstart = %d qinfifonext = %d\nQINFIFO:", qinstart, ahd->qinfifonext); } @@ -8256,7 +8252,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, while (qinpos != qintail) { scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]); if (scb == NULL) { - printf("qinpos = %d, SCB index = %d\n", + printk("qinpos = %d, SCB index = %d\n", qinpos, ahd->qinfifo[qinpos]); panic("Loop 1\n"); } @@ -8269,13 +8265,13 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, switch (action) { case SEARCH_COMPLETE: if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in qinfifo\n"); + printk("Inactive SCB in qinfifo\n"); ahd_done_with_status(ahd, scb, status); /* FALLTHROUGH */ case SEARCH_REMOVE: break; case SEARCH_PRINT: - printf(" 0x%x", ahd->qinfifo[qinpos]); + printk(" 0x%x", ahd->qinfifo[qinpos]); /* FALLTHROUGH */ case SEARCH_COUNT: ahd_qinfifo_requeue(ahd, prev_scb, scb); @@ -8292,7 +8288,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); if (action == SEARCH_PRINT) - printf("\nWAITING_TID_QUEUES:\n"); + printk("\nWAITING_TID_QUEUES:\n"); /* * Search waiting for selection lists. We traverse the @@ -8320,7 +8316,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, panic("TID LIST LOOP"); if (scbid >= ahd->scb_data.numscbs) { - printf("%s: Waiting TID List inconsistency. " + printk("%s: Waiting TID List inconsistency. " "SCB index == 0x%x, yet numscbs == 0x%x.", ahd_name(ahd), scbid, ahd->scb_data.numscbs); ahd_dump_card_state(ahd); @@ -8328,7 +8324,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, } scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: SCB = 0x%x Not Active!\n", + printk("%s: SCB = 0x%x Not Active!\n", ahd_name(ahd), scbid); panic("Waiting TID List traversal\n"); } @@ -8344,7 +8340,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, * We found a list of scbs that needs to be searched. */ if (action == SEARCH_PRINT) - printf(" %d ( ", SCB_GET_TARGET(ahd, scb)); + printk(" %d ( ", SCB_GET_TARGET(ahd, scb)); tid_head = scbid; found += ahd_search_scb_list(ahd, target, channel, lun, tag, role, status, @@ -8365,14 +8361,14 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, switch (action) { case SEARCH_COMPLETE: if ((mk_msg_scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB pending MK_MSG\n"); + printk("Inactive SCB pending MK_MSG\n"); ahd_done_with_status(ahd, mk_msg_scb, status); /* FALLTHROUGH */ case SEARCH_REMOVE: { u_int tail_offset; - printf("Removing MK_MSG scb\n"); + printk("Removing MK_MSG scb\n"); /* * Reset our tail to the tail of the @@ -8390,7 +8386,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, break; } case SEARCH_PRINT: - printf(" 0x%x", SCB_GET_TAG(scb)); + printk(" 0x%x", SCB_GET_TAG(scb)); /* FALLTHROUGH */ case SEARCH_COUNT: break; @@ -8407,7 +8403,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, * queue with a pending MK_MESSAGE scb, we * must queue the MK_MESSAGE scb. */ - printf("Queueing mk_msg_scb\n"); + printk("Queueing mk_msg_scb\n"); tid_head = ahd_inw(ahd, MK_MESSAGE_SCB); seq_flags2 &= ~PENDING_MK_MESSAGE; ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); @@ -8418,7 +8414,7 @@ ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, if (!SCBID_IS_NULL(tid_head)) tid_prev = tid_head; if (action == SEARCH_PRINT) - printf(")\n"); + printk(")\n"); } /* Restore saved state. */ @@ -8446,7 +8442,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, *list_tail = SCB_LIST_NULL; for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) { if (scbid >= ahd->scb_data.numscbs) { - printf("%s:SCB List inconsistency. " + printk("%s:SCB List inconsistency. " "SCB == 0x%x, yet numscbs == 0x%x.", ahd_name(ahd), scbid, ahd->scb_data.numscbs); ahd_dump_card_state(ahd); @@ -8454,7 +8450,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, } scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: SCB = %d Not Active!\n", + printk("%s: SCB = %d Not Active!\n", ahd_name(ahd), scbid); panic("Waiting List traversal\n"); } @@ -8470,7 +8466,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, switch (action) { case SEARCH_COMPLETE: if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in Waiting List\n"); + printk("Inactive SCB in Waiting List\n"); ahd_done_with_status(ahd, scb, status); /* FALLTHROUGH */ case SEARCH_REMOVE: @@ -8480,7 +8476,7 @@ ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, *list_head = next; break; case SEARCH_PRINT: - printf("0x%x ", scbid); + printk("0x%x ", scbid); case SEARCH_COUNT: prev = scbid; break; @@ -8668,7 +8664,7 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP) ahd_freeze_scb(scbp); if ((scbp->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB on pending list\n"); + printk("Inactive SCB on pending list\n"); ahd_done(ahd, scbp); found++; } @@ -8725,7 +8721,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) * Check if the last bus reset is cleared */ if (ahd->flags & AHD_BUS_RESET_ACTIVE) { - printf("%s: bus reset still active\n", + printk("%s: bus reset still active\n", ahd_name(ahd)); return 0; } @@ -8900,7 +8896,7 @@ ahd_stat_timer(void *arg) ahd_enable_coalescing(ahd, enint_coal); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) - printf("%s: Interrupt coalescing " + printk("%s: Interrupt coalescing " "now %sabled. Cmds %d\n", ahd_name(ahd), (enint_coal & ENINT_COALESCE) ? "en" : "dis", @@ -8975,9 +8971,9 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_SENSE) != 0) { ahd_print_path(ahd, scb); - printf("SCB 0x%x Received PKT Status of 0x%x\n", + printk("SCB 0x%x Received PKT Status of 0x%x\n", SCB_GET_TAG(scb), siu->status); - printf("\tflags = 0x%x, sense len = 0x%x, " + printk("\tflags = 0x%x, sense len = 0x%x, " "pktfail = 0x%x\n", siu->flags, scsi_4btoul(siu->sense_length), scsi_4btoul(siu->pkt_failures_length)); @@ -8986,27 +8982,27 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) if ((siu->flags & SIU_RSPVALID) != 0) { ahd_print_path(ahd, scb); if (scsi_4btoul(siu->pkt_failures_length) < 4) { - printf("Unable to parse pkt_failures\n"); + printk("Unable to parse pkt_failures\n"); } else { switch (SIU_PKTFAIL_CODE(siu)) { case SIU_PFC_NONE: - printf("No packet failure found\n"); + printk("No packet failure found\n"); break; case SIU_PFC_CIU_FIELDS_INVALID: - printf("Invalid Command IU Field\n"); + printk("Invalid Command IU Field\n"); break; case SIU_PFC_TMF_NOT_SUPPORTED: - printf("TMF not supportd\n"); + printk("TMF not supportd\n"); break; case SIU_PFC_TMF_FAILED: - printf("TMF failed\n"); + printk("TMF failed\n"); break; case SIU_PFC_INVALID_TYPE_CODE: - printf("Invalid L_Q Type code\n"); + printk("Invalid L_Q Type code\n"); break; case SIU_PFC_ILLEGAL_REQUEST: - printf("Illegal request\n"); + printk("Illegal request\n"); default: break; } @@ -9019,7 +9015,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) scb->flags |= SCB_PKT_SENSE; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_SENSE) != 0) - printf("Sense data available\n"); + printk("Sense data available\n"); #endif } ahd_done(ahd, scb); @@ -9037,7 +9033,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_SENSE) { ahd_print_path(ahd, scb); - printf("SCB %d: requests Check Status\n", + printk("SCB %d: requests Check Status\n", SCB_GET_TAG(scb)); } #endif @@ -9065,7 +9061,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_SENSE) { ahd_print_path(ahd, scb); - printf("Sending Sense\n"); + printk("Sending Sense\n"); } #endif scb->sg_count = 0; @@ -9117,7 +9113,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) break; } case SCSI_STATUS_OK: - printf("%s: Interrupted for staus of 0???\n", + printk("%s: Interrupted for staus of 0???\n", ahd_name(ahd)); /* FALLTHROUGH */ default: @@ -9192,7 +9188,7 @@ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) return; } else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) { ahd_print_path(ahd, scb); - printf("data overrun detected Tag == 0x%x.\n", + printk("data overrun detected Tag == 0x%x.\n", SCB_GET_TAG(scb)); ahd_freeze_devq(ahd, scb); ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); @@ -9232,7 +9228,7 @@ ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) { ahd_print_path(ahd, scb); - printf("Handled %sResidual of %d bytes\n", + printk("Handled %sResidual of %d bytes\n", (scb->flags & SCB_SENSE) ? "Sense " : "", resid); } #endif @@ -9272,7 +9268,7 @@ ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) { xpt_print_path(lstate->path); - printf("immediate event %x:%x lost\n", + printk("immediate event %x:%x lost\n", lstate->event_buffer[lstate->event_r_idx].event_type, lstate->event_buffer[lstate->event_r_idx].event_arg); lstate->event_r_idx++; @@ -9344,7 +9340,7 @@ ahd_dumpseq(struct ahd_softc* ahd) uint8_t ins_bytes[4]; ahd_insb(ahd, SEQRAM, ins_bytes, 4); - printf("0x%08x\n", ins_bytes[0] << 24 + printk("0x%08x\n", ins_bytes[0] << 24 | ins_bytes[1] << 16 | ins_bytes[2] << 8 | ins_bytes[3]); @@ -9372,7 +9368,7 @@ ahd_loadseq(struct ahd_softc *ahd) uint8_t download_consts[DOWNLOAD_CONST_COUNT]; if (bootverbose) - printf("%s: Downloading Sequencer Program...", + printk("%s: Downloading Sequencer Program...", ahd_name(ahd)); #if DOWNLOAD_CONST_COUNT != 8 @@ -9498,7 +9494,7 @@ ahd_loadseq(struct ahd_softc *ahd) if (cs_count != 0) { cs_count *= sizeof(struct cs); - ahd->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); + ahd->critical_sections = kmalloc(cs_count, GFP_ATOMIC); if (ahd->critical_sections == NULL) panic("ahd_loadseq: Could not malloc"); memcpy(ahd->critical_sections, cs_table, cs_count); @@ -9506,8 +9502,8 @@ ahd_loadseq(struct ahd_softc *ahd) ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE); if (bootverbose) { - printf(" %d instructions downloaded\n", downloaded); - printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", + printk(" %d instructions downloaded\n", downloaded); + printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags); } } @@ -9690,12 +9686,12 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries, u_int printed_mask; if (cur_column != NULL && *cur_column >= wrap_point) { - printf("\n"); + printk("\n"); *cur_column = 0; } - printed = printf("%s[0x%x]", name, value); + printed = printk("%s[0x%x]", name, value); if (table == NULL) { - printed += printf(" "); + printed += printk(" "); *cur_column += printed; return (printed); } @@ -9710,7 +9706,7 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries, == table[entry].mask)) continue; - printed += printf("%s%s", + printed += printk("%s%s", printed_mask == 0 ? ":(" : "|", table[entry].name); printed_mask |= table[entry].mask; @@ -9721,9 +9717,9 @@ ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries, break; } if (printed_mask != 0) - printed += printf(") "); + printed += printk(") "); else - printed += printf(" "); + printed += printk(" "); if (cur_column != NULL) *cur_column += printed; return (printed); @@ -9749,17 +9745,17 @@ ahd_dump_card_state(struct ahd_softc *ahd) } saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" + printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" "%s: Dumping Card State at program address 0x%x Mode 0x%x\n", ahd_name(ahd), ahd_inw(ahd, CURADDR), ahd_build_mode_state(ahd, ahd->saved_src_mode, ahd->saved_dst_mode)); if (paused) - printf("Card was paused\n"); + printk("Card was paused\n"); if (ahd_check_cmdcmpltqueues(ahd)) - printf("Completions are pending\n"); + printk("Completions are pending\n"); /* * Mode independent registers. @@ -9801,8 +9797,8 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50); ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50); ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50); - printf("\n"); - printf("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x " + printk("\n"); + printk("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x " "CURRSCB 0x%x NEXTSCB 0x%x\n", ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING), ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB), @@ -9813,12 +9809,12 @@ ahd_dump_card_state(struct ahd_softc *ahd) CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT); saved_scb_index = ahd_get_scbptr(ahd); - printf("Pending list:"); + printk("Pending list:"); i = 0; LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { if (i++ > AHD_SCB_MAX) break; - cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), + cur_col = printk("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT)); ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL), @@ -9826,16 +9822,16 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID), &cur_col, 60); } - printf("\nTotal %d\n", i); + printk("\nTotal %d\n", i); - printf("Kernel Free SCB list: "); + printk("Kernel Free SCB list: "); i = 0; TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { struct scb *list_scb; list_scb = scb; do { - printf("%d ", SCB_GET_TAG(list_scb)); + printk("%d ", SCB_GET_TAG(list_scb)); list_scb = LIST_NEXT(list_scb, collision_links); } while (list_scb && i++ < AHD_SCB_MAX); } @@ -9843,49 +9839,49 @@ ahd_dump_card_state(struct ahd_softc *ahd) LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { if (i++ > AHD_SCB_MAX) break; - printf("%d ", SCB_GET_TAG(scb)); + printk("%d ", SCB_GET_TAG(scb)); } - printf("\n"); + printk("\n"); - printf("Sequencer Complete DMA-inprog list: "); + printk("Sequencer Complete DMA-inprog list: "); scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD); i = 0; while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); - printf("%d ", scb_index); + printk("%d ", scb_index); scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } - printf("\n"); + printk("\n"); - printf("Sequencer Complete list: "); + printk("Sequencer Complete list: "); scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD); i = 0; while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); - printf("%d ", scb_index); + printk("%d ", scb_index); scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } - printf("\n"); + printk("\n"); - printf("Sequencer DMA-Up and Complete list: "); + printk("Sequencer DMA-Up and Complete list: "); scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); i = 0; while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); - printf("%d ", scb_index); + printk("%d ", scb_index); scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } - printf("\n"); - printf("Sequencer On QFreeze and Complete list: "); + printk("\n"); + printk("Sequencer On QFreeze and Complete list: "); scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); i = 0; while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); - printf("%d ", scb_index); + printk("%d ", scb_index); scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } - printf("\n"); + printk("\n"); ahd_set_scbptr(ahd, saved_scb_index); dffstat = ahd_inb(ahd, DFFSTAT); for (i = 0; i < 2; i++) { @@ -9896,7 +9892,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); fifo_scbptr = ahd_get_scbptr(ahd); - printf("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n", + printk("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n", ahd_name(ahd), i, (dffstat & (FIFO0FREE << i)) ? "Free" : "Active", ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr); @@ -9912,20 +9908,20 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50); ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50); if (cur_col > 50) { - printf("\n"); + printk("\n"); cur_col = 0; } - cur_col += printf("SHADDR = 0x%x%x, SHCNT = 0x%x ", + cur_col += printk("SHADDR = 0x%x%x, SHCNT = 0x%x ", ahd_inl(ahd, SHADDR+4), ahd_inl(ahd, SHADDR), (ahd_inb(ahd, SHCNT) | (ahd_inb(ahd, SHCNT + 1) << 8) | (ahd_inb(ahd, SHCNT + 2) << 16))); if (cur_col > 50) { - printf("\n"); + printk("\n"); cur_col = 0; } - cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ", + cur_col += printk("HADDR = 0x%x%x, HCNT = 0x%x ", ahd_inl(ahd, HADDR+4), ahd_inl(ahd, HADDR), (ahd_inb(ahd, HCNT) @@ -9940,52 +9936,52 @@ ahd_dump_card_state(struct ahd_softc *ahd) } #endif } - printf("\nLQIN: "); + printk("\nLQIN: "); for (i = 0; i < 20; i++) - printf("0x%x ", ahd_inb(ahd, LQIN + i)); - printf("\n"); + printk("0x%x ", ahd_inb(ahd, LQIN + i)); + printk("\n"); ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - printf("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n", + printk("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n", ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE), ahd_inb(ahd, OPTIONMODE)); - printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", + printk("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT), ahd_inb(ahd, MAXCMDCNT)); - printf("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n", + printk("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n", ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN)); ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50); - printf("\n"); + printk("\n"); ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); cur_col = 0; ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50); - printf("\n"); + printk("\n"); ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); - printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", + printk("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), ahd_inw(ahd, DINDEX)); - printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", + printk("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", ahd_name(ahd), ahd_get_scbptr(ahd), ahd_inw_scbram(ahd, SCB_NEXT), ahd_inw_scbram(ahd, SCB_NEXT2)); - printf("CDB %x %x %x %x %x %x\n", + printk("CDB %x %x %x %x %x %x\n", ahd_inb_scbram(ahd, SCB_CDB_STORE), ahd_inb_scbram(ahd, SCB_CDB_STORE+1), ahd_inb_scbram(ahd, SCB_CDB_STORE+2), ahd_inb_scbram(ahd, SCB_CDB_STORE+3), ahd_inb_scbram(ahd, SCB_CDB_STORE+4), ahd_inb_scbram(ahd, SCB_CDB_STORE+5)); - printf("STACK:"); + printk("STACK:"); for (i = 0; i < ahd->stack_size; i++) { ahd->saved_stack[i] = ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8); - printf(" 0x%x", ahd->saved_stack[i]); + printk(" 0x%x", ahd->saved_stack[i]); } for (i = ahd->stack_size-1; i >= 0; i--) { ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF); ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); } - printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); + printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); ahd_restore_modes(ahd, saved_modes); if (paused == 0) ahd_unpause(ahd); @@ -10004,8 +10000,8 @@ ahd_dump_scbs(struct ahd_softc *ahd) saved_scb_index = ahd_get_scbptr(ahd); for (i = 0; i < AHD_SCB_MAX; i++) { ahd_set_scbptr(ahd, i); - printf("%3d", i); - printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", + printk("%3d", i); + printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb_scbram(ahd, SCB_SCSIID), ahd_inw_scbram(ahd, SCB_NEXT), @@ -10013,7 +10009,7 @@ ahd_dump_scbs(struct ahd_softc *ahd) ahd_inl_scbram(ahd, SCB_SGPTR), ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR)); } - printf("\n"); + printk("\n"); ahd_set_scbptr(ahd, saved_scb_index); ahd_restore_modes(ahd, saved_modes); } @@ -10383,7 +10379,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { u_long s; - printf("Configuring Target Mode\n"); + printk("Configuring Target Mode\n"); ahd_lock(ahd, &s); if (LIST_FIRST(&ahd->pending_scbs) != NULL) { ccb->ccb_h.status = CAM_BUSY; @@ -10412,7 +10408,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) /* Are we already enabled?? */ if (lstate != NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Lun already enabled\n"); + printk("Lun already enabled\n"); ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; return; } @@ -10424,7 +10420,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) * specific commands. */ ccb->ccb_h.status = CAM_REQ_INVALID; - printf("Non-zero Group Codes\n"); + printk("Non-zero Group Codes\n"); return; } @@ -10436,15 +10432,15 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) tstate = ahd_alloc_tstate(ahd, target, channel); if (tstate == NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate tstate\n"); + printk("Couldn't allocate tstate\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } } - lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); + lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC); if (lstate == NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate lstate\n"); + printk("Couldn't allocate lstate\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } @@ -10454,9 +10450,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) xpt_path_target_id(ccb->ccb_h.path), xpt_path_lun_id(ccb->ccb_h.path)); if (status != CAM_REQ_CMP) { - free(lstate, M_DEVBUF); + kfree(lstate); xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate path\n"); + printk("Couldn't allocate path\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } @@ -10524,7 +10520,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) ahd_unlock(ahd, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); - printf("Lun now enabled for target mode\n"); + printk("Lun now enabled for target mode\n"); } else { struct scb *scb; int i, empty; @@ -10543,7 +10539,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) ccbh = &scb->io_ctx->ccb_h; if (ccbh->func_code == XPT_CONT_TARGET_IO && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ - printf("CTIO pending\n"); + printk("CTIO pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; ahd_unlock(ahd, &s); return; @@ -10551,12 +10547,12 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) } if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printf("ATIOs pending\n"); + printk("ATIOs pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; } if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printf("INOTs pending\n"); + printk("INOTs pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; } @@ -10566,9 +10562,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) } xpt_print_path(ccb->ccb_h.path); - printf("Target mode disabled\n"); + printk("Target mode disabled\n"); xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); + kfree(lstate); ahd_pause(ahd); /* Can we clean up the target too? */ @@ -10615,7 +10611,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) ahd_outb(ahd, SCSISEQ1, scsiseq1); if ((ahd->features & AHD_MULTIROLE) == 0) { - printf("Configuring Initiator Mode\n"); + printk("Configuring Initiator Mode\n"); ahd->flags &= ~AHD_TARGETROLE; ahd->flags |= AHD_INITIATORROLE; ahd_pause(ahd); @@ -10749,7 +10745,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) ahd->flags &= ~AHD_TQINFIFO_BLOCKED; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_TQIN) != 0) - printf("Incoming command from %d for %d:%d%s\n", + printk("Incoming command from %d for %d:%d%s\n", initiator, target, lun, lstate == ahd->black_hole ? "(Black Holed)" : ""); #endif @@ -10796,7 +10792,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) default: /* Only copy the opcode. */ atio->cdb_len = 1; - printf("Reserved or VU command code type encountered\n"); + printk("Reserved or VU command code type encountered\n"); break; } @@ -10813,7 +10809,7 @@ ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_TQIN) != 0) - printf("Received Immediate Command %d:%d:%d - %p\n", + printk("Received Immediate Command %d:%d:%d - %p\n", initiator, target, lun, ahd->pending_device); #endif ahd->pending_device = lstate; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 4c41332a354..88ad8482ef5 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -674,7 +674,7 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) struct ahd_linux_device *dev; if (bootverbose) - printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); + printk("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -798,10 +798,10 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd) scmd_printk(KERN_INFO, cmd, "Attempting to queue a TARGET RESET message:"); - printf("CDB:"); + printk("CDB:"); for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printf(" 0x%x", cmd->cmnd[cdb_byte]); - printf("\n"); + printk(" 0x%x", cmd->cmnd[cdb_byte]); + printk("\n"); /* * Determine if we currently own this command. @@ -857,16 +857,16 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd) ahd->platform_data->eh_done = &done; ahd_unlock(ahd, &flags); - printf("%s: Device reset code sleeping\n", ahd_name(ahd)); + printk("%s: Device reset code sleeping\n", ahd_name(ahd)); if (!wait_for_completion_timeout(&done, 5 * HZ)) { ahd_lock(ahd, &flags); ahd->platform_data->eh_done = NULL; ahd_unlock(ahd, &flags); - printf("%s: Device reset timer expired (active %d)\n", + printk("%s: Device reset timer expired (active %d)\n", ahd_name(ahd), dev->active); retval = FAILED; } - printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); + printk("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); return (retval); } @@ -884,7 +884,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) ahd = *(struct ahd_softc **)cmd->device->host->hostdata; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s: Bus reset called for cmd %p\n", + printk("%s: Bus reset called for cmd %p\n", ahd_name(ahd), cmd); #endif ahd_lock(ahd, &flags); @@ -894,7 +894,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) ahd_unlock(ahd, &flags); if (bootverbose) - printf("%s: SCSI bus reset delivered. " + printk("%s: SCSI bus reset delivered. " "%d SCBs aborted.\n", ahd_name(ahd), found); return (SUCCESS); @@ -935,7 +935,7 @@ ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, { bus_dma_tag_t dmat; - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); if (dmat == NULL) return (ENOMEM); @@ -956,7 +956,7 @@ ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, void ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat) { - free(dmat, M_DEVBUF); + kfree(dmat); } int @@ -1019,7 +1019,7 @@ ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; iocell_info[index] = value & 0xFFFF; if (bootverbose) - printf("iocell[%d:%ld] = %d\n", instance, index, value); + printk("iocell[%d:%ld] = %d\n", instance, index, value); } } @@ -1029,7 +1029,7 @@ ahd_linux_setup_tag_info_global(char *p) int tags, i, j; tags = simple_strtoul(p + 1, NULL, 0) & 0xff; - printf("Setting Global Tags= %d\n", tags); + printk("Setting Global Tags= %d\n", tags); for (i = 0; i < ARRAY_SIZE(aic79xx_tag_info); i++) { for (j = 0; j < AHD_NUM_TARGETS; j++) { @@ -1047,7 +1047,7 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) && (targ < AHD_NUM_TARGETS)) { aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; if (bootverbose) - printf("tag_info[%d:%d] = %d\n", instance, targ, value); + printk("tag_info[%d:%d] = %d\n", instance, targ, value); } } @@ -1088,7 +1088,7 @@ ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, if (targ == -1) targ = 0; } else { - printf("Malformed Option %s\n", + printk("Malformed Option %s\n", opt_name); done = TRUE; } @@ -1246,7 +1246,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa ahd_set_unit(ahd, ahd_linux_unit++); ahd_unlock(ahd, &s); sprintf(buf, "scsi%d", host->host_no); - new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); if (new_name != NULL) { strcpy(new_name, buf); ahd_set_name(ahd, new_name); @@ -1322,7 +1322,7 @@ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) { ahd->platform_data = - malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT); + kmalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC); if (ahd->platform_data == NULL) return (ENOMEM); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); @@ -1364,7 +1364,7 @@ ahd_platform_free(struct ahd_softc *ahd) if (ahd->platform_data->host) scsi_host_put(ahd->platform_data->host); - free(ahd->platform_data, M_DEVBUF); + kfree(ahd->platform_data); } } @@ -1502,7 +1502,7 @@ ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) if (ahd->unit >= ARRAY_SIZE(aic79xx_tag_info)) { if (warned_user == 0) { - printf(KERN_WARNING + printk(KERN_WARNING "aic79xx: WARNING: Insufficient tag_info instances\n" "aic79xx: for installed controllers. Using defaults\n" "aic79xx: Please update the aic79xx_tag_info array in\n" @@ -1544,7 +1544,7 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) ahd_send_async(ahd, devinfo.channel, devinfo.target, devinfo.lun, AC_TRANSFER_NEG); ahd_print_devinfo(ahd, &devinfo); - printf("Tagged Queuing enabled. Depth %d\n", tags); + printk("Tagged Queuing enabled. Depth %d\n", tags); } else { ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE); ahd_send_async(ahd, devinfo.channel, devinfo.target, @@ -1794,7 +1794,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) struct ahd_linux_device *dev; if ((scb->flags & SCB_ACTIVE) == 0) { - printf("SCB %d done'd twice\n", SCB_GET_TAG(scb)); + printk("SCB %d done'd twice\n", SCB_GET_TAG(scb)); ahd_dump_card_state(ahd); panic("Stopping for safety"); } @@ -1825,7 +1825,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) { ahd_print_path(ahd, scb); - printf("Set CAM_UNCOR_PARITY\n"); + printk("Set CAM_UNCOR_PARITY\n"); } #endif ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); @@ -1843,12 +1843,12 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) u_int i; ahd_print_path(ahd, scb); - printf("CDB:"); + printk("CDB:"); for (i = 0; i < scb->io_ctx->cmd_len; i++) - printf(" 0x%x", scb->io_ctx->cmnd[i]); - printf("\n"); + printk(" 0x%x", scb->io_ctx->cmnd[i]); + printk("\n"); ahd_print_path(ahd, scb); - printf("Saw underflow (%ld of %ld bytes). " + printk("Saw underflow (%ld of %ld bytes). " "Treated as error\n", ahd_get_residual(scb), ahd_get_transfer_length(scb)); @@ -1881,7 +1881,7 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) dev->commands_since_idle_or_otag = 0; if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printf("Recovery SCB completes\n"); + printk("Recovery SCB completes\n"); if (ahd_get_transaction_status(scb) == CAM_BDR_SENT || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); @@ -1963,14 +1963,14 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, if (ahd_debug & AHD_SHOW_SENSE) { int i; - printf("Copied %d bytes of sense data at %d:", + printk("Copied %d bytes of sense data at %d:", sense_size, sense_offset); for (i = 0; i < sense_size; i++) { if ((i & 0xF) == 0) - printf("\n"); - printf("0x%x ", cmd->sense_buffer[i]); + printk("\n"); + printk("0x%x ", cmd->sense_buffer[i]); } - printf("\n"); + printk("\n"); } #endif } @@ -1995,7 +1995,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_QFULL) != 0) { ahd_print_path(ahd, scb); - printf("Dropping tag count to %d\n", + printk("Dropping tag count to %d\n", dev->active); } #endif @@ -2014,7 +2014,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, == AHD_LOCK_TAGS_COUNT) { dev->maxtags = dev->active; ahd_print_path(ahd, scb); - printf("Locking max tag count at %d\n", + printk("Locking max tag count at %d\n", dev->active); } } else { @@ -2138,7 +2138,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) } if (do_fallback) { - printf("%s: device overrun (status %x) on %d:%d:%d\n", + printk("%s: device overrun (status %x) on %d:%d:%d\n", ahd_name(ahd), status, cmd->device->channel, cmd->device->id, cmd->device->lun); } @@ -2187,10 +2187,10 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) scmd_printk(KERN_INFO, cmd, "Attempting to queue an ABORT message:"); - printf("CDB:"); + printk("CDB:"); for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printf(" 0x%x", cmd->cmnd[cdb_byte]); - printf("\n"); + printk(" 0x%x", cmd->cmnd[cdb_byte]); + printk("\n"); ahd_lock(ahd, &flags); @@ -2249,7 +2249,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) goto no_cmd; } - printf("%s: At time of recovery, card was %spaused\n", + printk("%s: At time of recovery, card was %spaused\n", ahd_name(ahd), was_paused ? "" : "not "); ahd_dump_card_state(ahd); @@ -2260,7 +2260,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) pending_scb->hscb->tag, ROLE_INITIATOR, CAM_REQ_ABORTED, SEARCH_COMPLETE) > 0) { - printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun); retval = SUCCESS; @@ -2355,7 +2355,7 @@ ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) ahd_qinfifo_requeue_tail(ahd, pending_scb); ahd_set_scbptr(ahd, saved_scbptr); ahd_print_path(ahd, pending_scb); - printf("Device is disconnected, re-queuing SCB\n"); + printk("Device is disconnected, re-queuing SCB\n"); wait = TRUE; } else { scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n"); @@ -2380,21 +2380,21 @@ done: ahd->platform_data->eh_done = &done; ahd_unlock(ahd, &flags); - printf("%s: Recovery code sleeping\n", ahd_name(ahd)); + printk("%s: Recovery code sleeping\n", ahd_name(ahd)); if (!wait_for_completion_timeout(&done, 5 * HZ)) { ahd_lock(ahd, &flags); ahd->platform_data->eh_done = NULL; ahd_unlock(ahd, &flags); - printf("%s: Timer Expired (active %d)\n", + printk("%s: Timer Expired (active %d)\n", ahd_name(ahd), dev->active); retval = FAILED; } - printf("Recovery code awake\n"); + printk("Recovery code awake\n"); } else ahd_unlock(ahd, &flags); if (retval != SUCCESS) - printf("%s: Command abort returning 0x%x\n", + printk("%s: Command abort returning 0x%x\n", ahd_name(ahd), retval); return retval; @@ -2431,7 +2431,7 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: set period to %d\n", ahd_name(ahd), period); + printk("%s: set period to %d\n", ahd_name(ahd), period); #endif if (offset == 0) offset = MAX_OFFSET; @@ -2484,7 +2484,7 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: set offset to %d\n", ahd_name(ahd), offset); + printk("%s: set offset to %d\n", ahd_name(ahd), offset); #endif ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, @@ -2520,7 +2520,7 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s DT\n", ahd_name(ahd), + printk("%s: %s DT\n", ahd_name(ahd), dt ? "enabling" : "disabling"); #endif if (dt && spi_max_width(starget)) { @@ -2562,7 +2562,7 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s QAS\n", ahd_name(ahd), + printk("%s: %s QAS\n", ahd_name(ahd), qas ? "enabling" : "disabling"); #endif @@ -2601,7 +2601,7 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s IU\n", ahd_name(ahd), + printk("%s: %s IU\n", ahd_name(ahd), iu ? "enabling" : "disabling"); #endif @@ -2641,7 +2641,7 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s Read Streaming\n", ahd_name(ahd), + printk("%s: %s Read Streaming\n", ahd_name(ahd), rdstrm ? "enabling" : "disabling"); #endif @@ -2677,7 +2677,7 @@ static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s Write Flow Control\n", ahd_name(ahd), + printk("%s: %s Write Flow Control\n", ahd_name(ahd), wrflow ? "enabling" : "disabling"); #endif @@ -2714,14 +2714,14 @@ static void ahd_linux_set_rti(struct scsi_target *starget, int rti) if ((ahd->features & AHD_RTI) == 0) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: RTI not available\n", ahd_name(ahd)); + printk("%s: RTI not available\n", ahd_name(ahd)); #endif return; } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s RTI\n", ahd_name(ahd), + printk("%s: %s RTI\n", ahd_name(ahd), rti ? "enabling" : "disabling"); #endif @@ -2757,7 +2757,7 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_DV) != 0) - printf("%s: %s Precompensation\n", ahd_name(ahd), + printk("%s: %s Precompensation\n", ahd_name(ahd), pcomp ? "Enable" : "Disable"); #endif diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 55c1fe07969..28e43498cdf 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -363,13 +363,6 @@ struct ahd_platform_data { resource_size_t mem_busaddr; /* Mem Base Addr */ }; -/************************** OS Utility Wrappers *******************************/ -#define printf printk -#define M_NOWAIT GFP_ATOMIC -#define M_WAITOK 0 -#define malloc(size, type, flags) kmalloc(size, flags) -#define free(ptr, type) kfree(ptr) - void ahd_delay(long); /***************************** Low Level I/O **********************************/ diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 8f686122d54..3c85873b14b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -178,7 +178,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahd_get_pci_bus(pci), ahd_get_pci_slot(pci), ahd_get_pci_function(pci)); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); if (name == NULL) return (-ENOMEM); strcpy(name, buf); @@ -333,7 +333,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd) if (ahd_pci_test_register_access(ahd) != 0) { - printf("aic79xx: PCI Device %d:%d:%d " + printk("aic79xx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), @@ -346,7 +346,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd) } else command |= PCIM_CMD_MEMEN; } else if (bootverbose) { - printf("aic79xx: PCI%d:%d:%d MEM region 0x%llx " + printk("aic79xx: PCI%d:%d:%d MEM region 0x%llx " "unavailable. Cannot memory map device.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), @@ -365,7 +365,7 @@ ahd_pci_map_registers(struct ahd_softc *ahd) ahd->bshs[1].ioport = (u_long)base2; command |= PCIM_CMD_PORTEN; } else { - printf("aic79xx: PCI%d:%d:%d IO regions 0x%llx and " + printk("aic79xx: PCI%d:%d:%d IO regions 0x%llx and " "0x%llx unavailable. Cannot map device.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 90a04a37b4f..14b5f8d0e7f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -338,7 +338,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) */ if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { if (bootverbose) - printf("%s: Enabling 39Bit Addressing\n", + printk("%s: Enabling 39Bit Addressing\n", ahd_name(ahd)); devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); @@ -528,7 +528,7 @@ ahd_check_extport(struct ahd_softc *ahd) * Fetch VPD for this function and parse it. */ if (bootverbose) - printf("%s: Reading VPD from SEEPROM...", + printk("%s: Reading VPD from SEEPROM...", ahd_name(ahd)); /* Address is always in units of 16bit words */ @@ -541,12 +541,12 @@ ahd_check_extport(struct ahd_softc *ahd) if (error == 0) error = ahd_parse_vpddata(ahd, &vpd); if (bootverbose) - printf("%s: VPD parsing %s\n", + printk("%s: VPD parsing %s\n", ahd_name(ahd), error == 0 ? "successful" : "failed"); if (bootverbose) - printf("%s: Reading SEEPROM...", ahd_name(ahd)); + printk("%s: Reading SEEPROM...", ahd_name(ahd)); /* Address is always in units of 16bit words */ start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A'); @@ -556,16 +556,16 @@ ahd_check_extport(struct ahd_softc *ahd) /*bytestream*/FALSE); if (error != 0) { - printf("Unable to read SEEPROM\n"); + printk("Unable to read SEEPROM\n"); have_seeprom = 0; } else { have_seeprom = ahd_verify_cksum(sc); if (bootverbose) { if (have_seeprom == 0) - printf ("checksum error\n"); + printk ("checksum error\n"); else - printf ("done.\n"); + printk ("done.\n"); } } ahd_release_seeprom(ahd); @@ -615,21 +615,21 @@ ahd_check_extport(struct ahd_softc *ahd) uint16_t *sc_data; int i; - printf("%s: Seeprom Contents:", ahd_name(ahd)); + printk("%s: Seeprom Contents:", ahd_name(ahd)); sc_data = (uint16_t *)sc; for (i = 0; i < (sizeof(*sc)); i += 2) - printf("\n\t0x%.4x", sc_data[i]); - printf("\n"); + printk("\n\t0x%.4x", sc_data[i]); + printk("\n"); } #endif if (!have_seeprom) { if (bootverbose) - printf("%s: No SEEPROM available.\n", ahd_name(ahd)); + printk("%s: No SEEPROM available.\n", ahd_name(ahd)); ahd->flags |= AHD_USEDEFAULTS; error = ahd_default_config(ahd); adapter_control = CFAUTOTERM|CFSEAUTOTERM; - free(ahd->seep_config, M_DEVBUF); + kfree(ahd->seep_config); ahd->seep_config = NULL; } else { error = ahd_parse_cfgdata(ahd, sc); @@ -656,7 +656,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) if ((ahd->flags & AHD_STPWLEVEL_A) != 0) devconfig |= STPWLEVEL; if (bootverbose) - printf("%s: STPWLEVEL is %s\n", + printk("%s: STPWLEVEL is %s\n", ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off"); ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); @@ -671,7 +671,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl); if ((adapter_control & CFAUTOTERM) == 0) { if (bootverbose) - printf("%s: Manual Primary Termination\n", + printk("%s: Manual Primary Termination\n", ahd_name(ahd)); termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH); if ((adapter_control & CFSTERM) != 0) @@ -679,14 +679,14 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) if ((adapter_control & CFWSTERM) != 0) termctl |= FLX_TERMCTL_ENPRIHIGH; } else if (error != 0) { - printf("%s: Primary Auto-Term Sensing failed! " + printk("%s: Primary Auto-Term Sensing failed! " "Using Defaults.\n", ahd_name(ahd)); termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH; } if ((adapter_control & CFSEAUTOTERM) == 0) { if (bootverbose) - printf("%s: Manual Secondary Termination\n", + printk("%s: Manual Secondary Termination\n", ahd_name(ahd)); termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH); if ((adapter_control & CFSELOWTERM) != 0) @@ -694,7 +694,7 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) if ((adapter_control & CFSEHIGHTERM) != 0) termctl |= FLX_TERMCTL_ENSECHIGH; } else if (error != 0) { - printf("%s: Secondary Auto-Term Sensing failed! " + printk("%s: Secondary Auto-Term Sensing failed! " "Using Defaults.\n", ahd_name(ahd)); termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH; } @@ -714,22 +714,22 @@ ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl); if (error != 0) { - printf("%s: Unable to set termination settings!\n", + printk("%s: Unable to set termination settings!\n", ahd_name(ahd)); } else if (bootverbose) { - printf("%s: Primary High byte termination %sabled\n", + printk("%s: Primary High byte termination %sabled\n", ahd_name(ahd), (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis"); - printf("%s: Primary Low byte termination %sabled\n", + printk("%s: Primary Low byte termination %sabled\n", ahd_name(ahd), (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis"); - printf("%s: Secondary High byte termination %sabled\n", + printk("%s: Secondary High byte termination %sabled\n", ahd_name(ahd), (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis"); - printf("%s: Secondary Low byte termination %sabled\n", + printk("%s: Secondary Low byte termination %sabled\n", ahd_name(ahd), (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis"); } @@ -805,7 +805,7 @@ ahd_pci_intr(struct ahd_softc *ahd) if ((intstat & PCIINT) == 0) return; - printf("%s: PCI error Interrupt\n", ahd_name(ahd)); + printk("%s: PCI error Interrupt\n", ahd_name(ahd)); saved_modes = ahd_save_modes(ahd); ahd_dump_card_state(ahd); ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); @@ -832,7 +832,7 @@ ahd_pci_intr(struct ahd_softc *ahd) s = pci_status_strings[bit]; if (i == 7/*TARG*/ && bit == 3) s = "%s: Signaled Target Abort\n"; - printf(s, ahd_name(ahd), pci_status_source[i]); + printk(s, ahd_name(ahd), pci_status_source[i]); } } } @@ -862,7 +862,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) */ pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS, /*bytes*/2); - printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n", + printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n", ahd_name(ahd), pcix_status); saved_modes = ahd_save_modes(ahd); for (i = 0; i < 4; i++) { @@ -891,7 +891,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) static const char *s; s = split_status_strings[bit]; - printf(s, ahd_name(ahd), + printk(s, ahd_name(ahd), split_status_source[i]); } @@ -902,7 +902,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) static const char *s; s = split_status_strings[bit]; - printf(s, ahd_name(ahd), "SG"); + printk(s, ahd_name(ahd), "SG"); } } } @@ -950,7 +950,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd) pci = ahd->dev_softc; rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev < ID_AIC7902_PCI_REV_A4) { - printf("%s: Unable to attach to unsupported chip revision %d\n", + printk("%s: Unable to attach to unsupported chip revision %d\n", ahd_name(ahd), rev); ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); return (ENXIO); diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 014bed716e7..59c85d5a153 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -272,33 +272,32 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); if (length != sizeof(struct seeprom_config)) { - printf("ahd_proc_write_seeprom: incorrect buffer size\n"); + printk("ahd_proc_write_seeprom: incorrect buffer size\n"); goto done; } have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer); if (have_seeprom == 0) { - printf("ahd_proc_write_seeprom: cksum verification failed\n"); + printk("ahd_proc_write_seeprom: cksum verification failed\n"); goto done; } have_seeprom = ahd_acquire_seeprom(ahd); if (!have_seeprom) { - printf("ahd_proc_write_seeprom: No Serial EEPROM\n"); + printk("ahd_proc_write_seeprom: No Serial EEPROM\n"); goto done; } else { u_int start_addr; if (ahd->seep_config == NULL) { - ahd->seep_config = malloc(sizeof(*ahd->seep_config), - M_DEVBUF, M_NOWAIT); + ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); if (ahd->seep_config == NULL) { - printf("aic79xx: Unable to allocate serial " + printk("aic79xx: Unable to allocate serial " "eeprom buffer. Write failing\n"); goto done; } } - printf("aic79xx: Writing Serial EEPROM\n"); + printk("aic79xx: Writing Serial EEPROM\n"); start_addr = 32 * (ahd->channel - 'A'); ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr, sizeof(struct seeprom_config)/2); diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c index dd11999b77b..9e85a7ef9c8 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c +++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c @@ -207,14 +207,14 @@ ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, reset_seeprom(sd); } #ifdef AHC_DUMP_EEPROM - printf("\nSerial EEPROM:\n\t"); + printk("\nSerial EEPROM:\n\t"); for (k = 0; k < count; k = k + 1) { if (((k % 8) == 0) && (k != 0)) { - printf ("\n\t"); + printk(KERN_CONT "\n\t"); } - printf (" 0x%x", buf[k]); + printk(KERN_CONT " 0x%x", buf[k]); } - printf ("\n"); + printk(KERN_CONT "\n"); #endif return (1); } @@ -240,7 +240,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, ewen = &seeprom_long_ewen; ewds = &seeprom_long_ewds; } else { - printf("ahc_write_seeprom: unsupported seeprom type %d\n", + printk("ahc_write_seeprom: unsupported seeprom type %d\n", sd->sd_chip); return (0); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 45aa728a76b..3f5a542a779 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -910,7 +910,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) scb = ahc_lookup_scb(ahc, scb_index); if (scb == NULL) { - printf("%s: WARNING no command for scb %d " + printk("%s: WARNING no command for scb %d " "(cmdcmplt)\nQOUTPOS = %d\n", ahc_name(ahc), scb_index, (ahc->qoutfifonext - 1) & 0xFF); @@ -964,7 +964,7 @@ ahc_handle_brkadrint(struct ahc_softc *ahc) error = ahc_inb(ahc, ERROR); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; - printf("%s: brkadrint, %s at seqaddr = 0x%x\n", + printk("%s: brkadrint, %s at seqaddr = 0x%x\n", ahc_name(ahc), ahc_hard_errors[i].errmesg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); @@ -1021,7 +1021,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) scb = ahc_lookup_scb(ahc, scb_index); if (scb == NULL) { ahc_print_devinfo(ahc, &devinfo); - printf("ahc_intr - referenced scb " + printk("ahc_intr - referenced scb " "not valid during seqint 0x%x scb(%d)\n", intstat, scb_index); ahc_dump_card_state(ahc); @@ -1049,7 +1049,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); switch (hscb->shared_data.status.scsi_status) { case SCSI_STATUS_OK: - printf("%s: Interrupted for staus of 0???\n", + printk("%s: Interrupted for staus of 0???\n", ahc_name(ahc)); break; case SCSI_STATUS_CMD_TERMINATED: @@ -1063,7 +1063,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_SENSE) { ahc_print_path(ahc, scb); - printf("SCB %d: requests Check Status\n", + printk("SCB %d: requests Check Status\n", scb->hscb->tag); } #endif @@ -1086,7 +1086,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_SENSE) { ahc_print_path(ahc, scb); - printf("Sending Sense\n"); + printk("Sending Sense\n"); } #endif sg->addr = ahc_get_sense_bufaddr(ahc, scb); @@ -1162,29 +1162,29 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - printf("%s:%c:%d: no active SCB for reconnecting " + printk("%s:%c:%d: no active SCB for reconnecting " "target - issuing BUS DEVICE RESET\n", ahc_name(ahc), devinfo.channel, devinfo.target); - printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " "ARG_1 == 0x%x ACCUM = 0x%x\n", ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " "SINDEX == 0x%x\n", ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), ahc_index_busy_tcl(ahc, BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN))), ahc_inb(ahc, SINDEX)); - printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), ahc_inb(ahc, SCB_CONTROL)); - printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); - printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); - printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); + printk("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); + printk("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); ahc_dump_card_state(ahc); ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; ahc->msgout_len = 1; @@ -1197,7 +1197,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) case SEND_REJECT: { u_int rejbyte = ahc_inb(ahc, ACCUM); - printf("%s:%c:%d: Warning - unknown message received from " + printk("%s:%c:%d: Warning - unknown message received from " "target (0x%x). Rejecting\n", ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); break; @@ -1218,7 +1218,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int lastphase; lastphase = ahc_inb(ahc, LASTPHASE); - printf("%s:%c:%d: unknown scsi bus phase %x, " + printk("%s:%c:%d: unknown scsi bus phase %x, " "lastphase = 0x%x. Attempting to continue\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); @@ -1229,7 +1229,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int lastphase; lastphase = ahc_inb(ahc, LASTPHASE); - printf("%s:%c:%d: Missed busfree. " + printk("%s:%c:%d: Missed busfree. " "Lastphase = 0x%x, Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, lastphase, ahc_inb(ahc, SCSISIGI)); @@ -1257,7 +1257,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; if (bus_phase != P_MESGIN && bus_phase != P_MESGOUT) { - printf("ahc_intr: HOST_MSG_LOOP bad " + printk("ahc_intr: HOST_MSG_LOOP bad " "phase 0x%x\n", bus_phase); /* @@ -1359,7 +1359,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int scb_index; ahc_print_devinfo(ahc, &devinfo); - printf("Unable to clear parity error. " + printk("Unable to clear parity error. " "Resetting bus.\n"); scb_index = ahc_inb(ahc, SCB_TAG); scb = ahc_lookup_scb(ahc, scb_index); @@ -1395,18 +1395,18 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) break; } ahc_print_path(ahc, scb); - printf("data overrun detected %s." + printk("data overrun detected %s." " Tag == 0x%x.\n", ahc_phase_table[i].phasemsg, scb->hscb->tag); ahc_print_path(ahc, scb); - printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", + printk("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", ahc_get_transfer_length(scb), scb->sg_count); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x%x : Length %d\n", + printk("sg[%d] - Addr 0x%x%x : Length %d\n", i, (ahc_le32toh(scb->sg_list[i].len) >> 24 & SG_HIGH_ADDR_BITS), @@ -1453,7 +1453,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) { u_int scbindex; - printf("%s:%c:%d:%d: Attempt to issue message failed\n", + printk("%s:%c:%d:%d: Attempt to issue message failed\n", ahc_name(ahc), devinfo.channel, devinfo.target, devinfo.lun); scbindex = ahc_inb(ahc, SCB_TAG); @@ -1473,7 +1473,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) } case NO_FREE_SCB: { - printf("%s: No free or disconnected SCBs\n", ahc_name(ahc)); + printk("%s: No free or disconnected SCBs\n", ahc_name(ahc)); ahc_dump_card_state(ahc); panic("for safety"); break; @@ -1483,7 +1483,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int scbptr; scbptr = ahc_inb(ahc, SCBPTR); - printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", + printk("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", scbptr, ahc_inb(ahc, ARG_1), ahc->scb_data->hscbs[scbptr].tag); ahc_dump_card_state(ahc); @@ -1492,12 +1492,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) } case OUT_OF_RANGE: { - printf("%s: BTT calculation out of range\n", ahc_name(ahc)); - printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + printk("%s: BTT calculation out of range\n", ahc_name(ahc)); + printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " "ARG_1 == 0x%x ACCUM = 0x%x\n", ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " "SINDEX == 0x%x\n, A == 0x%x\n", ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), ahc_index_busy_tcl(ahc, @@ -1505,19 +1505,19 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) ahc_inb(ahc, SAVED_LUN))), ahc_inb(ahc, SINDEX), ahc_inb(ahc, ACCUM)); - printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), ahc_inb(ahc, SCB_CONTROL)); - printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", + printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); ahc_dump_card_state(ahc); panic("for safety"); break; } default: - printf("ahc_intr: seqint, " + printk("ahc_intr: seqint, " "intstat == 0x%x, scsisigi = 0x%x\n", intstat, ahc_inb(ahc, SCSISIGI)); break; @@ -1562,7 +1562,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) intr_channel = (cur_channel == 'A') ? 'B' : 'A'; } if (status == 0) { - printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); + printk("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_unpause(ahc); return; @@ -1583,7 +1583,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) int now_lvd; now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40; - printf("%s: Transceiver State Has Changed to %s mode\n", + printk("%s: Transceiver State Has Changed to %s mode\n", ahc_name(ahc), now_lvd ? "LVD" : "SE"); ahc_outb(ahc, CLRSINT0, CLRIOERR); /* @@ -1599,7 +1599,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/now_lvd == 0); } else if ((status & SCSIRSTI) != 0) { - printf("%s: Someone reset channel %c\n", + printk("%s: Someone reset channel %c\n", ahc_name(ahc), intr_channel); if (intr_channel != cur_channel) ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); @@ -1659,26 +1659,26 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_print_path(ahc, scb); scb->flags |= SCB_TRANSMISSION_ERROR; } else - printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, + printk("%s:%c:%d: ", ahc_name(ahc), intr_channel, SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); scsirate = ahc_inb(ahc, SCSIRATE); if (silent == FALSE) { - printf("parity error detected %s. " + printk("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", ahc_phase_table[i].phasemsg, ahc_inw(ahc, SEQADDR0), scsirate); if ((ahc->features & AHC_DT) != 0) { if ((sstat2 & CRCVALERR) != 0) - printf("\tCRC Value Mismatch\n"); + printk("\tCRC Value Mismatch\n"); if ((sstat2 & CRCENDERR) != 0) - printf("\tNo terminal CRC packet " + printk("\tNo terminal CRC packet " "recevied\n"); if ((sstat2 & CRCREQERR) != 0) - printf("\tIllegal CRC packet " + printk("\tIllegal CRC packet " "request\n"); if ((sstat2 & DUAL_EDGE_ERR) != 0) - printf("\tUnexpected %sDT Data Phase\n", + printk("\tUnexpected %sDT Data Phase\n", (scsirate & SINGLE_EDGE) ? "" : "non-"); } @@ -1746,7 +1746,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb = ahc_lookup_scb(ahc, scb_index); if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " + printk("%s: ahc_intr - referenced scb not " "valid during SELTO scb(%d, %d)\n", ahc_name(ahc), scbptr, scb_index); ahc_dump_card_state(ahc); @@ -1755,7 +1755,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_SELTO) != 0) { ahc_print_path(ahc, scb); - printf("Saw Selection Timeout for SCB 0x%x\n", + printk("Saw Selection Timeout for SCB 0x%x\n", scb_index); } #endif @@ -1831,7 +1831,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) == MSG_ABORT_TAG) tag = scb->hscb->tag; ahc_print_path(ahc, scb); - printf("SCB %d - Abort%s Completed.\n", + printk("SCB %d - Abort%s Completed.\n", scb->hscb->tag, tag == SCB_LIST_NULL ? "" : " Tag"); ahc_abort_scbs(ahc, target, channel, @@ -1934,7 +1934,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * We had not fully identified this connection, * so we cannot abort anything. */ - printf("%s: ", ahc_name(ahc)); + printk("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { if (lastphase == ahc_phase_table[i].phase) @@ -1949,7 +1949,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) */ ahc_force_renegotiation(ahc, &devinfo); } - printf("Unexpected busfree %s\n" + printk("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", ahc_phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) @@ -1958,7 +1958,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); } else { - printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", + printk("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); ahc_outb(ahc, CLRINT, CLRSCSIINT); } @@ -2025,7 +2025,7 @@ ahc_clear_critical_section(struct ahc_softc *ahc) break; if (steps > AHC_MAX_STEPS) { - printf("%s: Infinite loop in critical section\n", + printk("%s: Infinite loop in critical section\n", ahc_name(ahc)); ahc_dump_card_state(ahc); panic("critical section loop"); @@ -2104,23 +2104,23 @@ ahc_print_scb(struct scb *scb) struct hardware_scb *hscb = scb->hscb; - printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", + printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", (void *)scb, hscb->control, hscb->scsiid, hscb->lun, hscb->cdb_len); - printf("Shared Data: "); + printk("Shared Data: "); for (i = 0; i < sizeof(hscb->shared_data.cdb); i++) - printf("%#02x", hscb->shared_data.cdb[i]); - printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", + printk("%#02x", hscb->shared_data.cdb[i]); + printk(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", ahc_le32toh(hscb->dataptr), ahc_le32toh(hscb->datacnt), ahc_le32toh(hscb->sgptr), hscb->tag); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x%x : Length %d\n", + printk("sg[%d] - Addr 0x%x%x : Length %d\n", i, (ahc_le32toh(scb->sg_list[i].len) >> 24 & SG_HIGH_ADDR_BITS), @@ -2152,8 +2152,7 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) && ahc->enabled_targets[scsi_id] != master_tstate) panic("%s: ahc_alloc_tstate - Target already allocated", ahc_name(ahc)); - tstate = (struct ahc_tmode_tstate*)malloc(sizeof(*tstate), - M_DEVBUF, M_NOWAIT); + tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); if (tstate == NULL) return (NULL); @@ -2202,7 +2201,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) scsi_id += 8; tstate = ahc->enabled_targets[scsi_id]; if (tstate != NULL) - free(tstate, M_DEVBUF); + kfree(tstate); ahc->enabled_targets[scsi_id] = NULL; } #endif @@ -2589,13 +2588,13 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { if (offset != 0) { - printf("%s: target %d synchronous at %sMHz%s, " + printk("%s: target %d synchronous at %sMHz%s, " "offset = 0x%x\n", ahc_name(ahc), devinfo->target, syncrate->rate, (ppr_options & MSG_EXT_PPR_DT_REQ) ? " DT" : "", offset); } else { - printf("%s: target %d using " + printk("%s: target %d using " "asynchronous transfers\n", ahc_name(ahc), devinfo->target); } @@ -2658,7 +2657,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_send_async(ahc, devinfo->channel, devinfo->target, CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { - printf("%s: target %d using %dbit transfers\n", + printk("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, 8 * (0x01 << width)); } @@ -2835,7 +2834,7 @@ ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, void ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel, + printk("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); } @@ -2907,7 +2906,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; ahc->msgout_len++; ahc_print_path(ahc, scb); - printf("Bus Device Reset Message Sent\n"); + printk("Bus Device Reset Message Sent\n"); /* * Clear our selection hardware in advance of * the busfree. We may have an entry in the waiting @@ -2923,7 +2922,7 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; ahc->msgout_len++; ahc_print_path(ahc, scb); - printf("Abort%s Message Sent\n", + printk("Abort%s Message Sent\n", (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); /* * Clear our selection hardware in advance of @@ -2936,9 +2935,9 @@ ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { - printf("ahc_intr: AWAITING_MSG for an SCB that " + printk("ahc_intr: AWAITING_MSG for an SCB that " "does not have a waiting message\n"); - printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, + printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, devinfo->target_mask); panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " "SCB flags = %x", scb->hscb->tag, scb->hscb->control, @@ -3019,7 +3018,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) if (bootverbose) { ahc_print_devinfo(ahc, devinfo); - printf("Ensuring async\n"); + printk("Ensuring async\n"); } } @@ -3067,7 +3066,7 @@ ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_buf + ahc->msgout_index, period, offset); ahc->msgout_len += 5; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", + printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, period, offset); } @@ -3085,7 +3084,7 @@ ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc->msgout_buf + ahc->msgout_index, bus_width); ahc->msgout_len += 4; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending WDTR %x\n", + printk("(%s:%c:%d:%d): Sending WDTR %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, bus_width); } @@ -3107,7 +3106,7 @@ ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, bus_width, ppr_options); ahc->msgout_len += 8; if (bootverbose) { - printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " + printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " "offset %x, ppr_options %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, bus_width, period, offset, ppr_options); @@ -3160,7 +3159,7 @@ ahc_handle_proto_violation(struct ahc_softc *ahc) * to match. */ ahc_print_devinfo(ahc, &devinfo); - printf("Target did not send an IDENTIFY message. " + printk("Target did not send an IDENTIFY message. " "LASTPHASE = 0x%x.\n", lastphase); scb = NULL; } else if (scb == NULL) { @@ -3169,13 +3168,13 @@ ahc_handle_proto_violation(struct ahc_softc *ahc) * transaction. Print an error and reset the bus. */ ahc_print_devinfo(ahc, &devinfo); - printf("No SCB found during protocol violation\n"); + printk("No SCB found during protocol violation\n"); goto proto_violation_reset; } else { ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL); if ((seq_flags & NO_CDB_SENT) != 0) { ahc_print_path(ahc, scb); - printf("No or incomplete CDB sent to device.\n"); + printk("No or incomplete CDB sent to device.\n"); } else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) { /* * The target never bothered to provide status to @@ -3185,10 +3184,10 @@ ahc_handle_proto_violation(struct ahc_softc *ahc) * message. */ ahc_print_path(ahc, scb); - printf("Completed command without status.\n"); + printk("Completed command without status.\n"); } else { ahc_print_path(ahc, scb); - printf("Unknown protocol violation.\n"); + printk("Unknown protocol violation.\n"); ahc_dump_card_state(ahc); } } @@ -3202,7 +3201,7 @@ proto_violation_reset: * it away with a bus reset. */ found = ahc_reset_channel(ahc, 'A', TRUE); - printf("%s: Issued Channel %c Bus Reset. " + printk("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahc_name(ahc), 'A', found); } else { /* @@ -3224,7 +3223,7 @@ proto_violation_reset: ahc_print_path(ahc, scb); scb->flags |= SCB_ABORT; } - printf("Protocol violation %s. Attempting to abort.\n", + printk("Protocol violation %s. Attempting to abort.\n", ahc_lookup_phase_entry(curphase)->phasemsg); } } @@ -3257,14 +3256,14 @@ reswitch: #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { ahc_print_devinfo(ahc, &devinfo); - printf("INITIATOR_MSG_OUT"); + printk("INITIATOR_MSG_OUT"); } #endif phasemis = bus_phase != P_MESGOUT; if (phasemis) { #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - printf(" PHASEMIS %s\n", + printk(" PHASEMIS %s\n", ahc_lookup_phase_entry(bus_phase) ->phasemsg); } @@ -3291,7 +3290,7 @@ reswitch: ahc_outb(ahc, CLRSINT1, CLRREQINIT); #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", ahc->send_msg_perror); + printk(" byte 0x%x\n", ahc->send_msg_perror); #endif ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); break; @@ -3321,7 +3320,7 @@ reswitch: ahc_outb(ahc, CLRSINT1, CLRREQINIT); #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", + printk(" byte 0x%x\n", ahc->msgout_buf[ahc->msgout_index]); #endif ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); @@ -3335,14 +3334,14 @@ reswitch: #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { ahc_print_devinfo(ahc, &devinfo); - printf("INITIATOR_MSG_IN"); + printk("INITIATOR_MSG_IN"); } #endif phasemis = bus_phase != P_MESGIN; if (phasemis) { #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - printf(" PHASEMIS %s\n", + printk(" PHASEMIS %s\n", ahc_lookup_phase_entry(bus_phase) ->phasemsg); } @@ -3363,7 +3362,7 @@ reswitch: ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printf(" byte 0x%x\n", + printk(" byte 0x%x\n", ahc->msgin_buf[ahc->msgin_index]); #endif @@ -3385,7 +3384,7 @@ reswitch: #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { ahc_print_devinfo(ahc, &devinfo); - printf("Asserting ATN for response\n"); + printk("Asserting ATN for response\n"); } #endif ahc_assert_atn(ahc); @@ -3666,7 +3665,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) targ_scsirate & WIDEXFER, devinfo->role); if (bootverbose) { - printf("(%s:%c:%d:%d): Received " + printk("(%s:%c:%d:%d): Received " "SDTR period %x, offset %x\n\t" "Filtered to period %x, offset %x\n", ahc_name(ahc), devinfo->channel, @@ -3697,7 +3696,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) */ if (bootverbose && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated SDTR\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); @@ -3739,7 +3738,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ahc_validate_width(ahc, tinfo, &bus_width, devinfo->role); if (bootverbose) { - printf("(%s:%c:%d:%d): Received WDTR " + printk("(%s:%c:%d:%d): Received WDTR " "%x filtered to %x\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, @@ -3755,7 +3754,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) */ if (saved_width > bus_width) { reject = TRUE; - printf("(%s:%c:%d:%d): requested %dBit " + printk("(%s:%c:%d:%d): requested %dBit " "transfers. Rejecting...\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, @@ -3768,7 +3767,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) */ if (bootverbose && devinfo->role == ROLE_INITIATOR) { - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated WDTR\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); @@ -3886,12 +3885,12 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) } } else { if (devinfo->role != ROLE_TARGET) - printf("(%s:%c:%d:%d): Target " + printk("(%s:%c:%d:%d): Target " "Initiated PPR\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); else - printf("(%s:%c:%d:%d): Initiator " + printk("(%s:%c:%d:%d): Initiator " "Initiated PPR\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); @@ -3903,7 +3902,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) response = TRUE; } if (bootverbose) { - printf("(%s:%c:%d:%d): Received PPR width %x, " + printk("(%s:%c:%d:%d): Received PPR width %x, " "period %x, offset %x,options %x\n" "\tFiltered to width %x, period %x, " "offset %x, options %x\n", @@ -4033,7 +4032,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) * Attempt to negotiate SPI-2 style. */ if (bootverbose) { - printf("(%s:%c:%d:%d): PPR Rejected. " + printk("(%s:%c:%d:%d): PPR Rejected. " "Trying WDTR/SDTR\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); @@ -4049,7 +4048,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { /* note 8bit xfers */ - printf("(%s:%c:%d:%d): refuses WIDE negotiation. Using " + printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using " "8bit transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, @@ -4077,7 +4076,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) /*offset*/0, /*ppr_options*/0, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); - printf("(%s:%c:%d:%d): refuses synchronous negotiation. " + printk("(%s:%c:%d:%d): refuses synchronous negotiation. " "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); @@ -4088,13 +4087,13 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); if (tag_type == MSG_SIMPLE_TASK) { - printf("(%s:%c:%d:%d): refuses tagged commands. " + printk("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE); mask = ~0x23; } else { - printf("(%s:%c:%d:%d): refuses %s tagged commands. " + printk("(%s:%c:%d:%d): refuses %s tagged commands. " "Performing simple queue tagged I/O only\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK @@ -4144,7 +4143,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) /* * Otherwise, we ignore it. */ - printf("%s:%c:%d: Message reject for %x -- ignored\n", + printk("%s:%c:%d: Message reject for %x -- ignored\n", ahc_name(ahc), devinfo->channel, devinfo->target, last_msg); } @@ -4369,7 +4368,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (message != NULL && (verbose_level <= bootverbose)) - printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), + printk("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), message, devinfo->channel, devinfo->target, found); } @@ -4408,23 +4407,22 @@ ahc_alloc(void *platform_arg, char *name) int i; #ifndef __FreeBSD__ - ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT); + ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC); if (!ahc) { - printf("aic7xxx: cannot malloc softc!\n"); - free(name, M_DEVBUF); + printk("aic7xxx: cannot malloc softc!\n"); + kfree(name); return NULL; } #else ahc = device_get_softc((device_t)platform_arg); #endif memset(ahc, 0, sizeof(*ahc)); - ahc->seep_config = malloc(sizeof(*ahc->seep_config), - M_DEVBUF, M_NOWAIT); + ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC); if (ahc->seep_config == NULL) { #ifndef __FreeBSD__ - free(ahc, M_DEVBUF); + kfree(ahc); #endif - free(name, M_DEVBUF); + kfree(name); return (NULL); } LIST_INIT(&ahc->pending_scbs); @@ -4466,8 +4464,7 @@ ahc_softc_init(struct ahc_softc *ahc) ahc->pause = ahc->unpause | PAUSE; /* XXX The shared scb data stuff should be deprecated */ if (ahc->scb_data == NULL) { - ahc->scb_data = malloc(sizeof(*ahc->scb_data), - M_DEVBUF, M_NOWAIT); + ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), GFP_ATOMIC); if (ahc->scb_data == NULL) return (ENOMEM); memset(ahc->scb_data, 0, sizeof(*ahc->scb_data)); @@ -4486,7 +4483,7 @@ void ahc_set_name(struct ahc_softc *ahc, char *name) { if (ahc->name != NULL) - free(ahc->name, M_DEVBUF); + kfree(ahc->name); ahc->name = name; } @@ -4540,25 +4537,25 @@ ahc_free(struct ahc_softc *ahc) lstate = tstate->enabled_luns[j]; if (lstate != NULL) { xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); + kfree(lstate); } } #endif - free(tstate, M_DEVBUF); + kfree(tstate); } } #ifdef AHC_TARGET_MODE if (ahc->black_hole != NULL) { xpt_free_path(ahc->black_hole->path); - free(ahc->black_hole, M_DEVBUF); + kfree(ahc->black_hole); } #endif if (ahc->name != NULL) - free(ahc->name, M_DEVBUF); + kfree(ahc->name); if (ahc->seep_config != NULL) - free(ahc->seep_config, M_DEVBUF); + kfree(ahc->seep_config); #ifndef __FreeBSD__ - free(ahc, M_DEVBUF); + kfree(ahc); #endif return; } @@ -4633,7 +4630,7 @@ ahc_reset(struct ahc_softc *ahc, int reinit) } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)); if (wait == 0) { - printf("%s: WARNING - Failed chip reset! " + printk("%s: WARNING - Failed chip reset! " "Trying to initialize anyway.\n", ahc_name(ahc)); } ahc_outb(ahc, HCNTRL, ahc->pause); @@ -4656,7 +4653,7 @@ ahc_reset(struct ahc_softc *ahc, int reinit) ahc->features |= AHC_TWIN; break; default: - printf(" Unsupported adapter type. Ignoring\n"); + printk(" Unsupported adapter type. Ignoring\n"); return(-1); } @@ -4783,9 +4780,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) SLIST_INIT(&scb_data->sg_maps); /* Allocate SCB resources */ - scb_data->scbarray = - (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, - M_DEVBUF, M_NOWAIT); + scb_data->scbarray = (struct scb *)kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC); if (scb_data->scbarray == NULL) return (ENOMEM); memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC); @@ -4794,7 +4789,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->maxhscbs = ahc_probe_scbs(ahc); if (ahc->scb_data->maxhscbs == 0) { - printf("%s: No SCB space found\n", ahc_name(ahc)); + printk("%s: No SCB space found\n", ahc_name(ahc)); return (ENXIO); } @@ -4892,7 +4887,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) ahc_alloc_scbs(ahc); if (scb_data->numscbs == 0) { - printf("%s: ahc_init_scbdata - " + printk("%s: ahc_init_scbdata - " "Unable to allocate initial scbs\n", ahc_name(ahc)); goto error_exit; @@ -4935,7 +4930,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc) ahc_dmamem_free(ahc, scb_data->sg_dmat, sg_map->sg_vaddr, sg_map->sg_dmamap); - free(sg_map, M_DEVBUF); + kfree(sg_map); } ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); } @@ -4964,7 +4959,7 @@ ahc_fini_scbdata(struct ahc_softc *ahc) break; } if (scb_data->scbarray != NULL) - free(scb_data->scbarray, M_DEVBUF); + kfree(scb_data->scbarray); } static void @@ -4985,7 +4980,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) next_scb = &scb_data->scbarray[scb_data->numscbs]; - sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); + sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); if (sg_map == NULL) return; @@ -4994,7 +4989,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, (void **)&sg_map->sg_vaddr, BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { - free(sg_map, M_DEVBUF); + kfree(sg_map); return; } @@ -5014,8 +5009,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) #ifndef __linux__ int error; #endif - pdata = (struct scb_platform_data *)malloc(sizeof(*pdata), - M_DEVBUF, M_NOWAIT); + pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); if (pdata == NULL) break; next_scb->platform_data = pdata; @@ -5244,7 +5238,7 @@ ahc_chip_init(struct ahc_softc *ahc) * in "fast" mode. */ if (bootverbose) - printf("%s: Downloading Sequencer Program...", + printk("%s: Downloading Sequencer Program...", ahc_name(ahc)); error = ahc_loadseq(ahc); @@ -5290,22 +5284,22 @@ ahc_init(struct ahc_softc *ahc) #endif #ifdef AHC_PRINT_SRAM - printf("Scratch Ram:"); + printk("Scratch Ram:"); for (i = 0x20; i < 0x5f; i++) { if (((i % 8) == 0) && (i != 0)) { - printf ("\n "); + printk ("\n "); } - printf (" 0x%x", ahc_inb(ahc, i)); + printk (" 0x%x", ahc_inb(ahc, i)); } if ((ahc->features & AHC_MORE_SRAM) != 0) { for (i = 0x70; i < 0x7f; i++) { if (((i % 8) == 0) && (i != 0)) { - printf ("\n "); + printk ("\n "); } - printf (" 0x%x", ahc_inb(ahc, i)); + printk (" 0x%x", ahc_inb(ahc, i)); } } - printf ("\n"); + printk ("\n"); /* * Reading uninitialized scratch ram may * generate parity errors. @@ -5419,14 +5413,14 @@ ahc_init(struct ahc_softc *ahc) * data for any target mode initiator. */ if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printf("%s: unable to allocate ahc_tmode_tstate. " + printk("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); return (ENOMEM); } if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printf("%s: unable to allocate ahc_tmode_tstate. " + printk("%s: unable to allocate ahc_tmode_tstate. " "Failing attach\n", ahc_name(ahc)); return (ENOMEM); } @@ -5440,7 +5434,7 @@ ahc_init(struct ahc_softc *ahc) #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_MISC) { - printf("%s: hardware scb %u bytes; kernel scb %u bytes; " + printk("%s: hardware scb %u bytes; kernel scb %u bytes; " "ahc_dma %u bytes\n", ahc_name(ahc), (u_int)sizeof(struct hardware_scb), @@ -5470,7 +5464,7 @@ ahc_init(struct ahc_softc *ahc) /* Grab the disconnection disable table and invert it for our needs */ if ((ahc->flags & AHC_USEDEFAULTS) != 0) { - printf("%s: Host Adapter Bios disabled. Using default SCSI " + printk("%s: Host Adapter Bios disabled. Using default SCSI " "device parameters\n", ahc_name(ahc)); ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| AHC_TERM_ENB_A|AHC_TERM_ENB_B; @@ -5651,7 +5645,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) && ((intstat & INT_PEND) != 0 || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0)); if (maxloops == 0) { - printf("Infinite interrupt loop, INTSTAT = %x", + printk("Infinite interrupt loop, INTSTAT = %x", ahc_inb(ahc, INTSTAT)); } ahc_platform_flushwork(ahc); @@ -5910,7 +5904,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, while (qinpos != qintail) { scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]); if (scb == NULL) { - printf("qinpos = %d, SCB index = %d\n", + printk("qinpos = %d, SCB index = %d\n", qinpos, ahc->qinfifo[qinpos]); panic("Loop 1\n"); } @@ -5933,7 +5927,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, if (cstat != CAM_REQ_CMP) ahc_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in qinfifo\n"); + printk("Inactive SCB in qinfifo\n"); ahc_done(ahc, scb); /* FALLTHROUGH */ @@ -5976,7 +5970,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]); if (scb == NULL) { - printf("found = %d, qinstart = %d, qinfifionext = %d\n", + printk("found = %d, qinstart = %d, qinfifionext = %d\n", found, qinstart, ahc->qinfifonext); panic("First/Second Qinfifo fixup\n"); } @@ -6014,7 +6008,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, next); scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index >= ahc->scb_data->numscbs) { - printf("Waiting List inconsistency. " + printk("Waiting List inconsistency. " "SCB index == %d, yet numscbs == %d.", scb_index, ahc->scb_data->numscbs); ahc_dump_card_state(ahc); @@ -6022,7 +6016,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, } scb = ahc_lookup_scb(ahc, scb_index); if (scb == NULL) { - printf("scb_index = %d, next = %d\n", + printk("scb_index = %d, next = %d\n", scb_index, next); panic("Waiting List traversal\n"); } @@ -6046,7 +6040,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, if (cstat != CAM_REQ_CMP) ahc_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in Waiting List\n"); + printk("Inactive SCB in Waiting List\n"); ahc_done(ahc, scb); /* FALLTHROUGH */ } @@ -6153,7 +6147,7 @@ ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx, if (cstat != CAM_REQ_CMP) ahc_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB in untaggedQ\n"); + printk("Inactive SCB in untaggedQ\n"); ahc_done(ahc, scb); break; } @@ -6200,7 +6194,7 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, next); scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index >= ahc->scb_data->numscbs) { - printf("Disconnected List inconsistency. " + printk("Disconnected List inconsistency. " "SCB index == %d, yet numscbs == %d.", scb_index, ahc->scb_data->numscbs); ahc_dump_card_state(ahc); @@ -6456,7 +6450,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) ahc_freeze_scb(scbp); if ((scbp->flags & SCB_ACTIVE) == 0) - printf("Inactive SCB on pending list\n"); + printk("Inactive SCB on pending list\n"); ahc_done(ahc, scbp); found++; } @@ -6734,7 +6728,7 @@ ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb) #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MISC) != 0) { ahc_print_path(ahc, scb); - printf("Handled %sResidual of %d bytes\n", + printk("Handled %sResidual of %d bytes\n", (scb->flags & SCB_SENSE) ? "Sense " : "", resid); } #endif @@ -6774,7 +6768,7 @@ ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) { xpt_print_path(lstate->path); - printf("immediate event %x:%x lost\n", + printk("immediate event %x:%x lost\n", lstate->event_buffer[lstate->event_r_idx].event_type, lstate->event_buffer[lstate->event_r_idx].event_arg); lstate->event_r_idx++; @@ -6844,7 +6838,7 @@ ahc_dumpseq(struct ahc_softc* ahc) uint8_t ins_bytes[4]; ahc_insb(ahc, SEQRAM, ins_bytes, 4); - printf("0x%08x\n", ins_bytes[0] << 24 + printk("0x%08x\n", ins_bytes[0] << 24 | ins_bytes[1] << 16 | ins_bytes[2] << 8 | ins_bytes[3]); @@ -6912,7 +6906,7 @@ ahc_loadseq(struct ahc_softc *ahc) * storage capacity for this chip. Fail * the load. */ - printf("\n%s: Program too large for instruction memory " + printk("\n%s: Program too large for instruction memory " "size of %d!\n", ahc_name(ahc), ahc->instruction_ram_size); return (ENOMEM); @@ -6947,7 +6941,7 @@ ahc_loadseq(struct ahc_softc *ahc) if (cs_count != 0) { cs_count *= sizeof(struct cs); - ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT); + ahc->critical_sections = kmalloc(cs_count, GFP_ATOMIC); if (ahc->critical_sections == NULL) panic("ahc_loadseq: Could not malloc"); memcpy(ahc->critical_sections, cs_table, cs_count); @@ -6955,8 +6949,8 @@ ahc_loadseq(struct ahc_softc *ahc) ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); if (bootverbose) { - printf(" %d instructions downloaded\n", downloaded); - printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", + printk(" %d instructions downloaded\n", downloaded); + printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags); } return (0); @@ -7132,12 +7126,12 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries, u_int printed_mask; if (cur_column != NULL && *cur_column >= wrap_point) { - printf("\n"); + printk("\n"); *cur_column = 0; } - printed = printf("%s[0x%x]", name, value); + printed = printk("%s[0x%x]", name, value); if (table == NULL) { - printed += printf(" "); + printed += printk(" "); *cur_column += printed; return (printed); } @@ -7152,7 +7146,7 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries, == table[entry].mask)) continue; - printed += printf("%s%s", + printed += printk("%s%s", printed_mask == 0 ? ":(" : "|", table[entry].name); printed_mask |= table[entry].mask; @@ -7163,9 +7157,9 @@ ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries, break; } if (printed_mask != 0) - printed += printf(") "); + printed += printk(") "); else - printed += printf(" "); + printed += printk(" "); if (cur_column != NULL) *cur_column += printed; return (printed); @@ -7197,16 +7191,16 @@ ahc_dump_card_state(struct ahc_softc *ahc) saved_scbptr = ahc_inb(ahc, SCBPTR); last_phase = ahc_inb(ahc, LASTPHASE); - printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" + printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" "%s: Dumping Card State %s, at SEQADDR 0x%x\n", ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); if (paused) - printf("Card was paused\n"); - printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", + printk("Card was paused\n"); + printk("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX), ahc_inb(ahc, ARG_2)); - printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT), + printk("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT), ahc_inb(ahc, SCBPTR)); cur_col = 0; if ((ahc->features & AHC_DT) != 0) @@ -7230,15 +7224,15 @@ ahc_dump_card_state(struct ahc_softc *ahc) ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50); ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50); if (cur_col != 0) - printf("\n"); - printf("STACK:"); + printk("\n"); + printk("STACK:"); for (i = 0; i < STACK_SIZE; i++) - printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8)); - printf("\nSCB count = %d\n", ahc->scb_data->numscbs); - printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); - printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); + printk(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8)); + printk("\nSCB count = %d\n", ahc->scb_data->numscbs); + printk("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); + printk("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); /* QINFIFO */ - printf("QINFIFO entries: "); + printk("QINFIFO entries: "); if ((ahc->features & AHC_QUEUE_REGS) != 0) { qinpos = ahc_inb(ahc, SNSCB_QOFF); ahc_outb(ahc, SNSCB_QOFF, qinpos); @@ -7246,109 +7240,109 @@ ahc_dump_card_state(struct ahc_softc *ahc) qinpos = ahc_inb(ahc, QINPOS); qintail = ahc->qinfifonext; while (qinpos != qintail) { - printf("%d ", ahc->qinfifo[qinpos]); + printk("%d ", ahc->qinfifo[qinpos]); qinpos++; } - printf("\n"); + printk("\n"); - printf("Waiting Queue entries: "); + printk("Waiting Queue entries: "); scb_index = ahc_inb(ahc, WAITING_SCBH); i = 0; while (scb_index != SCB_LIST_NULL && i++ < 256) { ahc_outb(ahc, SCBPTR, scb_index); - printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); scb_index = ahc_inb(ahc, SCB_NEXT); } - printf("\n"); + printk("\n"); - printf("Disconnected Queue entries: "); + printk("Disconnected Queue entries: "); scb_index = ahc_inb(ahc, DISCONNECTED_SCBH); i = 0; while (scb_index != SCB_LIST_NULL && i++ < 256) { ahc_outb(ahc, SCBPTR, scb_index); - printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); + printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); scb_index = ahc_inb(ahc, SCB_NEXT); } - printf("\n"); + printk("\n"); ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); - printf("QOUTFIFO entries: "); + printk("QOUTFIFO entries: "); qoutpos = ahc->qoutfifonext; i = 0; while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) { - printf("%d ", ahc->qoutfifo[qoutpos]); + printk("%d ", ahc->qoutfifo[qoutpos]); qoutpos++; } - printf("\n"); + printk("\n"); - printf("Sequencer Free SCB List: "); + printk("Sequencer Free SCB List: "); scb_index = ahc_inb(ahc, FREE_SCBH); i = 0; while (scb_index != SCB_LIST_NULL && i++ < 256) { ahc_outb(ahc, SCBPTR, scb_index); - printf("%d ", scb_index); + printk("%d ", scb_index); scb_index = ahc_inb(ahc, SCB_NEXT); } - printf("\n"); + printk("\n"); - printf("Sequencer SCB Info: "); + printk("Sequencer SCB Info: "); for (i = 0; i < ahc->scb_data->maxhscbs; i++) { ahc_outb(ahc, SCBPTR, i); - cur_col = printf("\n%3d ", i); + cur_col = printk("\n%3d ", i); ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60); ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60); ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60); ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60); } - printf("\n"); + printk("\n"); - printf("Pending list: "); + printk("Pending list: "); i = 0; LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { if (i++ > 256) break; - cur_col = printf("\n%3d ", scb->hscb->tag); + cur_col = printk("\n%3d ", scb->hscb->tag); ahc_scb_control_print(scb->hscb->control, &cur_col, 60); ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60); ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60); if ((ahc->flags & AHC_PAGESCBS) == 0) { ahc_outb(ahc, SCBPTR, scb->hscb->tag); - printf("("); + printk("("); ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60); ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60); - printf(")"); + printk(")"); } } - printf("\n"); + printk("\n"); - printf("Kernel Free SCB list: "); + printk("Kernel Free SCB list: "); i = 0; SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) { if (i++ > 256) break; - printf("%d ", scb->hscb->tag); + printk("%d ", scb->hscb->tag); } - printf("\n"); + printk("\n"); maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; for (target = 0; target <= maxtarget; target++) { untagged_q = &ahc->untagged_queues[target]; if (TAILQ_FIRST(untagged_q) == NULL) continue; - printf("Untagged Q(%d): ", target); + printk("Untagged Q(%d): ", target); i = 0; TAILQ_FOREACH(scb, untagged_q, links.tqe) { if (i++ > 256) break; - printf("%d ", scb->hscb->tag); + printk("%d ", scb->hscb->tag); } - printf("\n"); + printk("\n"); } ahc_platform_dump_card_state(ahc); - printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); + printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); ahc_outb(ahc, SCBPTR, saved_scbptr); if (paused == 0) ahc_unpause(ahc); @@ -7489,7 +7483,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) u_long s; ahc_flag saved_flags; - printf("Configuring Target Mode\n"); + printk("Configuring Target Mode\n"); ahc_lock(ahc, &s); if (LIST_FIRST(&ahc->pending_scbs) != NULL) { ccb->ccb_h.status = CAM_BUSY; @@ -7535,7 +7529,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) /* Are we already enabled?? */ if (lstate != NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Lun already enabled\n"); + printk("Lun already enabled\n"); ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; return; } @@ -7547,7 +7541,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) * specific commands. */ ccb->ccb_h.status = CAM_REQ_INVALID; - printf("Non-zero Group Codes\n"); + printk("Non-zero Group Codes\n"); return; } @@ -7559,15 +7553,15 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) tstate = ahc_alloc_tstate(ahc, target, channel); if (tstate == NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate tstate\n"); + printk("Couldn't allocate tstate\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } } - lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT); + lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC); if (lstate == NULL) { xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate lstate\n"); + printk("Couldn't allocate lstate\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } @@ -7577,9 +7571,9 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) xpt_path_target_id(ccb->ccb_h.path), xpt_path_lun_id(ccb->ccb_h.path)); if (status != CAM_REQ_CMP) { - free(lstate, M_DEVBUF); + kfree(lstate); xpt_print_path(ccb->ccb_h.path); - printf("Couldn't allocate path\n"); + printk("Couldn't allocate path\n"); ccb->ccb_h.status = CAM_RESRC_UNAVAIL; return; } @@ -7654,7 +7648,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_REQ_CMP; xpt_print_path(ccb->ccb_h.path); - printf("Lun now enabled for target mode\n"); + printk("Lun now enabled for target mode\n"); } else { struct scb *scb; int i, empty; @@ -7673,7 +7667,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ccbh = &scb->io_ctx->ccb_h; if (ccbh->func_code == XPT_CONT_TARGET_IO && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ - printf("CTIO pending\n"); + printk("CTIO pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; ahc_unlock(ahc, &s); return; @@ -7681,12 +7675,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) } if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printf("ATIOs pending\n"); + printk("ATIOs pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; } if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printf("INOTs pending\n"); + printk("INOTs pending\n"); ccb->ccb_h.status = CAM_REQ_INVALID; } @@ -7696,9 +7690,9 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) } xpt_print_path(ccb->ccb_h.path); - printf("Target mode disabled\n"); + printk("Target mode disabled\n"); xpt_free_path(lstate->path); - free(lstate, M_DEVBUF); + kfree(lstate); ahc_pause(ahc); /* Can we clean up the target too? */ @@ -7750,7 +7744,7 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ahc_outb(ahc, SCSISEQ, scsiseq); if ((ahc->features & AHC_MULTIROLE) == 0) { - printf("Configuring Initiator Mode\n"); + printk("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; /* @@ -7897,12 +7891,12 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) * Wait for more ATIOs from the peripheral driver for this lun. */ if (bootverbose) - printf("%s: ATIOs exhausted\n", ahc_name(ahc)); + printk("%s: ATIOs exhausted\n", ahc_name(ahc)); return (1); } else ahc->flags &= ~AHC_TQINFIFO_BLOCKED; #if 0 - printf("Incoming command from %d for %d:%d%s\n", + printk("Incoming command from %d for %d:%d%s\n", initiator, target, lun, lstate == ahc->black_hole ? "(Black Holed)" : ""); #endif @@ -7949,7 +7943,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) default: /* Only copy the opcode. */ atio->cdb_len = 1; - printf("Reserved or VU command code type encountered\n"); + printk("Reserved or VU command code type encountered\n"); break; } @@ -7965,7 +7959,7 @@ ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) * to this accept tio. */ #if 0 - printf("Received Immediate Command %d:%d:%d - %p\n", + printk("Received Immediate Command %d:%d:%d - %p\n", initiator, target, lun, ahc->pending_device); #endif ahc->pending_device = lstate; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 5e42dac2350..aeea7a61478 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -653,7 +653,7 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) struct ahc_linux_device *dev; if (bootverbose) - printf("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id); + printk("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id); dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -755,7 +755,7 @@ ahc_linux_abort(struct scsi_cmnd *cmd) error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); if (error != 0) - printf("aic7xxx_abort returns 0x%x\n", error); + printk("aic7xxx_abort returns 0x%x\n", error); return (error); } @@ -769,7 +769,7 @@ ahc_linux_dev_reset(struct scsi_cmnd *cmd) error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); if (error != 0) - printf("aic7xxx_dev_reset returns 0x%x\n", error); + printk("aic7xxx_dev_reset returns 0x%x\n", error); return (error); } @@ -791,7 +791,7 @@ ahc_linux_bus_reset(struct scsi_cmnd *cmd) ahc_unlock(ahc, &flags); if (bootverbose) - printf("%s: SCSI bus reset delivered. " + printk("%s: SCSI bus reset delivered. " "%d SCBs aborted.\n", ahc_name(ahc), found); return SUCCESS; @@ -840,7 +840,7 @@ ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, { bus_dma_tag_t dmat; - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); if (dmat == NULL) return (ENOMEM); @@ -861,7 +861,7 @@ ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, void ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) { - free(dmat, M_DEVBUF); + kfree(dmat); } int @@ -918,7 +918,7 @@ ahc_linux_setup_tag_info_global(char *p) int tags, i, j; tags = simple_strtoul(p + 1, NULL, 0) & 0xff; - printf("Setting Global Tags= %d\n", tags); + printk("Setting Global Tags= %d\n", tags); for (i = 0; i < ARRAY_SIZE(aic7xxx_tag_info); i++) { for (j = 0; j < AHC_NUM_TARGETS; j++) { @@ -936,7 +936,7 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) && (targ < AHC_NUM_TARGETS)) { aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff; if (bootverbose) - printf("tag_info[%d:%d] = %d\n", instance, targ, value); + printk("tag_info[%d:%d] = %d\n", instance, targ, value); } } @@ -977,7 +977,7 @@ ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, if (targ == -1) targ = 0; } else { - printf("Malformed Option %s\n", + printk("Malformed Option %s\n", opt_name); done = TRUE; } @@ -1120,7 +1120,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa ahc_set_unit(ahc, ahc_linux_unit++); ahc_unlock(ahc, &s); sprintf(buf, "scsi%d", host->host_no); - new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); if (new_name != NULL) { strcpy(new_name, buf); ahc_set_name(ahc, new_name); @@ -1220,7 +1220,7 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) { ahc->platform_data = - malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT); + kmalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC); if (ahc->platform_data == NULL) return (ENOMEM); memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); @@ -1264,7 +1264,7 @@ ahc_platform_free(struct ahc_softc *ahc) if (ahc->platform_data->host) scsi_host_put(ahc->platform_data->host); - free(ahc->platform_data, M_DEVBUF); + kfree(ahc->platform_data); } } @@ -1378,7 +1378,7 @@ ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) if (ahc->unit >= ARRAY_SIZE(aic7xxx_tag_info)) { if (warned_user == 0) { - printf(KERN_WARNING + printk(KERN_WARNING "aic7xxx: WARNING: Insufficient tag_info instances\n" "aic7xxx: for installed controllers. Using defaults\n" "aic7xxx: Please update the aic7xxx_tag_info array in\n" @@ -1421,7 +1421,7 @@ ahc_linux_device_queue_depth(struct scsi_device *sdev) ahc_send_async(ahc, devinfo.channel, devinfo.target, devinfo.lun, AC_TRANSFER_NEG); ahc_print_devinfo(ahc, &devinfo); - printf("Tagged Queuing enabled. Depth %d\n", tags); + printk("Tagged Queuing enabled. Depth %d\n", tags); } else { ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE); ahc_send_async(ahc, devinfo.channel, devinfo.target, @@ -1735,7 +1735,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) * not have been dispatched to the controller, so * only check the SCB_ACTIVE flag for tagged transactions. */ - printf("SCB %d done'd twice\n", scb->hscb->tag); + printk("SCB %d done'd twice\n", scb->hscb->tag); ahc_dump_card_state(ahc); panic("Stopping for safety"); } @@ -1765,7 +1765,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MISC) != 0) { ahc_print_path(ahc, scb); - printf("Set CAM_UNCOR_PARITY\n"); + printk("Set CAM_UNCOR_PARITY\n"); } #endif ahc_set_transaction_status(scb, CAM_UNCOR_PARITY); @@ -1783,12 +1783,12 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) u_int i; ahc_print_path(ahc, scb); - printf("CDB:"); + printk("CDB:"); for (i = 0; i < scb->io_ctx->cmd_len; i++) - printf(" 0x%x", scb->io_ctx->cmnd[i]); - printf("\n"); + printk(" 0x%x", scb->io_ctx->cmnd[i]); + printk("\n"); ahc_print_path(ahc, scb); - printf("Saw underflow (%ld of %ld bytes). " + printk("Saw underflow (%ld of %ld bytes). " "Treated as error\n", ahc_get_residual(scb), ahc_get_transfer_length(scb)); @@ -1821,7 +1821,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) dev->commands_since_idle_or_otag = 0; if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printf("Recovery SCB completes\n"); + printk("Recovery SCB completes\n"); if (ahc_get_transaction_status(scb) == CAM_BDR_SENT || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED) ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); @@ -1886,14 +1886,14 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, if (ahc_debug & AHC_SHOW_SENSE) { int i; - printf("Copied %d bytes of sense data:", + printk("Copied %d bytes of sense data:", sense_size); for (i = 0; i < sense_size; i++) { if ((i & 0xF) == 0) - printf("\n"); - printf("0x%x ", cmd->sense_buffer[i]); + printk("\n"); + printk("0x%x ", cmd->sense_buffer[i]); } - printf("\n"); + printk("\n"); } #endif } @@ -1918,7 +1918,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, dev->openings = 0; /* ahc_print_path(ahc, scb); - printf("Dropping tag count to %d\n", dev->active); + printk("Dropping tag count to %d\n", dev->active); */ if (dev->active == dev->tags_on_last_queuefull) { @@ -1935,7 +1935,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, == AHC_LOCK_TAGS_COUNT) { dev->maxtags = dev->active; ahc_print_path(ahc, scb); - printf("Locking max tag count at %d\n", + printk("Locking max tag count at %d\n", dev->active); } } else { @@ -2100,10 +2100,10 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n", flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); - printf("CDB:"); + printk("CDB:"); for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printf(" 0x%x", cmd->cmnd[cdb_byte]); - printf("\n"); + printk(" 0x%x", cmd->cmnd[cdb_byte]); + printk("\n"); ahc_lock(ahc, &flags); @@ -2121,7 +2121,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) * No target device for this command exists, * so we must not still own the command. */ - printf("%s:%d:%d:%d: Is not an active device\n", + printk("%s:%d:%d:%d: Is not an active device\n", ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun); retval = SUCCESS; @@ -2133,7 +2133,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) cmd->device->channel + 'A', cmd->device->lun, CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) { - printf("%s:%d:%d:%d: Command found on untagged queue\n", + printk("%s:%d:%d:%d: Command found on untagged queue\n", ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun); retval = SUCCESS; @@ -2187,7 +2187,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) goto no_cmd; } - printf("%s: At time of recovery, card was %spaused\n", + printk("%s: At time of recovery, card was %spaused\n", ahc_name(ahc), was_paused ? "" : "not "); ahc_dump_card_state(ahc); @@ -2199,7 +2199,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) pending_scb->hscb->tag, ROLE_INITIATOR, CAM_REQ_ABORTED, SEARCH_COMPLETE) > 0) { - printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun); retval = SUCCESS; @@ -2313,7 +2313,7 @@ ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) ahc_qinfifo_requeue_tail(ahc, pending_scb); ahc_outb(ahc, SCBPTR, saved_scbptr); ahc_print_path(ahc, pending_scb); - printf("Device is disconnected, re-queuing SCB\n"); + printk("Device is disconnected, re-queuing SCB\n"); wait = TRUE; } else { scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n"); @@ -2338,16 +2338,16 @@ done: ahc->platform_data->eh_done = &done; ahc_unlock(ahc, &flags); - printf("Recovery code sleeping\n"); + printk("Recovery code sleeping\n"); if (!wait_for_completion_timeout(&done, 5 * HZ)) { ahc_lock(ahc, &flags); ahc->platform_data->eh_done = NULL; ahc_unlock(ahc, &flags); - printf("Timer Expired\n"); + printk("Timer Expired\n"); retval = FAILED; } - printf("Recovery code awake\n"); + printk("Recovery code awake\n"); } else ahc_unlock(ahc, &flags); return (retval); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 56f07e527b4..bca0fb83f55 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -368,13 +368,6 @@ struct ahc_platform_data { resource_size_t mem_busaddr; /* Mem Base Addr */ }; -/************************** OS Utility Wrappers *******************************/ -#define printf printk -#define M_NOWAIT GFP_ATOMIC -#define M_WAITOK 0 -#define malloc(size, type, flags) kmalloc(size, flags) -#define free(ptr, type) kfree(ptr) - void ahc_delay(long); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 78fc70c24e0..ee05e841075 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -225,7 +225,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_get_pci_bus(pci), ahc_get_pci_slot(pci), ahc_get_pci_function(pci)); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); if (name == NULL) return (-ENOMEM); strcpy(name, buf); @@ -412,7 +412,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc) */ if (ahc_pci_test_register_access(ahc) != 0) { - printf("aic7xxx: PCI Device %d:%d:%d " + printk("aic7xxx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), @@ -425,7 +425,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc) } else command |= PCIM_CMD_MEMEN; } else { - printf("aic7xxx: PCI%d:%d:%d MEM region 0x%llx " + printk("aic7xxx: PCI%d:%d:%d MEM region 0x%llx " "unavailable. Cannot memory map device.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), @@ -444,7 +444,7 @@ ahc_pci_map_registers(struct ahc_softc *ahc) ahc->bsh.ioport = (u_long)base; command |= PCIM_CMD_PORTEN; } else { - printf("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] " + printk("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] " "unavailable. Cannot map device.\n", ahc_get_pci_bus(ahc->dev_softc), ahc_get_pci_slot(ahc->dev_softc), diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 27014b9de12..2b11a427236 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -752,7 +752,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { if (bootverbose) - printf("%s: Enabling 39Bit Addressing\n", + printk("%s: Enabling 39Bit Addressing\n", ahc_name(ahc)); devconfig |= DACEN; } @@ -896,7 +896,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) /* See if someone else set us up already */ if ((ahc->flags & AHC_NO_BIOS_INIT) == 0 && scsiseq != 0) { - printf("%s: Using left over BIOS settings\n", + printk("%s: Using left over BIOS settings\n", ahc_name(ahc)); ahc->flags &= ~AHC_USEDEFAULTS; ahc->flags |= AHC_BIOS_ENABLED; @@ -1155,7 +1155,7 @@ done: ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, CLRINT, CLRBRKADRINT); if (bootverbose && enable) { - printf("%s: External SRAM, %s access%s, %dbytes/SCB\n", + printk("%s: External SRAM, %s access%s, %dbytes/SCB\n", ahc_name(ahc), fast ? "fast" : "slow", pcheck ? ", parity checking enabled" : "", large ? 64 : 32); @@ -1292,7 +1292,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) if (have_seeprom) { if (bootverbose) - printf("%s: Reading SEEPROM...", ahc_name(ahc)); + printk("%s: Reading SEEPROM...", ahc_name(ahc)); for (;;) { u_int start_addr; @@ -1309,9 +1309,9 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) if (have_seeprom != 0 || sd.sd_chip == C56_66) { if (bootverbose) { if (have_seeprom == 0) - printf ("checksum error\n"); + printk ("checksum error\n"); else - printf ("done.\n"); + printk ("done.\n"); } break; } @@ -1362,9 +1362,9 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) if (!have_seeprom) { if (bootverbose) - printf("%s: No SEEPROM available.\n", ahc_name(ahc)); + printk("%s: No SEEPROM available.\n", ahc_name(ahc)); ahc->flags |= AHC_USEDEFAULTS; - free(ahc->seep_config, M_DEVBUF); + kfree(ahc->seep_config); ahc->seep_config = NULL; sc = NULL; } else { @@ -1399,7 +1399,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) if ((sc->adapter_control & CFSTERM) != 0) *sxfrctl1 |= STPWEN; if (bootverbose) - printf("%s: Low byte termination %sabled\n", + printk("%s: Low byte termination %sabled\n", ahc_name(ahc), (*sxfrctl1 & STPWEN) ? "en" : "dis"); } @@ -1569,7 +1569,7 @@ configure_termination(struct ahc_softc *ahc, &eeprom_present); if ((adapter_control & CFSEAUTOTERM) == 0) { if (bootverbose) - printf("%s: Manual SE Termination\n", + printk("%s: Manual SE Termination\n", ahc_name(ahc)); enableSEC_low = (adapter_control & CFSELOWTERM); enableSEC_high = @@ -1577,7 +1577,7 @@ configure_termination(struct ahc_softc *ahc, } if ((adapter_control & CFAUTOTERM) == 0) { if (bootverbose) - printf("%s: Manual LVD Termination\n", + printk("%s: Manual LVD Termination\n", ahc_name(ahc)); enablePRI_low = (adapter_control & CFSTERM); enablePRI_high = (adapter_control & CFWSTERM); @@ -1604,19 +1604,19 @@ configure_termination(struct ahc_softc *ahc, if (bootverbose && (ahc->features & AHC_ULTRA2) == 0) { - printf("%s: internal 50 cable %s present", + printk("%s: internal 50 cable %s present", ahc_name(ahc), internal50_present ? "is":"not"); if ((ahc->features & AHC_WIDE) != 0) - printf(", internal 68 cable %s present", + printk(", internal 68 cable %s present", internal68_present ? "is":"not"); - printf("\n%s: external cable %s present\n", + printk("\n%s: external cable %s present\n", ahc_name(ahc), externalcable_present ? "is":"not"); } if (bootverbose) - printf("%s: BIOS eeprom %s present\n", + printk("%s: BIOS eeprom %s present\n", ahc_name(ahc), eeprom_present ? "is" : "not"); if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { @@ -1642,7 +1642,7 @@ configure_termination(struct ahc_softc *ahc, && (internal50_present != 0) && (internal68_present != 0) && (externalcable_present != 0)) { - printf("%s: Illegal cable configuration!!. " + printk("%s: Illegal cable configuration!!. " "Only two connectors on the " "adapter may be used at a " "time!\n", ahc_name(ahc)); @@ -1664,10 +1664,10 @@ configure_termination(struct ahc_softc *ahc, brddat |= BRDDAT6; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printf("%s: 68 pin termination " + printk("%s: 68 pin termination " "Enabled\n", ahc_name(ahc)); else - printf("%s: %sHigh byte termination " + printk("%s: %sHigh byte termination " "Enabled\n", ahc_name(ahc), enableSEC_high ? "Secondary " : ""); @@ -1683,10 +1683,10 @@ configure_termination(struct ahc_softc *ahc, *sxfrctl1 |= STPWEN; if (bootverbose) { if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printf("%s: 50 pin termination " + printk("%s: 50 pin termination " "Enabled\n", ahc_name(ahc)); else - printf("%s: %sLow byte termination " + printk("%s: %sLow byte termination " "Enabled\n", ahc_name(ahc), enableSEC_low ? "Secondary " : ""); @@ -1696,7 +1696,7 @@ configure_termination(struct ahc_softc *ahc, if (enablePRI_low != 0) { *sxfrctl1 |= STPWEN; if (bootverbose) - printf("%s: Primary Low Byte termination " + printk("%s: Primary Low Byte termination " "Enabled\n", ahc_name(ahc)); } @@ -1709,7 +1709,7 @@ configure_termination(struct ahc_softc *ahc, if (enablePRI_high != 0) { brddat |= BRDDAT4; if (bootverbose) - printf("%s: Primary High Byte " + printk("%s: Primary High Byte " "termination Enabled\n", ahc_name(ahc)); } @@ -1721,7 +1721,7 @@ configure_termination(struct ahc_softc *ahc, *sxfrctl1 |= STPWEN; if (bootverbose) - printf("%s: %sLow byte termination Enabled\n", + printk("%s: %sLow byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Primary " : ""); @@ -1731,7 +1731,7 @@ configure_termination(struct ahc_softc *ahc, && (ahc->features & AHC_WIDE) != 0) { brddat |= BRDDAT6; if (bootverbose) - printf("%s: %sHigh byte termination Enabled\n", + printk("%s: %sHigh byte termination Enabled\n", ahc_name(ahc), (ahc->features & AHC_ULTRA2) ? "Secondary " : ""); @@ -1937,29 +1937,29 @@ ahc_pci_intr(struct ahc_softc *ahc) status1 = ahc_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, /*bytes*/1); - printf("%s: PCI error Interrupt at seqaddr = 0x%x\n", + printk("%s: PCI error Interrupt at seqaddr = 0x%x\n", ahc_name(ahc), ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); if (status1 & DPE) { ahc->pci_target_perr_count++; - printf("%s: Data Parity Error Detected during address " + printk("%s: Data Parity Error Detected during address " "or write data phase\n", ahc_name(ahc)); } if (status1 & SSE) { - printf("%s: Signal System Error Detected\n", ahc_name(ahc)); + printk("%s: Signal System Error Detected\n", ahc_name(ahc)); } if (status1 & RMA) { - printf("%s: Received a Master Abort\n", ahc_name(ahc)); + printk("%s: Received a Master Abort\n", ahc_name(ahc)); } if (status1 & RTA) { - printf("%s: Received a Target Abort\n", ahc_name(ahc)); + printk("%s: Received a Target Abort\n", ahc_name(ahc)); } if (status1 & STA) { - printf("%s: Signaled a Target Abort\n", ahc_name(ahc)); + printk("%s: Signaled a Target Abort\n", ahc_name(ahc)); } if (status1 & DPR) { - printf("%s: Data Parity Error has been reported via PERR#\n", + printk("%s: Data Parity Error has been reported via PERR#\n", ahc_name(ahc)); } @@ -1968,14 +1968,14 @@ ahc_pci_intr(struct ahc_softc *ahc) status1, /*bytes*/1); if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) { - printf("%s: Latched PCIERR interrupt with " + printk("%s: Latched PCIERR interrupt with " "no status bits set\n", ahc_name(ahc)); } else { ahc_outb(ahc, CLRINT, CLRPARERR); } if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) { - printf( + printk( "%s: WARNING WARNING WARNING WARNING\n" "%s: Too many PCI parity errors observed as a target.\n" "%s: Some device on this bus is generating bad parity.\n" @@ -2386,7 +2386,7 @@ ahc_aha29160C_setup(struct ahc_softc *ahc) static int ahc_raid_setup(struct ahc_softc *ahc) { - printf("RAID functionality unsupported\n"); + printk("RAID functionality unsupported\n"); return (ENXIO); } @@ -2404,7 +2404,7 @@ ahc_aha394XX_setup(struct ahc_softc *ahc) ahc->channel = 'B'; break; default: - printf("adapter at unexpected slot %d\n" + printk("adapter at unexpected slot %d\n" "unable to map to a channel\n", ahc_get_pci_slot(pci)); ahc->channel = 'A'; @@ -2429,7 +2429,7 @@ ahc_aha398XX_setup(struct ahc_softc *ahc) ahc->channel = 'C'; break; default: - printf("adapter at unexpected slot %d\n" + printk("adapter at unexpected slot %d\n" "unable to map to a channel\n", ahc_get_pci_slot(pci)); ahc->channel = 'A'; @@ -2459,7 +2459,7 @@ ahc_aha494XX_setup(struct ahc_softc *ahc) ahc->channel = 'D'; break; default: - printf("adapter at unexpected slot %d\n" + printk("adapter at unexpected slot %d\n" "unable to map to a channel\n", ahc_get_pci_slot(pci)); ahc->channel = 'A'; diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index e92991a7c48..f2525f8ed1c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -248,13 +248,13 @@ ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length) ahc_pause(ahc); if (length != sizeof(struct seeprom_config)) { - printf("ahc_proc_write_seeprom: incorrect buffer size\n"); + printk("ahc_proc_write_seeprom: incorrect buffer size\n"); goto done; } have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer); if (have_seeprom == 0) { - printf("ahc_proc_write_seeprom: cksum verification failed\n"); + printk("ahc_proc_write_seeprom: cksum verification failed\n"); goto done; } @@ -290,26 +290,25 @@ ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length) sd.sd_DI = DI_2840; have_seeprom = TRUE; } else { - printf("ahc_proc_write_seeprom: unsupported adapter type\n"); + printk("ahc_proc_write_seeprom: unsupported adapter type\n"); goto done; } if (!have_seeprom) { - printf("ahc_proc_write_seeprom: No Serial EEPROM\n"); + printk("ahc_proc_write_seeprom: No Serial EEPROM\n"); goto done; } else { u_int start_addr; if (ahc->seep_config == NULL) { - ahc->seep_config = malloc(sizeof(*ahc->seep_config), - M_DEVBUF, M_NOWAIT); + ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC); if (ahc->seep_config == NULL) { - printf("aic7xxx: Unable to allocate serial " + printk("aic7xxx: Unable to allocate serial " "eeprom buffer. Write failing\n"); goto done; } } - printf("aic7xxx: Writing Serial EEPROM\n"); + printk("aic7xxx: Writing Serial EEPROM\n"); start_addr = 32 * (ahc->channel - 'A'); ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr, sizeof(struct seeprom_config)/2); -- cgit v1.2.3-70-g09d2 From bbe56c734cc1ecccd7b2b143e1767bf2b1eafc76 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 27 Jul 2010 12:30:24 -0500 Subject: [SCSI] arcmsr: fix up bin_attr functions Commit commit 2c3c8bea608866d8bd9dcf92657d57fdcac011c5 Author: Chris Wright Date: Wed May 12 18:28:57 2010 -0700 sysfs: add struct file* to bin_attr callbacks Added an extra struct file * parameter at the beginning, which the arcmsr binary attribute additions didn't have. Fix this to prevent nasty crashes. Cc: Nick Cheng Signed-off-by: James Bottomley --- drivers/scsi/arcmsr/arcmsr_attr.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 69f8346aa28..07fdfe57e38 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -59,7 +59,8 @@ struct device_attribute *arcmsr_host_attrs[]; -static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, + struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -105,7 +106,8 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, return (allxfer_len); } -static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, + struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -153,7 +155,8 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, } } -static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, + struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) -- cgit v1.2.3-70-g09d2 From 457ff3b7dc3796d8778286217ad304ff122e948f Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:16:00 +0530 Subject: [SCSI] be2iscsi: Fix warnings from new checkpatch.pl The latest checkpatch.pl throws some new warnings. Fixing it to get rid of a bunch of warnings Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be.h | 6 +- drivers/scsi/be2iscsi/be_cmds.c | 24 +++---- drivers/scsi/be2iscsi/be_cmds.h | 20 +++--- drivers/scsi/be2iscsi/be_iscsi.c | 32 ++++----- drivers/scsi/be2iscsi/be_main.c | 141 ++++++++++++++++++++------------------- drivers/scsi/be2iscsi/be_main.h | 20 +++--- drivers/scsi/be2iscsi/be_mgmt.c | 6 +- 7 files changed, 126 insertions(+), 123 deletions(-) diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 136b49cea79..1cb8a5e85c7 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -128,8 +128,8 @@ struct be_ctrl_info { #define mcc_timeout 120000 /* 5s timeout */ /* Returns number of pages spanned by the data starting at the given addr */ -#define PAGES_4K_SPANNED(_address, size) \ - ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ +#define PAGES_4K_SPANNED(_address, size) \ + ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) /* Byte offset into the page corresponding to given address */ @@ -137,7 +137,7 @@ struct be_ctrl_info { ((size_t)(addr) & (PAGE_SIZE_4K-1)) /* Returns bit offset within a DWORD of a bitfield */ -#define AMAP_BIT_OFFSET(_struct, field) \ +#define AMAP_BIT_OFFSET(_struct, field) \ (((size_t)&(((_struct *)0)->field))%32) /* Returns the bit mask of the field that is NOT shifted into location. */ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index cda6642c736..4f19030c1e3 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -151,20 +151,20 @@ void beiscsi_async_link_state_process(struct beiscsi_hba *phba, { switch (evt->port_link_status) { case ASYNC_EVENT_LINK_DOWN: - SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d \n", - evt->physical_port); + SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d\n", + evt->physical_port); phba->state |= BE_ADAPTER_LINK_DOWN; iscsi_host_for_each_session(phba->shost, be2iscsi_fail_session); break; case ASYNC_EVENT_LINK_UP: phba->state = BE_ADAPTER_UP; - SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d \n", + SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d\n", evt->physical_port); break; default: SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" - "Physical Port %d \n", + "Physical Port %d\n", evt->port_link_status, evt->physical_port); } @@ -199,7 +199,7 @@ int beiscsi_process_mcc(struct beiscsi_hba *phba) else SE_DEBUG(DBG_LVL_1, " Unsupported Async Event, flags" - " = 0x%08x \n", compl->flags); + " = 0x%08x\n", compl->flags); } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { status = be_mcc_compl_process(ctrl, compl); @@ -286,7 +286,7 @@ int be_mbox_notify(struct be_ctrl_info *ctrl) status = be_mbox_db_ready_wait(ctrl); if (status != 0) { - SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n"); + SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n"); return status; } val = 0; @@ -297,14 +297,14 @@ int be_mbox_notify(struct be_ctrl_info *ctrl) status = be_mbox_db_ready_wait(ctrl); if (status != 0) { - SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n"); + SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n"); return status; } if (be_mcc_compl_is_new(compl)) { status = be_mcc_compl_process(ctrl, &mbox->compl); be_mcc_compl_use(compl); if (status) { - SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n"); + SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process\n"); return status; } } else { @@ -500,7 +500,7 @@ int be_cmd_fw_initialize(struct be_ctrl_info *ctrl) status = be_mbox_notify(ctrl); if (status) - SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n"); + SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed\n"); spin_unlock(&ctrl->mbox_lock); return status; @@ -517,7 +517,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, void *ctxt = &req->context; int status; - SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create \n"); + SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create\n"); spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); @@ -550,7 +550,7 @@ int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, cq->id = le16_to_cpu(resp->cq_id); cq->created = true; } else - SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n", + SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x\n", status); spin_unlock(&ctrl->mbox_lock); @@ -619,7 +619,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, u8 subsys = 0, opcode = 0; int status; - SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy \n"); + SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy\n"); spin_lock(&ctrl->mbox_lock); memset(wrb, 0, sizeof(*wrb)); be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 49fcc787ee8..f94df6cdebc 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -47,8 +47,8 @@ struct be_mcc_wrb { #define CQE_FLAGS_VALID_MASK (1 << 31) #define CQE_FLAGS_ASYNC_MASK (1 << 30) -#define CQE_FLAGS_COMPLETED_MASK (1 << 28) -#define CQE_FLAGS_CONSUMED_MASK (1 << 27) +#define CQE_FLAGS_COMPLETED_MASK (1 << 28) +#define CQE_FLAGS_CONSUMED_MASK (1 << 27) /* Completion Status */ #define MCC_STATUS_SUCCESS 0x0 @@ -143,14 +143,14 @@ struct be_mcc_mailbox { */ #define OPCODE_COMMON_CQ_CREATE 12 #define OPCODE_COMMON_EQ_CREATE 13 -#define OPCODE_COMMON_MCC_CREATE 21 -#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32 +#define OPCODE_COMMON_MCC_CREATE 21 +#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32 #define OPCODE_COMMON_GET_FW_VERSION 35 #define OPCODE_COMMON_MODIFY_EQ_DELAY 41 #define OPCODE_COMMON_FIRMWARE_CONFIG 42 -#define OPCODE_COMMON_MCC_DESTROY 53 -#define OPCODE_COMMON_CQ_DESTROY 54 -#define OPCODE_COMMON_EQ_DESTROY 55 +#define OPCODE_COMMON_MCC_DESTROY 53 +#define OPCODE_COMMON_CQ_DESTROY 54 +#define OPCODE_COMMON_EQ_DESTROY 55 #define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 #define OPCODE_COMMON_FUNCTION_RESET 61 @@ -164,9 +164,9 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7 #define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61 #define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64 -#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65 +#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65 #define OPCODE_COMMON_ISCSI_WRBQ_CREATE 66 -#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67 +#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67 struct be_cmd_req_hdr { u8 opcode; /* dword 0 */ @@ -875,7 +875,7 @@ struct be_fw_cfg { */ #define UNSOL_HDR_NOTIFY 28 /* Unsolicited header notify.*/ #define UNSOL_DATA_NOTIFY 29 /* Unsolicited data notify.*/ -#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest +#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest * error notify. */ #define DRIVERMSG_NOTIFY 31 /* TCP acknowledge based diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 454027ccbf1..d9321ee0153 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -52,7 +52,7 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n"); if (!ep) { - SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n"); + SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep\n"); return NULL; } beiscsi_ep = ep->dd_data; @@ -157,7 +157,7 @@ static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, "Connection table already occupied. Detected clash\n"); return -EINVAL; } else { - SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n", + SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn)\n", cid, beiscsi_conn); phba->conn_table[cid] = beiscsi_conn; } @@ -196,7 +196,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, if (beiscsi_ep->phba != phba) { SE_DEBUG(DBG_LVL_8, - "beiscsi_ep->hba=%p not equal to phba=%p \n", + "beiscsi_ep->hba=%p not equal to phba=%p\n", beiscsi_ep->phba, phba); return -EEXIST; } @@ -204,7 +204,7 @@ int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; beiscsi_conn->ep = beiscsi_ep; beiscsi_ep->conn = beiscsi_conn; - SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n", + SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d\n", beiscsi_conn, conn, beiscsi_ep->ep_cid); return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); } @@ -308,7 +308,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, case ISCSI_HOST_PARAM_HWADDRESS: tag = be_cmd_get_mac_addr(phba); if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed \n"); + SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); return -1; } else wait_event_interruptible(phba->ctrl.mcc_wait[tag], @@ -319,7 +319,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; if (status || extd_status) { SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" - " status = %d extd_status = %d \n", + " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); return -1; @@ -493,7 +493,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, SE_DEBUG(DBG_LVL_1, "No free cid available\n"); return ret; } - SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ", + SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n", beiscsi_ep->ep_cid); phba->ep_array[beiscsi_ep->ep_cid - phba->fw_config.iscsi_cid_start] = ep; @@ -507,7 +507,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep); if (!tag) { SE_DEBUG(DBG_LVL_1, - "mgmt_open_connection Failed for cid=%d \n", + "mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], @@ -526,7 +526,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); - ptcpcnct_out = embedded_payload(wrb); + ptcpcnct_out = embedded_payload(wrb); beiscsi_ep = ep->dd_data; beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; beiscsi_ep->cid_vld = 1; @@ -556,18 +556,18 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, struct iscsi_endpoint *ep; int ret; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n"); + SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect\n"); if (shost) phba = iscsi_host_priv(shost); else { ret = -ENXIO; - SE_DEBUG(DBG_LVL_1, "shost is NULL \n"); + SE_DEBUG(DBG_LVL_1, "shost is NULL\n"); return ERR_PTR(ret); } if (phba->state != BE_ADAPTER_UP) { ret = -EBUSY; - SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP \n"); + SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP\n"); return ERR_PTR(ret); } @@ -581,7 +581,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep->phba = phba; beiscsi_ep->openiscsi_ep = ep; if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { - SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn \n"); + SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n"); ret = -ENOMEM; goto free_ep; } @@ -624,7 +624,7 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); if (!tag) { - SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x", + SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n", beiscsi_ep->ep_cid); ret = -1; } else { @@ -646,7 +646,7 @@ static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, if (phba->conn_table[cid]) phba->conn_table[cid] = NULL; else { - SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n"); + SE_DEBUG(DBG_LVL_8, "Connection table Not occupied.\n"); return -EINVAL; } return 0; @@ -687,7 +687,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) savecfg_flag); if (!tag) { SE_DEBUG(DBG_LVL_1, - "mgmt_invalidate_connection Failed for cid=%d \n", + "mgmt_invalidate_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 0d35bf6c6ac..001888b0c84 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -216,7 +216,7 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0); if (!shost) { dev_err(&pcidev->dev, "beiscsi_hba_alloc -" - "iscsi_host_alloc failed \n"); + "iscsi_host_alloc failed\n"); return NULL; } shost->dma_boundary = pcidev->dma_mask; @@ -371,7 +371,7 @@ static void beiscsi_get_params(struct beiscsi_hba *phba) + BE2_TMFS) / 512) + 1) * 512; phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) ? 1024 : phba->params.num_eq_entries; - SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n", + SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d\n", phba->params.num_eq_entries); phba->params.num_cq_entries = (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 @@ -692,7 +692,7 @@ beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, break; default: shost_printk(KERN_WARNING, phba->shost, - "Unrecognized opcode 0x%x in async msg \n", + "Unrecognized opcode 0x%x in async msg\n", (ppdu-> dw[offsetof(struct amap_pdu_base, opcode) / 32] & PDUBASE_OPCODE_MASK)); @@ -711,7 +711,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) if (phba->io_sgl_hndl_avbl) { SE_DEBUG(DBG_LVL_8, - "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n", + "In alloc_io_sgl_handle,io_sgl_alloc_index=%d\n", phba->io_sgl_alloc_index); psgl_handle = phba->io_sgl_hndl_base[phba-> io_sgl_alloc_index]; @@ -730,7 +730,7 @@ static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) static void free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) { - SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n", + SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d\n", phba->io_sgl_free_index); if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) { /* @@ -739,7 +739,7 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) */ SE_DEBUG(DBG_LVL_8, "Double Free in IO SGL io_sgl_free_index=%d," - "value there=%p \n", phba->io_sgl_free_index, + "value there=%p\n", phba->io_sgl_free_index, phba->io_sgl_hndl_base[phba->io_sgl_free_index]); return; } @@ -804,7 +804,7 @@ free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, SE_DEBUG(DBG_LVL_8, "FREE WRB: pwrb_handle=%p free_index=0x%x" - "wrb_handles_available=%d \n", + "wrb_handles_available=%d\n", pwrb_handle, pwrb_context->free_index, pwrb_context->wrb_handles_available); } @@ -816,7 +816,7 @@ static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) if (phba->eh_sgl_hndl_avbl) { psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index]; phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL; - SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n", + SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x\n", phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index); phba->eh_sgl_hndl_avbl--; if (phba->eh_sgl_alloc_index == @@ -834,7 +834,7 @@ void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) { - SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d \n", + SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d\n", phba->eh_sgl_free_index); if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) { /* @@ -842,7 +842,7 @@ free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * failed in xmit_task or alloc_pdu. */ SE_DEBUG(DBG_LVL_8, - "Double Free in eh SGL ,eh_sgl_free_index=%d \n", + "Double Free in eh SGL ,eh_sgl_free_index=%d\n", phba->eh_sgl_free_index); return; } @@ -1081,7 +1081,7 @@ static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, case HWH_TYPE_LOGIN: SE_DEBUG(DBG_LVL_1, "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd" - "- Solicited path \n"); + "- Solicited path\n"); break; case HWH_TYPE_NOP: @@ -1164,7 +1164,7 @@ hwi_get_async_handle(struct beiscsi_hba *phba, default: pbusy_list = NULL; shost_printk(KERN_WARNING, phba->shost, - "Unexpected code=%d \n", + "Unexpected code=%d\n", pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32] & PDUCQE_CODE_MASK); return NULL; @@ -1552,7 +1552,7 @@ static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba) else SE_DEBUG(DBG_LVL_1, " Unsupported Async Event, flags" - " = 0x%08x \n", mcc_compl->flags); + " = 0x%08x\n", mcc_compl->flags); } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { be_mcc_compl_process_isr(&phba->ctrl, mcc_compl); atomic_dec(&phba->ctrl.mcc_obj.q.used); @@ -1611,7 +1611,7 @@ static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) hwi_complete_cmd(beiscsi_conn, phba, sol); break; case DRIVERMSG_NOTIFY: - SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n"); + SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY\n"); dmsg = (struct dmsg_cqe *)sol; hwi_complete_drvr_msgs(beiscsi_conn, phba, sol); break; @@ -1782,9 +1782,9 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, - (addr & 0xFFFFFFFF)); + ((u32)(addr & 0xFFFFFFFF))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, - (addr >> 32)); + ((u32)(addr >> 32))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, sg_len); sge_len = sg_len; @@ -1794,9 +1794,9 @@ hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, sg_len = sg_dma_len(sg); addr = (u64) sg_dma_address(sg); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb, - (addr & 0xFFFFFFFF)); + ((u32)(addr & 0xFFFFFFFF))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb, - (addr >> 32)); + ((u32)(addr >> 32))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb, sg_len); } @@ -1872,9 +1872,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) addr = 0; } AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, - (addr & 0xFFFFFFFF)); + ((u32)(addr & 0xFFFFFFFF))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, - (addr >> 32)); + ((u32)(addr >> 32))); AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, task->data_count); @@ -1904,9 +1904,9 @@ static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) psgl++; if (task->data) { AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, - (addr & 0xFFFFFFFF)); + ((u32)(addr & 0xFFFFFFFF))); AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, - (addr >> 32)); + ((u32)(addr >> 32))); } AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106); } @@ -2054,7 +2054,8 @@ free_mem: mem_descr->mem_array[j - 1].size, mem_descr->mem_array[j - 1]. virtual_address, - mem_descr->mem_array[j - 1]. + (unsigned long)mem_descr-> + mem_array[j - 1]. bus_address.u.a64.address); } if (i) { @@ -2223,10 +2224,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) if (mem_descr->mem_array[0].virtual_address) { SE_DEBUG(DBG_LVL_8, "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF" - "va=%p \n", mem_descr->mem_array[0].virtual_address); + "va=%p\n", mem_descr->mem_array[0].virtual_address); } else shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_header.va_base = mem_descr->mem_array[0].virtual_address; @@ -2239,10 +2240,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) if (mem_descr->mem_array[0].virtual_address) { SE_DEBUG(DBG_LVL_8, "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING" - "va=%p \n", mem_descr->mem_array[0].virtual_address); + "va=%p\n", mem_descr->mem_array[0].virtual_address); } else shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_header.ring_base = mem_descr->mem_array[0].virtual_address; @@ -2251,10 +2252,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) if (mem_descr->mem_array[0].virtual_address) { SE_DEBUG(DBG_LVL_8, "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE" - "va=%p \n", mem_descr->mem_array[0].virtual_address); + "va=%p\n", mem_descr->mem_array[0].virtual_address); } else shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_header.handle_base = mem_descr->mem_array[0].virtual_address; @@ -2266,10 +2267,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) if (mem_descr->mem_array[0].virtual_address) { SE_DEBUG(DBG_LVL_8, "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF" - "va=%p \n", mem_descr->mem_array[0].virtual_address); + "va=%p\n", mem_descr->mem_array[0].virtual_address); } else shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_data.va_base = mem_descr->mem_array[0].virtual_address; pasync_ctx->async_data.pa_base.u.a64.address = @@ -2280,10 +2281,10 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) if (mem_descr->mem_array[0].virtual_address) { SE_DEBUG(DBG_LVL_8, "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING" - "va=%p \n", mem_descr->mem_array[0].virtual_address); + "va=%p\n", mem_descr->mem_array[0].virtual_address); } else shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_data.ring_base = mem_descr->mem_array[0].virtual_address; @@ -2292,7 +2293,7 @@ static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) mem_descr += HWI_MEM_ASYNC_DATA_HANDLE; if (!mem_descr->mem_array[0].virtual_address) shost_printk(KERN_WARNING, phba->shost, - "No Virtual address \n"); + "No Virtual address\n"); pasync_ctx->async_data.handle_base = mem_descr->mem_array[0].virtual_address; @@ -2364,7 +2365,7 @@ be_sgl_create_contiguous(void *virtual_address, WARN_ON(!sgl); sgl->va = virtual_address; - sgl->dma = physical_address; + sgl->dma = (unsigned long)physical_address; sgl->size = length; return 0; @@ -2447,7 +2448,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, sizeof(struct be_eq_entry), eq_vaddress); if (ret) { shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for EQ \n"); + "be_fill_queue Failed for EQ\n"); goto create_eq_error; } @@ -2457,7 +2458,7 @@ static int beiscsi_create_eqs(struct beiscsi_hba *phba, if (ret) { shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create" - "Failedfor EQ \n"); + "Failedfor EQ\n"); goto create_eq_error; } SE_DEBUG(DBG_LVL_8, "eqid = %d\n", phwi_context->be_eq[i].q.id); @@ -2505,7 +2506,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, sizeof(struct sol_cqe), cq_vaddress); if (ret) { shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for ISCSI CQ \n"); + "be_fill_queue Failed for ISCSI CQ\n"); goto create_cq_error; } @@ -2515,7 +2516,7 @@ static int beiscsi_create_cqs(struct beiscsi_hba *phba, if (ret) { shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create" - "Failed for ISCSI CQ \n"); + "Failed for ISCSI CQ\n"); goto create_cq_error; } SE_DEBUG(DBG_LVL_8, "iscsi cq_id is %d for eq_id %d\n", @@ -2565,7 +2566,8 @@ beiscsi_create_def_hdr(struct beiscsi_hba *phba, "be_fill_queue Failed for DEF PDU HDR\n"); return ret; } - mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; + mem->dma = (unsigned long)mem_descr->mem_array[idx]. + bus_address.u.a64.address; ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq, def_pdu_ring_sz, phba->params.defpdu_hdr_sz); @@ -2609,7 +2611,8 @@ beiscsi_create_def_data(struct beiscsi_hba *phba, "be_fill_queue Failed for DEF PDU DATA\n"); return ret; } - mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address; + mem->dma = (unsigned long)mem_descr->mem_array[idx]. + bus_address.u.a64.address; ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq, def_pdu_ring_sz, phba->params.defpdu_data_sz); @@ -2623,7 +2626,7 @@ beiscsi_create_def_data(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n", phwi_context->be_def_dataq.id); hwi_post_async_buffers(phba, 0); - SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n"); + SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED\n"); return 0; } @@ -2655,7 +2658,7 @@ beiscsi_post_pages(struct beiscsi_hba *phba) } pm_arr++; } - SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n"); + SE_DEBUG(DBG_LVL_8, "POSTED PAGES\n"); return 0; } @@ -2885,7 +2888,7 @@ static int find_num_cpus(void) if (num_cpus >= MAX_CPUS) num_cpus = MAX_CPUS - 1; - SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", num_cpus); + SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", num_cpus); return num_cpus; } @@ -2908,7 +2911,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) status = beiscsi_create_eqs(phba, phwi_context); if (status != 0) { - shost_printk(KERN_ERR, phba->shost, "EQ not created \n"); + shost_printk(KERN_ERR, phba->shost, "EQ not created\n"); goto error; } @@ -2919,7 +2922,7 @@ static int hwi_init_port(struct beiscsi_hba *phba) status = mgmt_check_supported_fw(ctrl, phba); if (status != 0) { shost_printk(KERN_ERR, phba->shost, - "Unsupported fw version \n"); + "Unsupported fw version\n"); goto error; } @@ -2975,7 +2978,7 @@ static int hwi_init_controller(struct beiscsi_hba *phba) if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) { phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba-> init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address; - SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n", + SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p\n", phwi_ctrlr->phwi_ctxt); } else { shost_printk(KERN_ERR, phba->shost, @@ -3008,8 +3011,8 @@ static void beiscsi_free_mem(struct beiscsi_hba *phba) pci_free_consistent(phba->pcidev, mem_descr->mem_array[j - 1].size, mem_descr->mem_array[j - 1].virtual_address, - mem_descr->mem_array[j - 1].bus_address. - u.a64.address); + (unsigned long)mem_descr->mem_array[j - 1]. + bus_address.u.a64.address); } kfree(mem_descr->mem_array); mem_descr++; @@ -3025,7 +3028,7 @@ static int beiscsi_init_controller(struct beiscsi_hba *phba) ret = beiscsi_get_memory(phba); if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -" - "Failed in beiscsi_alloc_memory \n"); + "Failed in beiscsi_alloc_memory\n"); return ret; } @@ -3102,12 +3105,12 @@ static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) } SE_DEBUG(DBG_LVL_8, "phba->io_sgl_hndl_avbl=%d" - "phba->eh_sgl_hndl_avbl=%d \n", + "phba->eh_sgl_hndl_avbl=%d\n", phba->io_sgl_hndl_avbl, phba->eh_sgl_hndl_avbl); mem_descr_sg = phba->init_mem; mem_descr_sg += HWI_MEM_SGE; - SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n", + SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d\n", mem_descr_sg->num_elements); arr_index = 0; idx = 0; @@ -3156,7 +3159,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) if (!phba->ep_array) { shost_printk(KERN_ERR, phba->shost, "Failed to allocate memory in " - "hba_setup_cid_tbls \n"); + "hba_setup_cid_tbls\n"); kfree(phba->cid_array); return -ENOMEM; } @@ -3185,21 +3188,21 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba) addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); reg = ioread32(addr); - SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg); + SE_DEBUG(DBG_LVL_8, "reg =x%08x\n", reg); enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; if (!enabled) { reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr); + SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr); iowrite32(reg, addr); if (!phba->msix_enabled) { eq = &phwi_context->be_eq[0].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id); + SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); } else { for (i = 0; i <= phba->num_cpus; i++) { eq = &phwi_context->be_eq[i].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id); + SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); } } @@ -3220,7 +3223,7 @@ static void hwi_disable_intr(struct beiscsi_hba *phba) iowrite32(reg, addr); } else shost_printk(KERN_WARNING, phba->shost, - "In hwi_disable_intr, Already Disabled \n"); + "In hwi_disable_intr, Already Disabled\n"); } static int beiscsi_init_port(struct beiscsi_hba *phba) @@ -3231,14 +3234,14 @@ static int beiscsi_init_port(struct beiscsi_hba *phba) if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe - Failed in" - "beiscsi_init_controller \n"); + "beiscsi_init_controller\n"); return ret; } ret = beiscsi_init_sgl_handle(phba); if (ret < 0) { shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe - Failed in" - "beiscsi_init_sgl_handle \n"); + "beiscsi_init_sgl_handle\n"); goto do_cleanup_ctrlr; } @@ -3297,7 +3300,7 @@ static void beiscsi_clean_port(struct beiscsi_hba *phba) mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0); if (mgmt_status) shost_printk(KERN_WARNING, phba->shost, - "mgmt_epfw_cleanup FAILED \n"); + "mgmt_epfw_cleanup FAILED\n"); hwi_purge_eq(phba); hwi_cleanup(phba); @@ -3487,7 +3490,7 @@ free_hndls: io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, io_task->bhs_pa.u.a64.address); - SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n"); + SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n"); return -ENOMEM; } @@ -3654,7 +3657,7 @@ static int beiscsi_mtask(struct iscsi_task *task) break; default: - SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n", + SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported\n", task->hdr->opcode & ISCSI_OPCODE_MASK); return -EINVAL; } @@ -3696,7 +3699,7 @@ static int beiscsi_task_xmit(struct iscsi_task *task) sg = scsi_sglist(sc); if (sc->sc_data_direction == DMA_TO_DEVICE) { writedir = 1; - SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n", + SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x\n", task->imm_count); } else writedir = 0; @@ -3713,7 +3716,7 @@ static void beiscsi_remove(struct pci_dev *pcidev) phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev); if (!phba) { - dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n"); + dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n"); return; } @@ -3782,7 +3785,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, phba = beiscsi_hba_alloc(pcidev); if (!phba) { dev_err(&pcidev->dev, "beiscsi_dev_probe-" - " Failed in beiscsi_hba_alloc \n"); + " Failed in beiscsi_hba_alloc\n"); goto disable_pci; } @@ -3805,7 +3808,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, else num_cpus = 1; phba->num_cpus = num_cpus; - SE_DEBUG(DBG_LVL_8, "num_cpus = %d \n", phba->num_cpus); + SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus); if (enable_msix) beiscsi_msix_enable(phba); @@ -3877,7 +3880,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, "Failed to hwi_enable_intr\n"); goto free_ctrlr; } - SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n"); + SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; free_ctrlr: @@ -3989,7 +3992,7 @@ static int __init beiscsi_module_init(void) "transport.\n"); return -ENOMEM; } - SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n", + SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p\n", &beiscsi_iscsi_transport); ret = pci_register_driver(&beiscsi_pci_driver); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 87ec21280a3..e6ddddbbae7 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -39,7 +39,7 @@ "Linux iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" -#define BE_VENDOR_ID 0x19A2 +#define BE_VENDOR_ID 0x19A2 /* DEVICE ID's for BE2 */ #define BE_DEVICE_ID1 0x212 #define OC_DEVICE_ID1 0x702 @@ -68,8 +68,8 @@ #define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */ #define BEISCSI_NUM_DEVICES_SUPPORTED 0x01 #define BEISCSI_MAX_FRAGS_INIT 192 -#define BE_NUM_MSIX_ENTRIES 1 -#define MPU_EP_SEMAPHORE 0xac +#define BE_NUM_MSIX_ENTRIES 1 +#define MPU_EP_SEMAPHORE 0xac #define BE_SENSE_INFO_SIZE 258 #define BE_ISCSI_PDU_HEADER_SIZE 64 @@ -105,7 +105,7 @@ do { \ #define HWI_GET_ASYNC_PDU_CTX(phwi) (phwi->phwi_ctxt->pasync_ctx) /********* Memory BAR register ************/ -#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc +#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc /** * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt * Disable" may still globally block interrupts in addition to individual @@ -116,7 +116,7 @@ do { \ #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ /********* ISR0 Register offset **********/ -#define CEV_ISR0_OFFSET 0xC18 +#define CEV_ISR0_OFFSET 0xC18 #define CEV_ISR_SIZE 4 /** @@ -139,12 +139,12 @@ do { \ #define DB_EQ_REARM_SHIFT (29) /* bit 29 */ /********* Compl Q door bell *************/ -#define DB_CQ_OFFSET 0x120 +#define DB_CQ_OFFSET 0x120 #define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ /* Number of event entries processed */ -#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ +#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ /* Rearm bit */ -#define DB_CQ_REARM_SHIFT (29) /* bit 29 */ +#define DB_CQ_REARM_SHIFT (29) /* bit 29 */ #define GET_HWI_CONTROLLER_WS(pc) (pc->phwi_ctrlr) #define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\ @@ -161,12 +161,12 @@ enum be_mem_enum { HWI_MEM_WRBH, HWI_MEM_SGLH, HWI_MEM_SGE, - HWI_MEM_ASYNC_HEADER_BUF, /* 5 */ + HWI_MEM_ASYNC_HEADER_BUF, /* 5 */ HWI_MEM_ASYNC_DATA_BUF, HWI_MEM_ASYNC_HEADER_RING, HWI_MEM_ASYNC_DATA_RING, HWI_MEM_ASYNC_HEADER_HANDLE, - HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */ + HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */ HWI_MEM_ASYNC_PDU_CONTEXT, ISCSI_MEM_GLOBAL_HEADER, SE_MEM_MAX diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 350cbeaae16..7d4ac5c1a86 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -58,7 +58,7 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, } } else { shost_printk(KERN_WARNING, phba->shost, - "Failed in mgmt_get_fw_config \n"); + "Failed in mgmt_get_fw_config\n"); } spin_unlock(&ctrl->mbox_lock); @@ -167,7 +167,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, &nonemb_cmd.dma); if (nonemb_cmd.va == NULL) { SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for mgmt_invalidate_icds\n"); + "Failed to alloc memory for mgmt_invalidate_icds\n"); spin_unlock(&ctrl->mbox_lock); return 0; } @@ -339,7 +339,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, if (phba->nxt_cqid == phba->num_cpus) phba->nxt_cqid = 0; req->cq_id = phwi_context->be_cq[i].id; - SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d \n", i, req->cq_id); + SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d\n", i, req->cq_id); req->defq_id = def_hdr_id; req->hdr_ring_id = def_hdr_id; req->data_ring_id = def_data_id; -- cgit v1.2.3-70-g09d2 From d3ad2bb31c26d7314fad98da8abb04f4fa24ed16 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:16:38 +0530 Subject: [SCSI] be2iscsi: Fixing return values This patch fixes the return values as per comment from Mike Christie Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.c | 12 ++++++------ drivers/scsi/be2iscsi/be_iscsi.c | 12 ++++++------ drivers/scsi/be2iscsi/be_main.c | 4 ++-- drivers/scsi/be2iscsi/be_mgmt.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 4f19030c1e3..9cc1f557315 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -98,7 +98,7 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, dev_err(&ctrl->pdev->dev, "error in cmd completion: status(compl/extd)=%d/%d\n", compl_status, extd_status); - return -1; + return -EBUSY; } return 0; } @@ -231,7 +231,7 @@ static int be_mcc_wait_compl(struct beiscsi_hba *phba) } if (i == mcc_timeout) { dev_err(&phba->pcidev->dev, "mccq poll timed out\n"); - return -1; + return -EBUSY; } return 0; } @@ -257,7 +257,7 @@ static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl) if (cnt > 6000000) { dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n"); - return -1; + return -EBUSY; } if (cnt > 50) { @@ -309,7 +309,7 @@ int be_mbox_notify(struct be_ctrl_info *ctrl) } } else { dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n"); - return -1; + return -EBUSY; } return 0; } @@ -355,7 +355,7 @@ static int be_mbox_notify_wait(struct beiscsi_hba *phba) return status; } else { dev_err(&phba->pcidev->dev, "invalid mailbox completion\n"); - return -1; + return -EBUSY; } return 0; } @@ -652,7 +652,7 @@ int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, default: spin_unlock(&ctrl->mbox_lock); BUG(); - return -1; + return -ENXIO; } be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); if (queue_type != QTYPE_SGL) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index d9321ee0153..cd1b8301036 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -230,7 +230,7 @@ int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, if (!beiscsi_ep) { SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_get_param , no beiscsi_ep\n"); - return -1; + return -ENODEV; } switch (param) { @@ -309,7 +309,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, tag = be_cmd_get_mac_addr(phba); if (!tag) { SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -1; + return -EAGAIN; } else wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); @@ -322,7 +322,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, " status = %d extd_status = %d\n", status, extd_status); free_mcc_tag(&phba->ctrl, tag); - return -1; + return -EAGAIN; } else { wrb = queue_get_wrb(mccq, wrb_num); free_mcc_tag(&phba->ctrl, tag); @@ -485,7 +485,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, struct tcp_connect_and_offload_out *ptcpcnct_out; unsigned short status, extd_status; unsigned int tag, wrb_num; - int ret = -1; + int ret = -ENOMEM; SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); beiscsi_ep->ep_cid = beiscsi_get_cid(phba); @@ -536,7 +536,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, free_ep: beiscsi_free_ep(beiscsi_ep); - return -1; + return -EBUSY; } /** @@ -626,7 +626,7 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) if (!tag) { SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n", beiscsi_ep->ep_cid); - ret = -1; + ret = -EAGAIN; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 001888b0c84..e6259d7498f 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -2681,7 +2681,7 @@ static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, mem->size = len * entry_size; mem->va = pci_alloc_consistent(phba->pcidev, mem->size, &mem->dma); if (!mem->va) - return -1; + return -ENOMEM; memset(mem->va, 0, mem->size); return 0; } @@ -2877,7 +2877,7 @@ mcc_cq_destroy: mcc_cq_free: be_queue_free(phba, cq); err: - return -1; + return -ENOMEM; } static int find_num_cpus(void) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 7d4ac5c1a86..ff8b1cd6fec 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -81,7 +81,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for mgmt_check_supported_fw" "\n"); - return -1; + return -ENOMEM; } nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); req = nonemb_cmd.va; -- cgit v1.2.3-70-g09d2 From 03a1231009927b7168d6d86a7a7f6c7f9b4be85a Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:17:16 +0530 Subject: [SCSI] be2iscsi: Fixing the return type of functions Fixing some functions return values that did not match with the possible return values Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.h | 2 +- drivers/scsi/be2iscsi/be_main.c | 2 +- drivers/scsi/be2iscsi/be_mgmt.c | 13 ++++++------- drivers/scsi/be2iscsi/be_mgmt.h | 10 +++++----- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index f94df6cdebc..30a293f52ef 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -423,7 +423,7 @@ int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, struct be_queue_info *cq); int be_poll_mcc(struct be_ctrl_info *ctrl); -unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, +int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index e6259d7498f..3b54dc72371 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3295,7 +3295,7 @@ static void hwi_purge_eq(struct beiscsi_hba *phba) static void beiscsi_clean_port(struct beiscsi_hba *phba) { - unsigned char mgmt_status; + int mgmt_status; mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0); if (mgmt_status) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ff8b1cd6fec..dcb70fac2fc 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -21,7 +21,7 @@ #include "be_mgmt.h" #include "be_iscsi.h" -unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, +int mgmt_get_fw_config(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba) { struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); @@ -65,7 +65,7 @@ unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, return status; } -unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, +int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba) { struct be_dma_mem nonemb_cmd; @@ -117,8 +117,7 @@ unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl, return status; } - -unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) +int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) { struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb = wrb_from_mccq(phba); @@ -144,7 +143,7 @@ unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) return status; } -unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, +unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, unsigned int num_invalidate, unsigned int cid) { @@ -202,7 +201,7 @@ unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, return tag; } -unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, +unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, unsigned short issue_reset, @@ -239,7 +238,7 @@ unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, return tag; } -unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, +unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag) { struct be_ctrl_info *ctrl = &phba->ctrl; diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 3d316b82feb..74b885a4b83 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -86,14 +86,14 @@ struct mcc_wrb { struct mcc_wrb_payload payload; }; -unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); +int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, struct beiscsi_endpoint *beiscsi_ep); -unsigned char mgmt_upload_connection(struct beiscsi_hba *phba, +unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag); -unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba, +unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, unsigned int num_invalidate, unsigned int cid); @@ -237,10 +237,10 @@ struct beiscsi_endpoint { u16 cid_vld; }; -unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl, +int mgmt_get_fw_config(struct be_ctrl_info *ctrl, struct beiscsi_hba *phba); -unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba, +unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, struct beiscsi_endpoint *beiscsi_ep, unsigned short cid, unsigned short issue_reset, -- cgit v1.2.3-70-g09d2 From f5ed7bd4c6ca5fcec77d3007779d38f63cbb95f4 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:18:01 +0530 Subject: [SCSI] be2iscsi: pass the return from beiscsi_open_conn This patch passes on the value returned by beiscsi_open_conn Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index cd1b8301036..4f3c2a4079d 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -580,9 +580,9 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, beiscsi_ep = ep->dd_data; beiscsi_ep->phba = phba; beiscsi_ep->openiscsi_ep = ep; - if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) { + ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking); + if (ret) { SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n"); - ret = -ENOMEM; goto free_ep; } -- cgit v1.2.3-70-g09d2 From 1f92638f074f7c6776fb2b565f252573f2b5488c Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:22:27 +0530 Subject: [SCSI] be2iscsi: Fix for freeing cid This patch frees up the allocated cid and returns error if allocation of tag fails. Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 4f3c2a4079d..de79b7cf804 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -509,6 +509,8 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + return -EAGAIN; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); -- cgit v1.2.3-70-g09d2 From 238f6b7255c68d2774795c97b32701c09fd1e543 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:23:22 +0530 Subject: [SCSI] be2iscsi: No return value for hwi_enable_intr hwi_enable_intr need not return any value. This patch fixes the that and removes code designed to handle a failure return value Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 3b54dc72371..26ac049c0c8 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3172,7 +3172,7 @@ static int hba_setup_cid_tbls(struct beiscsi_hba *phba) return 0; } -static unsigned char hwi_enable_intr(struct beiscsi_hba *phba) +static void hwi_enable_intr(struct beiscsi_hba *phba) { struct be_ctrl_info *ctrl = &phba->ctrl; struct hwi_controller *phwi_ctrlr; @@ -3207,7 +3207,6 @@ static unsigned char hwi_enable_intr(struct beiscsi_hba *phba) } } } - return true; } static void hwi_disable_intr(struct beiscsi_hba *phba) @@ -3773,7 +3772,7 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; struct be_eq_obj *pbe_eq; - int ret, msix_vec, num_cpus, i; + int ret, num_cpus, i; ret = beiscsi_enable_pci(pcidev); if (ret < 0) { @@ -3874,25 +3873,10 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, "Failed to beiscsi_init_irqs\n"); goto free_blkenbld; } - ret = hwi_enable_intr(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed to hwi_enable_intr\n"); - goto free_ctrlr; - } + hwi_enable_intr(phba); SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); return 0; -free_ctrlr: - if (phba->msix_enabled) { - for (i = 0; i <= phba->num_cpus; i++) { - msix_vec = phba->msix_entries[i].vector; - free_irq(msix_vec, &phwi_context->be_eq[i]); - } - } else - if (phba->pcidev->irq) - free_irq(phba->pcidev->irq, phba); - pci_disable_msix(phba->pcidev); free_blkenbld: destroy_workqueue(phba->wq); if (blk_iopoll_enabled) @@ -3910,6 +3894,8 @@ free_port: phba->ctrl.mbox_mem_alloced.dma); beiscsi_unmap_pci_function(phba); hba_free: + if (phba->msix_enabled) + pci_disable_msix(phba->pcidev); iscsi_host_remove(phba->shost); pci_dev_put(phba->pcidev); iscsi_host_free(phba->shost); -- cgit v1.2.3-70-g09d2 From 4f5af07e1bc4ae64b7a7ead5bf60f40a3115ceeb Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:23:55 +0530 Subject: [SCSI] be2iscsi: Fix to handle request_irq failure This patch handles request_irq failures by properly cleaning up Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 26ac049c0c8..67a7e3f7bae 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -616,7 +616,7 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) struct pci_dev *pcidev = phba->pcidev; struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; - int ret, msix_vec, i = 0; + int ret, msix_vec, i, j; char desc[32]; phwi_ctrlr = phba->phwi_ctrlr; @@ -628,10 +628,25 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) msix_vec = phba->msix_entries[i].vector; ret = request_irq(msix_vec, be_isr_msix, 0, desc, &phwi_context->be_eq[i]); + if (ret) { + shost_printk(KERN_ERR, phba->shost, + "beiscsi_init_irqs-Failed to" + "register msix for i = %d\n", i); + if (!i) + return ret; + goto free_msix_irqs; + } } msix_vec = phba->msix_entries[i].vector; ret = request_irq(msix_vec, be_isr_mcc, 0, "beiscsi_msix_mcc", &phwi_context->be_eq[i]); + if (ret) { + shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-" + "Failed to register beiscsi_msix_mcc\n"); + i++; + goto free_msix_irqs; + } + } else { ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, "beiscsi", phba); @@ -642,6 +657,10 @@ static int beiscsi_init_irqs(struct beiscsi_hba *phba) } } return 0; +free_msix_irqs: + for (j = i - 1; j == 0; j++) + free_irq(msix_vec, &phwi_context->be_eq[j]); + return ret; } static void hwi_ring_cq_db(struct beiscsi_hba *phba, -- cgit v1.2.3-70-g09d2 From 5db3f33d687c5a4ba589bf3af98c786399c6e213 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:24:22 +0530 Subject: [SCSI] be2iscsi: Free tags allocated This patch frees tags that are already allocated in case of failure Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_mgmt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index dcb70fac2fc..3036d9ee790 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -168,6 +168,7 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, SE_DEBUG(DBG_LVL_1, "Failed to alloc memory for mgmt_invalidate_icds\n"); spin_unlock(&ctrl->mbox_lock); + free_mcc_tag(&phba->ctrl, tag); return 0; } nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); @@ -330,6 +331,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n", dst_addr->sa_family); spin_unlock(&ctrl->mbox_lock); + free_mcc_tag(&phba->ctrl, tag); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From e9b911935033ea9e28a2f7a274c9a81db1f8d91a Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:24:53 +0530 Subject: [SCSI] be2iscsi: Adding crashdump support These changes allow the driver to support crashdump. We need to reset the chip incase of a crashdump Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.c | 80 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/be2iscsi/be_cmds.h | 3 ++ drivers/scsi/be2iscsi/be_main.c | 50 ++++++++++++++++++++++++++ drivers/scsi/be2iscsi/be_main.h | 9 ++++- 4 files changed, 141 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 9cc1f557315..7c7537335c8 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -19,6 +19,86 @@ #include "be_mgmt.h" #include "be_main.h" +int beiscsi_pci_soft_reset(struct beiscsi_hba *phba) +{ + u32 sreset; + u8 *pci_reset_offset = 0; + u8 *pci_online0_offset = 0; + u8 *pci_online1_offset = 0; + u32 pconline0 = 0; + u32 pconline1 = 0; + u32 i; + + pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET; + pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0; + pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1; + sreset = readl((void *)pci_reset_offset); + sreset |= BE2_SET_RESET; + writel(sreset, (void *)pci_reset_offset); + + i = 0; + while (sreset & BE2_SET_RESET) { + if (i > 64) + break; + msleep(100); + sreset = readl((void *)pci_reset_offset); + i++; + } + + if (sreset & BE2_SET_RESET) { + printk(KERN_ERR "Soft Reset did not deassert\n"); + return -EIO; + } + pconline1 = BE2_MPU_IRAM_ONLINE; + writel(pconline0, (void *)pci_online0_offset); + writel(pconline1, (void *)pci_online1_offset); + + sreset = BE2_SET_RESET; + writel(sreset, (void *)pci_reset_offset); + + i = 0; + while (sreset & BE2_SET_RESET) { + if (i > 64) + break; + msleep(1); + sreset = readl((void *)pci_reset_offset); + i++; + } + if (sreset & BE2_SET_RESET) { + printk(KERN_ERR "MPU Online Soft Reset did not deassert\n"); + return -EIO; + } + return 0; +} + +int be_chk_reset_complete(struct beiscsi_hba *phba) +{ + unsigned int num_loop; + u8 *mpu_sem = 0; + u32 status; + + num_loop = 1000; + mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; + msleep(5000); + + while (num_loop) { + status = readl((void *)mpu_sem); + + if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000) + break; + msleep(60); + num_loop--; + } + + if ((status & 0x80000000) || (!num_loop)) { + printk(KERN_ERR "Failed in be_chk_reset_complete" + "status = 0x%x\n", status); + return -EIO; + } + + return 0; +} + void be_mcc_notify(struct beiscsi_hba *phba) { struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 30a293f52ef..0df19cb58a3 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -901,6 +901,9 @@ struct be_fw_cfg { * the cxn */ +int beiscsi_pci_soft_reset(struct beiscsi_hba *phba); +int be_chk_reset_complete(struct beiscsi_hba *phba); + void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, bool embedded, u8 sge_cnt); diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 67a7e3f7bae..1a22125f520 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -41,6 +41,8 @@ static unsigned int be_iopoll_budget = 10; static unsigned int be_max_phys_size = 64; static unsigned int enable_msix = 1; +static unsigned int gcrashmode = 0; +static unsigned int num_hba = 0; MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); @@ -3731,6 +3733,8 @@ static void beiscsi_remove(struct pci_dev *pcidev) struct hwi_context_memory *phwi_context; struct be_eq_obj *pbe_eq; unsigned int i, msix_vec; + u8 *real_offset = 0; + u32 value = 0; phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev); if (!phba) { @@ -3759,6 +3763,14 @@ static void beiscsi_remove(struct pci_dev *pcidev) beiscsi_clean_port(phba); beiscsi_free_mem(phba); + real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; + + value = readl((void *)real_offset); + + if (value & 0x00010000) { + value &= 0xfffeffff; + writel(value, (void *)real_offset); + } beiscsi_unmap_pci_function(phba); pci_free_consistent(phba->pcidev, phba->ctrl.mbox_mem_alloced.size, @@ -3792,6 +3804,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, struct hwi_context_memory *phwi_context; struct be_eq_obj *pbe_eq; int ret, num_cpus, i; + u8 *real_offset = 0; + u32 value = 0; ret = beiscsi_enable_pci(pcidev); if (ret < 0) { @@ -3837,6 +3851,33 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, goto hba_free; } + if (!num_hba) { + real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; + value = readl((void *)real_offset); + if (value & 0x00010000) { + gcrashmode++; + shost_printk(KERN_ERR, phba->shost, + "Loading Driver in crashdump mode\n"); + ret = beiscsi_pci_soft_reset(phba); + if (ret) { + shost_printk(KERN_ERR, phba->shost, + "Reset Failed. Aborting Crashdump\n"); + goto hba_free; + } + ret = be_chk_reset_complete(phba); + if (ret) { + shost_printk(KERN_ERR, phba->shost, + "Failed to get out of reset." + "Aborting Crashdump\n"); + goto hba_free; + } + } else { + value |= 0x00010000; + writel(value, (void *)real_offset); + num_hba++; + } + } + spin_lock_init(&phba->io_sgl_lock); spin_lock_init(&phba->mgmt_sgl_lock); spin_lock_init(&phba->isr_lock); @@ -3907,6 +3948,15 @@ free_twq: beiscsi_clean_port(phba); beiscsi_free_mem(phba); free_port: + real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; + + value = readl((void *)real_offset); + + if (value & 0x00010000) { + value &= 0xfffeffff; + writel(value, (void *)real_offset); + } + pci_free_consistent(phba->pcidev, phba->ctrl.mbox_mem_alloced.size, phba->ctrl.mbox_mem_alloced.va, diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index e6ddddbbae7..05ad76e48d8 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -69,7 +69,14 @@ #define BEISCSI_NUM_DEVICES_SUPPORTED 0x01 #define BEISCSI_MAX_FRAGS_INIT 192 #define BE_NUM_MSIX_ENTRIES 1 -#define MPU_EP_SEMAPHORE 0xac + +#define MPU_EP_CONTROL 0 +#define MPU_EP_SEMAPHORE 0xac +#define BE2_SOFT_RESET 0x5c +#define BE2_PCI_ONLINE0 0xb0 +#define BE2_PCI_ONLINE1 0xb4 +#define BE2_SET_RESET 0x80 +#define BE2_MPU_IRAM_ONLINE 0x00000080 #define BE_SENSE_INFO_SIZE 258 #define BE_ISCSI_PDU_HEADER_SIZE 64 -- cgit v1.2.3-70-g09d2 From d2cecf0dcb2eb066756e0303d9f162ebe20d0591 Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:25:40 +0530 Subject: [SCSI] be2iscsi: Maintain same ITT across login This patch ensures that the same ITT is maintained across all login pdu's Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 41 ++++++++++++++++++++++++++++++++++++----- drivers/scsi/be2iscsi/be_main.h | 1 + 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 1a22125f520..fdd9161096c 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3452,14 +3452,12 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) return -ENOMEM; io_task->bhs_pa.u.a64.address = paddr; io_task->libiscsi_itt = (itt_t)task->itt; - io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start - ); io_task->conn = beiscsi_conn; task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; task->hdr_max = sizeof(struct be_cmd_bhs); + io_task->psgl_handle = NULL; + io_task->psgl_handle = NULL; if (task->sc) { spin_lock(&phba->io_sgl_lock); @@ -3467,6 +3465,11 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) spin_unlock(&phba->io_sgl_lock); if (!io_task->psgl_handle) goto free_hndls; + io_task->pwrb_handle = alloc_wrb_handle(phba, + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start); + if (!io_task->pwrb_handle) + goto free_io_hndls; } else { io_task->scsi_cmnd = NULL; if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { @@ -3481,9 +3484,20 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) beiscsi_conn->login_in_progress = 1; beiscsi_conn->plogin_sgl_handle = io_task->psgl_handle; + io_task->pwrb_handle = + alloc_wrb_handle(phba, + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start); + if (!io_task->pwrb_handle) + goto free_io_hndls; + beiscsi_conn->plogin_wrb_handle = + io_task->pwrb_handle; + } else { io_task->psgl_handle = beiscsi_conn->plogin_sgl_handle; + io_task->pwrb_handle = + beiscsi_conn->plogin_wrb_handle; } } else { spin_lock(&phba->mgmt_sgl_lock); @@ -3491,6 +3505,13 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) spin_unlock(&phba->mgmt_sgl_lock); if (!io_task->psgl_handle) goto free_hndls; + io_task->pwrb_handle = + alloc_wrb_handle(phba, + beiscsi_conn->beiscsi_conn_cid - + phba->fw_config.iscsi_cid_start); + if (!io_task->pwrb_handle) + goto free_mgmt_hndls; + } } itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> @@ -3501,12 +3522,22 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->cmd_bhs->iscsi_hdr.itt = itt; return 0; +free_io_hndls: + spin_lock(&phba->io_sgl_lock); + free_io_sgl_handle(phba, io_task->psgl_handle); + spin_unlock(&phba->io_sgl_lock); + goto free_hndls; +free_mgmt_hndls: + spin_lock(&phba->mgmt_sgl_lock); + free_mgmt_sgl_handle(phba, io_task->psgl_handle); + spin_unlock(&phba->mgmt_sgl_lock); free_hndls: phwi_ctrlr = phba->phwi_ctrlr; pwrb_context = &phwi_ctrlr->wrb_context[ beiscsi_conn->beiscsi_conn_cid - phba->fw_config.iscsi_cid_start]; - free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); + if (io_task->pwrb_handle) + free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); io_task->pwrb_handle = NULL; pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, io_task->bhs_pa.u.a64.address); diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 05ad76e48d8..08996d008ba 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -359,6 +359,7 @@ struct beiscsi_conn { u32 beiscsi_conn_cid; struct beiscsi_endpoint *ep; unsigned short login_in_progress; + struct wrb_handle *plogin_wrb_handle; struct sgl_handle *plogin_sgl_handle; struct beiscsi_session *beiscsi_sess; struct iscsi_task *task; -- cgit v1.2.3-70-g09d2 From 42f43c419e1881b543faf20182cad0f789b73d2f Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:26:45 +0530 Subject: [SCSI] be2iscsi: Limit max_xmit_length This patch limits max_xmit_length to 64K incase older utilities are used Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index de79b7cf804..a131a576a10 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -277,6 +277,10 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, if (session->max_burst > 262144) session->max_burst = 262144; break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + if ((conn->max_xmit_dlength > 65536) || + (conn->max_xmit_dlength == 0)) + conn->max_xmit_dlength = 65536; default: return 0; } -- cgit v1.2.3-70-g09d2 From 0aa094331b19e54f928e2ac083285ff68d91c69b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:27:16 +0530 Subject: [SCSI] be2iscsi: Remove debug print in IO path This patch removes a Debug Print in the IO path Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index fdd9161096c..b70b4ba7207 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -3744,8 +3744,6 @@ static int beiscsi_task_xmit(struct iscsi_task *task) SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n") return num_sg; } - SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n", - (scsi_bufflen(sc)), sc, num_sg, sc->serial_number); xferlen = scsi_bufflen(sc); sg = scsi_sglist(sc); if (sc->sc_data_direction == DMA_TO_DEVICE) { -- cgit v1.2.3-70-g09d2 From 3cbb7a74a76e45f5e410367259844e8266fba6ec Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:27:47 +0530 Subject: [SCSI] be2iscsi: Fix for premature buffer free This patch fixes a bug where the buffer was being freed as soon as submission to HW is done. Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_iscsi.c | 24 ++++++++++++++++++++- drivers/scsi/be2iscsi/be_main.c | 41 ++++++++++++++++++++++++++++++++---- drivers/scsi/be2iscsi/be_mgmt.c | 45 +++++++++++++++++++--------------------- drivers/scsi/be2iscsi/be_mgmt.h | 9 +++++--- 4 files changed, 87 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index a131a576a10..6d63e7b312c 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -488,6 +488,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, struct be_mcc_wrb *wrb; struct tcp_connect_and_offload_out *ptcpcnct_out; unsigned short status, extd_status; + struct be_dma_mem nonemb_cmd; unsigned int tag, wrb_num; int ret = -ENOMEM; @@ -504,16 +505,31 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl * 2)) { SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); goto free_ep; } beiscsi_ep->cid_vld = 0; - tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep); + nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + sizeof(struct tcp_connect_and_offload_in), + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + SE_DEBUG(DBG_LVL_1, + "Failed to allocate memory for mgmt_open_connection" + "\n"); + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + return -ENOMEM; + } + nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in); + memset(nonemb_cmd.va, 0, nonemb_cmd.size); + tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd); if (!tag) { SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed for cid=%d\n", beiscsi_ep->ep_cid); beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return -EAGAIN; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], @@ -526,7 +542,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" " status = %d extd_status = %d\n", status, extd_status); + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); free_mcc_tag(&phba->ctrl, tag); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); goto free_ep; } else { wrb = queue_get_wrb(mccq, wrb_num); @@ -538,6 +557,9 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep, beiscsi_ep->cid_vld = 1; SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); } + beiscsi_put_cid(phba, beiscsi_ep->ep_cid); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return 0; free_ep: diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index b70b4ba7207..7436c5ad569 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -71,6 +71,7 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) struct beiscsi_hba *phba; struct iscsi_session *session; struct invalidate_command_table *inv_tbl; + struct be_dma_mem nonemb_cmd; unsigned int cid, tag, num_invalidate; cls_session = starget_to_session(scsi_target(sc->device)); @@ -101,18 +102,34 @@ static int beiscsi_eh_abort(struct scsi_cmnd *sc) inv_tbl->cid = cid; inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index; num_invalidate = 1; - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid); + nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + sizeof(struct invalidate_commands_params_in), + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + SE_DEBUG(DBG_LVL_1, + "Failed to allocate memory for" + "mgmt_invalidate_icds\n"); + return FAILED; + } + nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); + + tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, + cid, &nonemb_cmd); if (!tag) { shost_printk(KERN_WARNING, phba->shost, "mgmt_invalidate_icds could not be" " submitted\n"); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); + return FAILED; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } - + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return iscsi_eh_abort(sc); } @@ -126,6 +143,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) struct iscsi_session *session; struct iscsi_cls_session *cls_session; struct invalidate_command_table *inv_tbl; + struct be_dma_mem nonemb_cmd; unsigned int cid, tag, i, num_invalidate; int rc = FAILED; @@ -160,18 +178,33 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) spin_unlock_bh(&session->lock); inv_tbl = phba->inv_tbl; - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, cid); + nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, + sizeof(struct invalidate_commands_params_in), + &nonemb_cmd.dma); + if (nonemb_cmd.va == NULL) { + SE_DEBUG(DBG_LVL_1, + "Failed to allocate memory for" + "mgmt_invalidate_icds\n"); + return FAILED; + } + nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); + memset(nonemb_cmd.va, 0, nonemb_cmd.size); + tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, + cid, &nonemb_cmd); if (!tag) { shost_printk(KERN_WARNING, phba->shost, "mgmt_invalidate_icds could not be" " submitted\n"); + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return FAILED; } else { wait_event_interruptible(phba->ctrl.mcc_wait[tag], phba->ctrl.mcc_numtag[tag]); free_mcc_tag(&phba->ctrl, tag); } - + pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, + nonemb_cmd.va, nonemb_cmd.dma); return iscsi_eh_device_reset(sc); unlock: spin_unlock_bh(&session->lock); diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index 3036d9ee790..3f3fab91a7d 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -50,7 +50,7 @@ int mgmt_get_fw_config(struct be_ctrl_info *ctrl, pfw_cfg->ulp[0].sq_count; if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { SE_DEBUG(DBG_LVL_8, - "FW reported MAX CXNS as %d \t" + "FW reported MAX CXNS as %d\t" "Max Supported = %d.\n", phba->fw_config.iscsi_cid_count, BE2_MAX_SESSIONS); @@ -145,9 +145,10 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid) + unsigned int num_invalidate, unsigned int cid, + struct be_dma_mem *nonemb_cmd) + { - struct be_dma_mem nonemb_cmd; struct be_ctrl_info *ctrl = &phba->ctrl; struct be_mcc_wrb *wrb; struct be_sge *sge; @@ -161,18 +162,7 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, return tag; } - nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to alloc memory for mgmt_invalidate_icds\n"); - spin_unlock(&ctrl->mbox_lock); - free_mcc_tag(&phba->ctrl, tag); - return 0; - } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - req = nonemb_cmd.va; + req = nonemb_cmd->va; memset(req, 0, sizeof(*req)); wrb = wrb_from_mccq(phba); sge = nonembedded_sgl(wrb); @@ -190,15 +180,12 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, req->icd_count++; inv_tbl++; } - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd.size); + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); - if (nonemb_cmd.va) - pci_free_consistent(ctrl->pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); return tag; } @@ -269,7 +256,9 @@ unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, - struct beiscsi_endpoint *beiscsi_ep) + struct beiscsi_endpoint *beiscsi_ep, + struct be_dma_mem *nonemb_cmd) + { struct hwi_controller *phwi_ctrlr; struct hwi_context_memory *phwi_context; @@ -285,6 +274,7 @@ int mgmt_open_connection(struct beiscsi_hba *phba, unsigned int tag = 0; unsigned int i; unsigned short cid = beiscsi_ep->ep_cid; + struct be_sge *sge; phwi_ctrlr = phba->phwi_ctrlr; phwi_context = phwi_ctrlr->phwi_ctxt; @@ -300,10 +290,14 @@ int mgmt_open_connection(struct beiscsi_hba *phba, return tag; } wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); + memset(wrb, 0, sizeof(*wrb)); + sge = nonembedded_sgl(wrb); + + req = nonemb_cmd->va; + memset(req, 0, sizeof(*req)); wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 1); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, sizeof(*req)); @@ -347,6 +341,9 @@ int mgmt_open_connection(struct beiscsi_hba *phba, req->do_offload = 1; req->dataout_template_pa.lo = ptemplate_address->lo; req->dataout_template_pa.hi = ptemplate_address->hi; + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); be_mcc_notify(phba); spin_unlock(&ctrl->mbox_lock); return tag; diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index 74b885a4b83..b9acedf7865 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -87,15 +87,18 @@ struct mcc_wrb { }; int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); -int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr, - struct beiscsi_endpoint *beiscsi_ep); +int mgmt_open_connection(struct beiscsi_hba *phba, + struct sockaddr *dst_addr, + struct beiscsi_endpoint *beiscsi_ep, + struct be_dma_mem *nonemb_cmd); unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, unsigned short cid, unsigned int upload_flag); unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid); + unsigned int num_invalidate, unsigned int cid, + struct be_dma_mem *nonemb_cmd); struct iscsi_invalidate_connection_params_in { struct be_cmd_req_hdr hdr; -- cgit v1.2.3-70-g09d2 From b38c1e8bd19340e1a5b712287a8d61da26225d5b Mon Sep 17 00:00:00 2001 From: Jayamohan Kallickal Date: Thu, 22 Jul 2010 04:28:13 +0530 Subject: [SCSI] be2iscsi: The extended shift must be 16 Signed-off-by: Jayamohan Kallickal Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/be_cmds.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 0df19cb58a3..40641d0845f 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -56,7 +56,7 @@ struct be_mcc_wrb { #define CQE_STATUS_COMPL_MASK 0xFFFF #define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ #define CQE_STATUS_EXTD_MASK 0xFFFF -#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */ +#define CQE_STATUS_EXTD_SHIFT 16 /* bits 0 - 15 */ struct be_mcc_compl { u32 status; /* dword 0 */ -- cgit v1.2.3-70-g09d2 From 82c57028e4bf6e2755de91b36223f57406746fa8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 4 May 2010 10:29:52 -0700 Subject: [SCSI] scsi: add Kconfig dependency on NET be2iscsi driver should #include linux/if_ether.h since it uses sysfs_format_mac(). It should also depend on NET since it selects SCSI_ISCSI_ATTRS, which depends on NET. These changes fix a build error when CONFIG_NET is not enabled: ERROR: "sysfs_format_mac" [drivers/scsi/be2iscsi/be2iscsi.ko] undefined! Signed-off-by: Randy Dunlap Acked-by: Jayamohan Kallickal Signed-off-by: James Bottomley --- drivers/scsi/be2iscsi/Kconfig | 2 +- drivers/scsi/be2iscsi/be_main.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig index 2952fcd008e..84c275fb9f6 100644 --- a/drivers/scsi/be2iscsi/Kconfig +++ b/drivers/scsi/be2iscsi/Kconfig @@ -1,6 +1,6 @@ config BE2ISCSI tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" - depends on PCI && SCSI + depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS help diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index 08996d008ba..c643bb3736f 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 1df79ca4223632113f14618833b8bb1727a8ca15 Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Wed, 14 Jul 2010 10:49:43 -0700 Subject: [SCSI] ipr: fix transition to operational for new adapters The method of transitioning to operational for new adapters includes using initialization stages. The current stage is indicated via a register read. The final good stage in the sequence is "operational" but does not necessarily indicate that the driver can proceed. There is another bit that gets set in the adapter->host interrupt register when the adapter has completed enough of its bringup such that it can accept commands. The driver was not checking that bit before proceeding which led to intermittent errors and adapter resets. The fix is to check the "transition to operational" bit in the interrupt register after detecting that the initialization stage is "operational" and only proceed if both are set. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index ce839c8eeea..f73007db2be 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7169,12 +7169,15 @@ static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd) stage_time = ioa_cfg->transop_timeout; ipr_cmd->job_step = ipr_ioafp_identify_hrrq; } else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) { - ipr_cmd->job_step = ipr_ioafp_identify_hrrq; - maskval = IPR_PCII_IPL_STAGE_CHANGE; - maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER; - writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - return IPR_RC_JOB_CONTINUE; + int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); + if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { + ipr_cmd->job_step = ipr_ioafp_identify_hrrq; + maskval = IPR_PCII_IPL_STAGE_CHANGE; + maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER; + writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg); + int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + return IPR_RC_JOB_CONTINUE; + } } ipr_cmd->timer.data = (unsigned long) ipr_cmd; -- cgit v1.2.3-70-g09d2 From 75576bb9b208d7c66822f310cdef9ca2d72c879c Mon Sep 17 00:00:00 2001 From: Wayne Boyer Date: Wed, 14 Jul 2010 10:50:14 -0700 Subject: [SCSI] ipr: fix resource type update and add sdev and shost attributes Setting the resource type in the ipr_update_res_entry function was incorrect in that the top 4 bits were masked off. The assignment has been updated to no longer mask those bits. Then, two new attributes were added to allow the user space utilities to more easily get information. The resource_type sdev attribute is set for all devices in the adapter's configuration table and indicates the type of device. The fw_type shost attribute indicates the firmware type supported by the adapter. Finally, the resource_path attribute was changed to be mode S_IRUGO. Signed-off-by: Wayne Boyer Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f73007db2be..52568588039 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -1168,7 +1168,7 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res, if (res->ioa_cfg->sis64) { res->flags = cfgtew->u.cfgte64->flags; res->res_flags = cfgtew->u.cfgte64->res_flags; - res->type = cfgtew->u.cfgte64->res_type & 0x0f; + res->type = cfgtew->u.cfgte64->res_type; memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data, sizeof(struct ipr_std_inq_data)); @@ -3762,6 +3762,36 @@ static struct device_attribute ipr_update_fw_attr = { .store = ipr_store_update_fw }; +/** + * ipr_show_fw_type - Show the adapter's firmware type. + * @dev: class device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_fw_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + unsigned long lock_flags = 0; + int len; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->sis64); + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static struct device_attribute ipr_ioa_fw_type_attr = { + .attr = { + .name = "fw_type", + .mode = S_IRUGO, + }, + .show = ipr_show_fw_type +}; + static struct device_attribute *ipr_ioa_attrs[] = { &ipr_fw_version_attr, &ipr_log_level_attr, @@ -3769,6 +3799,7 @@ static struct device_attribute *ipr_ioa_attrs[] = { &ipr_ioa_state_attr, &ipr_ioa_reset_attr, &ipr_update_fw_attr, + &ipr_ioa_fw_type_attr, NULL, }; @@ -4122,14 +4153,49 @@ static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribut static struct device_attribute ipr_resource_path_attr = { .attr = { .name = "resource_path", - .mode = S_IRUSR, + .mode = S_IRUGO, }, .show = ipr_show_resource_path }; +/** + * ipr_show_resource_type - Show the resource type for this device. + * @dev: device struct + * @buf: buffer + * + * Return value: + * number of bytes printed to buffer + **/ +static ssize_t ipr_show_resource_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; + struct ipr_resource_entry *res; + unsigned long lock_flags = 0; + ssize_t len = -ENXIO; + + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + res = (struct ipr_resource_entry *)sdev->hostdata; + + if (res) + len = snprintf(buf, PAGE_SIZE, "%x\n", res->type); + + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + return len; +} + +static struct device_attribute ipr_resource_type_attr = { + .attr = { + .name = "resource_type", + .mode = S_IRUGO, + }, + .show = ipr_show_resource_type +}; + static struct device_attribute *ipr_dev_attrs[] = { &ipr_adapter_handle_attr, &ipr_resource_path_attr, + &ipr_resource_type_attr, NULL, }; -- cgit v1.2.3-70-g09d2 From 589a52d6a97e01c5ff6c244ee6c8ea57726c610f Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 14 Jul 2010 15:30:54 -0400 Subject: [SCSI] lpfc 8.3.15: BSG, Discovery, and Misc fixes - BSG interface related: - Fix node reference count if node is active - Warn if we're overwriting an active CT context - Discovery related: - Clear "Ignore Reg Login" flag when purging mailbox queue - Pay attention to return code for fc_block_scsi_eh() - Stall device loss code if we're almost done when it fires (we're logged in, but PRLI is outstanding) - Bugs - Correct DIF code for endianness issues - Correct where we had missed points to check txq on i/o completion/cleanup Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 27 +++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_els.c | 5 +++++ drivers/scsi/lpfc/lpfc_hbadisc.c | 5 +++-- drivers/scsi/lpfc/lpfc_scsi.c | 38 +++++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_sli.c | 20 ++++++++------------ 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 55f984166db..d521569e662 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -962,10 +962,22 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (phba->sli_rev == LPFC_SLI_REV4) { evt_dat->immed_dat = phba->ctx_idx; phba->ctx_idx = (phba->ctx_idx + 1) % 64; + /* Provide warning for over-run of the ct_ctx array */ + if (phba->ct_ctx[evt_dat->immed_dat].flags & + UNSOL_VALID) + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "2717 CT context array entry " + "[%d] over-run: oxid:x%x, " + "sid:x%x\n", phba->ctx_idx, + phba->ct_ctx[ + evt_dat->immed_dat].oxid, + phba->ct_ctx[ + evt_dat->immed_dat].SID); phba->ct_ctx[evt_dat->immed_dat].oxid = piocbq->iocb.ulpContext; phba->ct_ctx[evt_dat->immed_dat].SID = piocbq->iocb.un.rcvels.remoteID; + phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID; } else evt_dat->immed_dat = piocbq->iocb.ulpContext; @@ -1323,6 +1335,21 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, rc = IOCB_ERROR; goto issue_ct_rsp_exit; } + + /* Check if the ndlp is active */ + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -IOCB_ERROR; + goto issue_ct_rsp_exit; + } + + /* get a refernece count so the ndlp doesn't go away while + * we respond + */ + if (!lpfc_nlp_get(ndlp)) { + rc = -IOCB_ERROR; + goto issue_ct_rsp_exit; + } + icmd->un.ulpWord[3] = ndlp->nlp_rpi; /* The exchange is done, mark the entry as invalid */ phba->ct_ctx[tag].flags &= ~UNSOL_VALID; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 017c933d60a..f80156246e5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -6962,6 +6962,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; unsigned long iflag = 0; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&phba->sli4_hba.abts_sgl_list_lock); @@ -6974,6 +6975,10 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); + + /* Check if TXQ queue needs to be serviced */ + if (pring->txq_cnt) + lpfc_worker_wake_up(phba); return; } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9fcad20491e..a610464da16 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -276,7 +276,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE)) + (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) && + (ndlp->nlp_state != NLP_STE_PRLI_ISSUE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); lpfc_unregister_unused_fcf(phba); @@ -587,7 +588,7 @@ lpfc_work_done(struct lpfc_hba *phba) (status & HA_RXMASK)); } - if (phba->pport->work_port_events & WORKER_SERVICE_TXQ) + if (pring->txq_cnt) lpfc_drain_txq(phba); /* * Turn on Ring interrupts diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7b66b71a14f..d6089c985c3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -623,6 +623,7 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, unsigned long iflag = 0; struct lpfc_iocbq *iocbq; int i; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock); @@ -651,6 +652,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); psb->exch_busy = 0; spin_unlock_irqrestore(&phba->hbalock, iflag); + if (pring->txq_cnt) + lpfc_worker_wake_up(phba); return; } @@ -1322,6 +1325,10 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); pde5->reftag = reftag; + /* Endian convertion if necessary for PDE5 */ + pde5->word0 = cpu_to_le32(pde5->word0); + pde5->reftag = cpu_to_le32(pde5->reftag); + /* advance bpl and increment bde count */ num_bde++; bpl++; @@ -1340,6 +1347,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde6_ai, pde6, 1); bf_set(pde6_apptagval, pde6, apptagval); + /* Endian convertion if necessary for PDE6 */ + pde6->word0 = cpu_to_le32(pde6->word0); + pde6->word1 = cpu_to_le32(pde6->word1); + pde6->word2 = cpu_to_le32(pde6->word2); + /* advance bpl and increment bde count */ num_bde++; bpl++; @@ -1447,6 +1459,10 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); pde5->reftag = reftag; + /* Endian convertion if necessary for PDE5 */ + pde5->word0 = cpu_to_le32(pde5->word0); + pde5->reftag = cpu_to_le32(pde5->reftag); + /* advance bpl and increment bde count */ num_bde++; bpl++; @@ -1463,6 +1479,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bf_set(pde6_ai, pde6, 1); bf_set(pde6_apptagval, pde6, apptagval); + /* Endian convertion if necessary for PDE6 */ + pde6->word0 = cpu_to_le32(pde6->word0); + pde6->word1 = cpu_to_le32(pde6->word1); + pde6->word2 = cpu_to_le32(pde6->word2); + /* advance bpl and increment bde count */ num_bde++; bpl++; @@ -1474,7 +1495,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); protgroup_len = sg_dma_len(sgpe); - /* must be integer multiple of the DIF block length */ BUG_ON(protgroup_len % 8); @@ -3047,7 +3067,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) int ret = SUCCESS; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); - fc_block_scsi_eh(cmnd); + ret = fc_block_scsi_eh(cmnd); + if (ret) + return ret; lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; BUG_ON(!lpfc_cmd); @@ -3365,7 +3387,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) return FAILED; } pnode = rdata->pnode; - fc_block_scsi_eh(cmnd); + status = fc_block_scsi_eh(cmnd); + if (status) + return status; status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { @@ -3430,7 +3454,9 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) return FAILED; } pnode = rdata->pnode; - fc_block_scsi_eh(cmnd); + status = fc_block_scsi_eh(cmnd); + if (status) + return status; status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { @@ -3496,7 +3522,9 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - fc_block_scsi_eh(cmnd); + ret = fc_block_scsi_eh(cmnd); + if (ret) + return ret; /* * Since the driver manages a single bus device, reset all diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 7ddf5268227..086f9526160 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -601,15 +601,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list); /* Check if TXQ queue needs to be serviced */ - if (pring->txq_cnt) { - spin_lock_irqsave( - &phba->pport->work_port_lock, iflag); - phba->pport->work_port_events |= - WORKER_SERVICE_TXQ; + if (pring->txq_cnt) lpfc_worker_wake_up(phba); - spin_unlock_irqrestore( - &phba->pport->work_port_lock, iflag); - } } } @@ -12757,6 +12750,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) LPFC_MBOXQ_t *mb, *nextmb; struct lpfc_dmabuf *mp; struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { @@ -12778,6 +12772,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) } ndlp = (struct lpfc_nodelist *) mb->context2; if (ndlp) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; + spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); mb->context2 = NULL; } @@ -12793,6 +12790,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { ndlp = (struct lpfc_nodelist *) mb->context2; if (ndlp) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; + spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); mb->context2 = NULL; } @@ -12879,10 +12879,6 @@ lpfc_drain_txq(struct lpfc_hba *phba) spin_unlock_irqrestore(&phba->hbalock, iflags); } - spin_lock_irqsave(&phba->pport->work_port_lock, iflags); - phba->pport->work_port_events &= ~WORKER_SERVICE_TXQ; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); - /* Cancel all the IOCBs that cannot be issued */ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); -- cgit v1.2.3-70-g09d2 From 3804dc84b8c11038ef75d97fd11e43658f623665 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 14 Jul 2010 15:31:37 -0400 Subject: [SCSI] lpfc 8.3.15: FCoE Related Fixes FCoE Related Fixes - Correct find-next-FCF routine so that it searches at next FCF rather than current one. - Enhanced round-robin FCF failover algorithm to re-start on "New FCF" async event - Update the manner in which we look at FCFs while they may be in their discovery state. - Use LPFC_FCOE_NULL_VID macro when checkinf for valid vlan_id for FCF Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 24 +++++++++--------- drivers/scsi/lpfc/lpfc_hbadisc.c | 28 ++++++++++++++------ drivers/scsi/lpfc/lpfc_init.c | 22 ++++++++-------- drivers/scsi/lpfc/lpfc_mbox.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 55 +++++++++++++++++++++++++++++++++++----- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 6 files changed, 92 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f80156246e5..afbed6bc31f 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -813,18 +813,21 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, - "2760 FLOGI exhausted FCF " - "round robin failover list, " - "retry FLOGI on the current " - "registered FCF index:%d\n", + "2760 Completed one round " + "of FLOGI FCF round robin " + "failover list, retry FLOGI " + "on currently registered " + "FCF index:%d\n", phba->fcf.current_rec.fcf_indx); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DISCOVERY; - spin_unlock_irq(&phba->hbalock); } else { + lpfc_printf_log(phba, KERN_INFO, + LOG_FIP | LOG_ELS, + "2794 FLOGI FCF round robin " + "failover to FCF index x%x\n", + fcf_index); rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index); - if (rc) { + if (rc) lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2761 FLOGI round " @@ -833,10 +836,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "rc:x%x, fcf_index:" "%d\n", rc, phba->fcf.current_rec.fcf_indx); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DISCOVERY; - spin_unlock_irq(&phba->hbalock); - } else + else goto out; } } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a610464da16..92498e488f4 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1572,7 +1572,7 @@ lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) } /** - * lpfc_mbx_cmpl_read_fcf_record - Completion handler for read_fcf mbox. + * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command. * @phba: pointer to lpfc hba data structure. * @mboxq: pointer to mailbox object. * @next_fcf_index: pointer to holder of next fcf index. @@ -2026,9 +2026,14 @@ read_next_fcf: memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec, sizeof(struct lpfc_fcf_rec)); - /* mark the FCF fast failover completed */ + /* + * Mark the fast FCF failover rediscovery completed + * and the start of the first round of the roundrobin + * FCF failover. + */ spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; + phba->fcf.fcf_flag &= + ~(FCF_REDISC_FOV | FCF_REDISC_RRU); spin_unlock_irq(&phba->hbalock); /* * Set up the initial registered FCF index for FLOGI @@ -2074,9 +2079,14 @@ read_next_fcf: * through the FCF scanning process. */ - /* mark the initial FCF discovery completed */ + /* + * Mark the initial FCF discovery completed and + * the start of the first round of the roundrobin + * FCF failover. + */ spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_INIT_DISC; + phba->fcf.fcf_flag &= + ~(FCF_INIT_DISC | FCF_REDISC_RRU); spin_unlock_irq(&phba->hbalock); /* * Set up the initial registered FCF index for FLOGI @@ -2206,7 +2216,7 @@ lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) goto out; /* If FCF discovery period is over, no need to proceed */ - if (phba->fcf.fcf_flag & FCF_DISCOVERY) + if (!(phba->fcf.fcf_flag & FCF_DISCOVERY)) goto out; /* Parse the FCF record from the non-embedded mailbox command */ @@ -5331,13 +5341,15 @@ void lpfc_unregister_unused_fcf(struct lpfc_hba *phba) { /* - * If HBA is not running in FIP mode or if HBA does not support - * FCoE or if FCF is not registered, do nothing. + * If HBA is not running in FIP mode, if HBA does not support + * FCoE, if FCF discovery is ongoing, or if FCF has not been + * registered, do nothing. */ spin_lock_irq(&phba->hbalock); if (!(phba->hba_flag & HBA_FCOE_SUPPORT) || !(phba->fcf.fcf_flag & FCF_REGISTERED) || !(phba->hba_flag & HBA_FIP_SUPPORT) || + (phba->fcf.fcf_flag & FCF_DISCOVERY) || (phba->pport->port_state == LPFC_FLOGI)) { spin_unlock_irq(&phba->hbalock); return; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index fb06933f8e6..2786ee3b605 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3357,22 +3357,14 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, "evt_tag:x%x, fcf_index:x%x\n", acqe_fcoe->event_tag, acqe_fcoe->index); + /* If the FCF discovery is in progress, do nothing. */ spin_lock_irq(&phba->hbalock); - if ((phba->fcf.fcf_flag & FCF_SCAN_DONE) || - (phba->hba_flag & FCF_DISC_INPROGRESS)) { - /* - * If the current FCF is in discovered state or - * FCF discovery is in progress, do nothing. - */ + if (phba->hba_flag & FCF_DISC_INPROGRESS) { spin_unlock_irq(&phba->hbalock); break; } - + /* If fast FCF failover rescan event is pending, do nothing */ if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { - /* - * If fast FCF failover rescan event is pending, - * do nothing. - */ spin_unlock_irq(&phba->hbalock); break; } @@ -3393,7 +3385,13 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, acqe_fcoe->index); rc = lpfc_sli4_read_fcf_rec(phba, acqe_fcoe->index); } - + /* If the FCF has been in discovered state, do nothing. */ + spin_lock_irq(&phba->hbalock); + if (phba->fcf.fcf_flag & FCF_SCAN_DONE) { + spin_unlock_irq(&phba->hbalock); + break; + } + spin_unlock_irq(&phba->hbalock); /* Otherwise, scan the entire FCF table and re-discover SAN */ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2770 Start FCF table scan due to new FCF " diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index cb5d93b41b5..9c2c7c7140c 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -2045,7 +2045,7 @@ lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox) phba->fcf.current_rec.fcf_indx); /* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */ bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3); - if (phba->fcf.current_rec.vlan_id != 0xFFFF) { + if (phba->fcf.current_rec.vlan_id != LPFC_FCOE_NULL_VID) { bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1); bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, phba->fcf.current_rec.vlan_id); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 086f9526160..e758eae0d0f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -12405,19 +12405,47 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) { uint16_t next_fcf_index; - /* Search from the currently registered FCF index */ + /* Search start from next bit of currently registered FCF index */ + next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) % + LPFC_SLI4_FCF_TBL_INDX_MAX; next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, LPFC_SLI4_FCF_TBL_INDX_MAX, - phba->fcf.current_rec.fcf_indx); + next_fcf_index); + /* Wrap around condition on phba->fcf.fcf_rr_bmask */ if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, LPFC_SLI4_FCF_TBL_INDX_MAX, 0); - /* Round robin failover stop condition */ - if ((next_fcf_index == phba->fcf.fcf_rr_init_indx) || - (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX)) + + /* Check roundrobin failover list empty condition */ + if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2844 No roundrobin failover FCF available\n"); return LPFC_FCOE_FCF_NEXT_NONE; + } + + /* Check roundrobin failover index bmask stop condition */ + if (next_fcf_index == phba->fcf.fcf_rr_init_indx) { + if (!(phba->fcf.fcf_flag & FCF_REDISC_RRU)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2847 Round robin failover FCF index " + "search hit stop condition:x%x\n", + next_fcf_index); + return LPFC_FCOE_FCF_NEXT_NONE; + } + /* The roundrobin failover index bmask updated, start over */ + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2848 Round robin failover FCF index bmask " + "updated, start over\n"); + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_REDISC_RRU; + spin_unlock_irq(&phba->hbalock); + return phba->fcf.fcf_rr_init_indx; + } + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2845 Get next round robin failover " + "FCF index x%x\n", next_fcf_index); return next_fcf_index; } @@ -12447,11 +12475,20 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index) /* Set the eligible FCF record index bmask */ set_bit(fcf_index, phba->fcf.fcf_rr_bmask); + /* Set the roundrobin index bmask updated */ + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag |= FCF_REDISC_RRU; + spin_unlock_irq(&phba->hbalock); + + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2790 Set FCF index x%x to round robin failover " + "bmask\n", fcf_index); + return 0; } /** - * lpfc_sli4_fcf_rr_index_set - Clear bmask from eligible fcf record index + * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index * @phba: pointer to lpfc hba data structure. * * This routine clears the FCF record index from the eligible bmask for @@ -12472,6 +12509,10 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) } /* Clear the eligible FCF record index bmask */ clear_bit(fcf_index, phba->fcf.fcf_rr_bmask); + + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2791 Clear FCF index x%x from round robin failover " + "bmask\n", fcf_index); } /** @@ -12534,7 +12575,7 @@ lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) } /** - * lpfc_sli4_redisc_all_fcf - Request to rediscover entire FCF table by port. + * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port. * @phba: pointer to lpfc hba data structure. * * This routine is invoked to request for rediscovery of the entire FCF table diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index c916079fbb3..a3b24d99a2a 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -163,6 +163,7 @@ struct lpfc_fcf { #define FCF_REDISC_PEND 0x80 /* FCF rediscovery pending */ #define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */ #define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */ +#define FCF_REDISC_RRU 0x400 /* Roundrobin bitmap updated */ uint32_t addr_mode; uint16_t fcf_rr_init_indx; uint32_t eligible_fcf_cnt; -- cgit v1.2.3-70-g09d2 From 7dc517df3ace15b5a29b331abe0af86ed4836236 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 14 Jul 2010 15:32:10 -0400 Subject: [SCSI] lpfc 8.3.15: Add target queue depth throttling Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 3 ++- drivers/scsi/lpfc/lpfc_attr.c | 12 +++++++++++- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 15 ++++++++------- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index bb40fcbe17c..3482d5a5aed 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -48,7 +48,7 @@ struct lpfc_sli2_slim; #define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt queue depth change in millisecs */ #define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */ -#define LPFC_MIN_TGT_QDEPTH 100 +#define LPFC_MIN_TGT_QDEPTH 10 #define LPFC_MAX_TGT_QDEPTH 0xFFFF #define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data @@ -400,6 +400,7 @@ struct lpfc_vport { uint32_t cfg_max_luns; uint32_t cfg_enable_da_id; uint32_t cfg_max_scsicmpl_time; + uint32_t cfg_tgt_queue_depth; uint32_t dev_loss_tmo_changed; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index a7c6b739055..868874c28f9 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -2207,6 +2207,13 @@ LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1, LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128, "Max number of FCP commands we can queue to a specific LUN"); +/* +# tgt_queue_depth: This parameter is used to limit the number of outstanding +# commands per target port. Value range is [10,65535]. Default value is 65535. +*/ +LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535, + "Max number of FCP commands we can queue to a specific target port"); + /* # hba_queue_depth: This parameter is used to limit the number of outstanding # commands per lpfc HBA. Value range is [32,8192]. If this parameter @@ -3122,7 +3129,7 @@ lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; - ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; } spin_unlock_irq(shost->host_lock); return 0; @@ -3326,6 +3333,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_temp_sensor, &dev_attr_lpfc_log_verbose, &dev_attr_lpfc_lun_queue_depth, + &dev_attr_lpfc_tgt_queue_depth, &dev_attr_lpfc_hba_queue_depth, &dev_attr_lpfc_peer_port_login, &dev_attr_lpfc_nodev_tmo, @@ -3387,6 +3395,7 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_drvr_version, &dev_attr_lpfc_log_verbose, &dev_attr_lpfc_lun_queue_depth, + &dev_attr_lpfc_tgt_queue_depth, &dev_attr_lpfc_nodev_tmo, &dev_attr_lpfc_devloss_tmo, &dev_attr_lpfc_hba_queue_depth, @@ -4575,6 +4584,7 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport) { lpfc_log_verbose_init(vport, lpfc_log_verbose); lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth); + lpfc_tgt_queue_depth_init(vport, lpfc_tgt_queue_depth); lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo); lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo); lpfc_peer_port_login_init(vport, lpfc_peer_port_login); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 92498e488f4..0639c994349 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3583,7 +3583,7 @@ lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, kref_init(&ndlp->kref); NLP_INT_NODE_ACT(ndlp); atomic_set(&ndlp->cmd_pending, 0); - ndlp->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; } struct lpfc_nodelist * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index d6089c985c3..c818a725596 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -2458,14 +2458,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } spin_unlock_irqrestore(shost->host_lock, flags); } else if (pnode && NLP_CHK_NODE_ACT(pnode)) { - if ((pnode->cmd_qdepth < LPFC_MAX_TGT_QDEPTH) && + if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) && time_after(jiffies, pnode->last_change_time + msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { spin_lock_irqsave(shost->host_lock, flags); - pnode->cmd_qdepth += pnode->cmd_qdepth * - LPFC_TGTQ_RAMPUP_PCENT / 100; - if (pnode->cmd_qdepth > LPFC_MAX_TGT_QDEPTH) - pnode->cmd_qdepth = LPFC_MAX_TGT_QDEPTH; + depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT + / 100; + depth = depth ? depth : 1; + pnode->cmd_qdepth += depth; + if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth) + pnode->cmd_qdepth = vport->cfg_tgt_queue_depth; pnode->last_change_time = jiffies; spin_unlock_irqrestore(shost->host_lock, flags); } @@ -2920,8 +2922,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); goto out_fail_command; } - if (vport->cfg_max_scsicmpl_time && - (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth)) + if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) goto out_host_busy; lpfc_cmd = lpfc_get_scsi_buf(phba); -- cgit v1.2.3-70-g09d2 From 32de596074592ee8593416c83347b5a787e825c5 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 14 Jul 2010 15:32:40 -0400 Subject: [SCSI] lpfc 8.3.15: Update driver version 8.3.15 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 33d9d8db4d3..d28830af71d 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.14" +#define LPFC_DRIVER_VERSION "8.3.15" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v1.2.3-70-g09d2 From e84d96dbb0638186feb526c32810a3400f33d0c8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 15 Jul 2010 10:20:19 +0200 Subject: [SCSI] dpt_i2o: move range check forward The check to test that "bus_no" was valid came after we had already used it as an array offset. This patch moves it forward. Signed-off-by: Dan Carpenter Signed-off-by: James Bottomley --- drivers/scsi/dpt_i2o.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index f2d4df14c31..ffc1edf5e80 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -2640,6 +2640,13 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) continue; } bus_no = buf[0]>>16; + if (bus_no >= MAX_CHANNEL) { /* Something wrong skip it */ + printk(KERN_WARNING + "%s: Channel number %d out of range\n", + pHba->name, bus_no); + continue; + } + scsi_id = buf[1]; scsi_lun = (buf[2]>>8 )&0xff; pDev = pHba->channel[bus_no].device[scsi_id]; @@ -2668,10 +2675,6 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) adpt_i2o_report_hba_unit(pHba, d); adpt_i2o_install_device(pHba, d); - if(bus_no >= MAX_CHANNEL) { // Something wrong skip it - printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no); - continue; - } pDev = pHba->channel[bus_no].device[scsi_id]; if( pDev == NULL){ pDev = -- cgit v1.2.3-70-g09d2 From 2cf75f1c8aa4cab3ace57f9159f1dc85cba69d38 Mon Sep 17 00:00:00 2001 From: "Yanqing_Liu@Dell.com" Date: Wed, 19 May 2010 12:31:36 -0500 Subject: [SCSI] scsi_dh_rdac: Add Dell MD36xxi controller into RDAC device list This patch is to add next generation of Dell iSCSI PowerVault controller MD36xxi into RDAC device list. Signed-off-by: Yanqing Liu Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_rdac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 5b683e42954..b9bcfa4c7d2 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -768,6 +768,7 @@ static const struct scsi_dh_devlist rdac_dev_list[] = { {"DELL", "MD3000i"}, {"DELL", "MD32xx"}, {"DELL", "MD32xxi"}, + {"DELL", "MD36xxi"}, {"LSI", "INF-01-00"}, {"ENGENIO", "INF-01-00"}, {"STK", "FLEXLINE 380"}, -- cgit v1.2.3-70-g09d2 From ba402804ac2447ad41f4919603bf3e6f6db63110 Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Tue, 20 Jul 2010 15:19:10 -0700 Subject: [SCSI] libfc: fix slowpath error from WARN_ON in fc_fcp_send_data This is exposed by a mpio test using EMC CLARiiON targets when LUN tresspassing happens, the burst length from the XFER_READY for the MODE SELECT(10) is 19 bytes, much smaller than FC_MIN_MAX_PAYLOAD as 256 bytes. This patch removes the related two WARN_ON()s. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 8914f1e95b7..a0a3ae7d861 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -580,10 +580,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, fsp, seq_blen, lport->lso_max, t_blen); } - WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); if (t_blen > 512) t_blen &= ~(512 - 1); /* round down to block size */ - WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD); /* won't go below 256 */ sc = fsp->cmd; remaining = seq_blen; -- cgit v1.2.3-70-g09d2 From d058fd31c7f44960b00566bda39c85377f461a7b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 20 Jul 2010 15:19:15 -0700 Subject: [SCSI] fcoe: make it possible to verify fcoe with sparse Analyzing fcoe with sparse currently fails. This is because struct fcoe_rcv_info contains two enum members that have been declared with __attribute__((packed)). Apparently gcc honors this attribute while sparse ignores it. The result is that sizeof(struct fcoe_rcv_info) == sizeof(struct sk_buff::cb) == 48 on a 64-bit system according to gcc, but not according to sparse. The patch below modifies the definition of struct fcoe_rcv_info such that gcc and sparse interpret this structure definition in the same way. The current sparse output is as follows: $ cd linux-2.6.34 $ make C=2 M=drivers/scsi/fcoe modules CHECK drivers/scsi/fcoe/fcoe.c include/scsi/fc_frame.h:81:9: error: invalid bitfield width, -1. CC [M] drivers/scsi/fcoe/fcoe.o CHECK drivers/scsi/fcoe/libfcoe.c include/scsi/fc_frame.h:81:9: error: invalid bitfield width, -1. drivers/scsi/fcoe/libfcoe.c:56:37: error: invalid initializer Signed-off-by: Bart Van Assche Cc: jeykholt@cisco.com Signed-off-by: Robert Love Signed-off-by: James Bottomley --- include/scsi/fc_frame.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h index 4d3e9c7b7c5..15427fab8a5 100644 --- a/include/scsi/fc_frame.h +++ b/include/scsi/fc_frame.h @@ -66,8 +66,8 @@ struct fcoe_rcv_info { struct fc_fcp_pkt *fr_fsp; /* for the corresponding fcp I/O */ u32 fr_crc; u16 fr_max_payload; /* max FC payload */ - enum fc_sof fr_sof; /* start of frame delimiter */ - enum fc_eof fr_eof; /* end of frame delimiter */ + u8 fr_sof; /* start of frame delimiter */ + u8 fr_eof; /* end of frame delimiter */ u8 fr_flags; /* flags - see below */ u8 granted_mac[ETH_ALEN]; /* FCoE MAC address */ }; -- cgit v1.2.3-70-g09d2 From e0d93c5bc47ae270ea38192c9a49f660e0406060 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 20 Jul 2010 15:19:20 -0700 Subject: [SCSI] libfc: IO errors on link down due to cable unplug In this case, sync IO fails with EIO(5) errors as:- "Thread:1 System call error:5 - Input/output error (::pwrite() failed)". This is due to IO time out while libfc doing link down processing to block all rports and if timed out IO was at last retry attempt then it fails to user with EIO error followed by these log messages. [77848.612169] host2: rport bf0015: Delete port [77848.612221] host2: rport e10aef: work delete [77848.612232] host2: rport e10002: work event 3 [77848.612422] sd 2:0:1:1: [sdi] Unhandled error code [77848.612426] sd 2:0:1:1: [sdi] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK [77848.612431] sd 2:0:1:1: [sdi] CDB: Write(10): 2a 00 00 00 11 20 00 00 20 00 [77848.612445] end_request: I/O error, dev sdi, sector 4384 [77848.612553] sd 2:0:1:2: [sdj] Unhandled error code To fix these EIO errors, such timed out incomplete IOs needs to be re-queued without counting retry attempt and this patch does that using DID_REQUEUE scsi code. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_fcp.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index a0a3ae7d861..61a12970bd1 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1971,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) break; } + if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) { + sc_cmd->result = (DID_REQUEUE << 16); + FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n"); + } + spin_lock_irqsave(&si->scsi_queue_lock, flags); list_del(&fsp->list); spin_unlock_irqrestore(&si->scsi_queue_lock, flags); -- cgit v1.2.3-70-g09d2 From 9d4cbc05f32fc0a1024de2a9d5635bc9d180e4ae Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 20 Jul 2010 15:19:26 -0700 Subject: [SCSI] fcoe: cleans up fcoe_disable and fcoe_enable The fc_fabric_logoff and fc_fabric_login are redundant here after recently added fcoe_ctlr_link_down/up to these functions, therefore this patch removes logoff and login to only use link down and up here. This works best for their current usages with fcoe DCB link down or up. This also works well to avoid EIO errors when fcoe DCB link goes down as lport state moves out of ready quickly from fcoe_ctlr_link_down and that allows re-queuing timed out IOs for this case also. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 44a07593de5..d340cf2d857 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1918,8 +1918,8 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp) rtnl_unlock(); if (fcoe) { - fc_fabric_logoff(fcoe->ctlr.lp); fcoe_ctlr_link_down(&fcoe->ctlr); + fcoe_clean_pending_queue(fcoe->ctlr.lp); } else rc = -ENODEV; @@ -1972,12 +1972,10 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp) fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock(); - if (fcoe) { - if (!fcoe_link_ok(fcoe->ctlr.lp)) - fcoe_ctlr_link_up(&fcoe->ctlr); - rc = fc_fabric_login(fcoe->ctlr.lp); - } else + if (!fcoe) rc = -ENODEV; + else if (!fcoe_link_ok(fcoe->ctlr.lp)) + fcoe_ctlr_link_up(&fcoe->ctlr); dev_put(netdev); out_nodev: -- cgit v1.2.3-70-g09d2 From 519e5135e2537c9dbc1cbcc0891b0a936ff5dcd2 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 20 Jul 2010 15:19:32 -0700 Subject: [SCSI] fcoe: adds src and dest mac address checking for fcoe frames This is per FC-BB-5 Annex-D recommendation and per that if address checking fails then drop the frame. FIP code paths are already doing this so only needed for fcoe frames. The src address checking is limited to only fip mode since this might break non-fip mode used in p2p due to used OUI based addressing in some p2p code paths, going forward FIP will be the only mode, therefore limited this to only FIP mode so that it won't break non-fip p2p mode for now. -v2 Removes FCOE packet type checking since fcoe_rcv is registered to receive only FCoE type packets from netdev and it is already checked by netdev. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 20 +++++++++++++++++--- include/scsi/libfcoe.h | 10 ++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d340cf2d857..a120962b25b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1210,6 +1210,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, struct fcoe_interface *fcoe; struct fc_frame_header *fh; struct fcoe_percpu_s *fps; + struct fcoe_port *port; + struct ethhdr *eh; unsigned int cpu; fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); @@ -1227,9 +1229,21 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, skb_tail_pointer(skb), skb_end_pointer(skb), skb->csum, skb->dev ? skb->dev->name : ""); - /* check for FCOE packet type */ - if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { - FCOE_NETDEV_DBG(netdev, "Wrong FC type frame"); + /* check for mac addresses */ + eh = eth_hdr(skb); + port = lport_priv(lport); + if (compare_ether_addr(eh->h_dest, port->data_src_addr) && + compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) && + compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) { + FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n", + eh->h_dest); + goto err; + } + + if (is_fip_mode(&fcoe->ctlr) && + compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) { + FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", + eh->h_source); goto err; } diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index ec13f51531f..81aee1c4c2f 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -170,4 +170,14 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *, u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int); int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *); +/** + * is_fip_mode() - returns true if FIP mode selected. + * @fip: FCoE controller. + */ +static inline bool is_fip_mode(struct fcoe_ctlr *fip) +{ + return fip->state == FIP_ST_ENABLED; +} + + #endif /* _LIBFCOE_H */ -- cgit v1.2.3-70-g09d2 From 42e9041467cf5fd33501b91b27e26807c259c896 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:19:37 -0700 Subject: [SCSI] libfc: convert rport lookup to be RCU safe To allow LLD to do lookups on rports without grabbing a mutex, make them RCU-safe. The caller of lport->tt.rport_lookup will have the choice of holding disc_mutex or the rcu_read_lock(). Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 6 +++--- drivers/scsi/libfc/fc_rport.c | 22 ++++++++++++++++++---- include/scsi/libfc.h | 2 ++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index c7985da8809..d0fa9a0ddc8 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -63,12 +63,12 @@ static void fc_disc_restart(struct fc_disc *); void fc_disc_stop_rports(struct fc_disc *disc) { struct fc_lport *lport; - struct fc_rport_priv *rdata, *next; + struct fc_rport_priv *rdata; lport = disc->lport; mutex_lock(&disc->disc_mutex); - list_for_each_entry_safe(rdata, next, &disc->rports, peers) + list_for_each_entry_rcu(rdata, &disc->rports, peers) lport->tt.rport_logoff(rdata); mutex_unlock(&disc->disc_mutex); } @@ -292,7 +292,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) * Skip ports which were never discovered. These are the dNS port * and ports which were created by PLOGI. */ - list_for_each_entry(rdata, &disc->rports, peers) { + list_for_each_entry_rcu(rdata, &disc->rports, peers) { if (!rdata->disc_id) continue; if (rdata->disc_id == disc->disc_id) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 363cde30c94..6b569732f89 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -95,13 +95,15 @@ static const char *fc_rport_state_names[] = { * fc_rport_lookup() - Lookup a remote port by port_id * @lport: The local port to lookup the remote port on * @port_id: The remote port ID to look up + * + * The caller must hold either disc_mutex or rcu_read_lock(). */ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, u32 port_id) { struct fc_rport_priv *rdata; - list_for_each_entry(rdata, &lport->disc.rports, peers) + list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) if (rdata->ids.port_id == port_id) return rdata; return NULL; @@ -146,10 +148,22 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); INIT_WORK(&rdata->event_work, fc_rport_work); if (port_id != FC_FID_DIR_SERV) - list_add(&rdata->peers, &lport->disc.rports); + list_add_rcu(&rdata->peers, &lport->disc.rports); return rdata; } +/** + * fc_rport_free_rcu() - Free a remote port + * @rcu: The rcu_head structure inside the remote port + */ +static void fc_rport_free_rcu(struct rcu_head *rcu) +{ + struct fc_rport_priv *rdata; + + rdata = container_of(rcu, struct fc_rport_priv, rcu); + kfree(rdata); +} + /** * fc_rport_destroy() - Free a remote port after last reference is released * @kref: The remote port's kref @@ -159,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref) struct fc_rport_priv *rdata; rdata = container_of(kref, struct fc_rport_priv, kref); - kfree(rdata); + call_rcu(&rdata->rcu, fc_rport_free_rcu); } /** @@ -334,7 +348,7 @@ static void fc_rport_work(struct work_struct *work) mutex_unlock(&rdata->rp_mutex); } else { FC_RPORT_DBG(rdata, "work delete\n"); - list_del(&rdata->peers); + list_del_rcu(&rdata->peers); mutex_unlock(&rdata->rp_mutex); kref_put(&rdata->kref, lport->tt.rport_destroy); } diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 6d78df77dab..b0310b9b346 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -195,6 +195,7 @@ struct fc_rport_libfc_priv { * @rp_mutex: The mutex that protects the remote port * @retry_work: Handle for retries * @event_callback: Callback when READY, FAILED or LOGO states complete + * @rcu: Structure used for freeing in an RCU-safe manner */ struct fc_rport_priv { struct fc_lport *local_port; @@ -217,6 +218,7 @@ struct fc_rport_priv { struct list_head peers; struct work_struct event_work; u32 supported_classes; + struct rcu_head rcu; }; /** -- cgit v1.2.3-70-g09d2 From f90377abcab2e305450ee76a0f9042907560c5d8 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:19:42 -0700 Subject: [SCSI] libfc: provide space for LLD after remote port structure Add pre-zeroed space after the allocation for fc_rport_priv for use by the lower-level driver. This is primarily for VN2VN FIP mode, but could be used in other ways someday. The space required is specified in lport->rport_priv_size. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 2 +- include/scsi/libfc.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 6b569732f89..6d68482649c 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -127,7 +127,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, if (rdata) return rdata; - rdata = kzalloc(sizeof(*rdata), GFP_KERNEL); + rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL); if (!rdata) return NULL; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index b0310b9b346..fcbee8c38b0 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -799,6 +799,7 @@ struct fc_disc { * @mfs: The maximum Fibre Channel payload size * @max_retry_count: The maximum retry attempts * @max_rport_retry_count: The maximum remote port retry attempts + * @rport_priv_size: Size needed by driver after struct fc_rport_priv * @lro_xid: The maximum XID for LRO * @lso_max: The maximum large offload send size * @fcts: FC-4 type mask @@ -848,6 +849,7 @@ struct fc_lport { u32 mfs; u8 max_retry_count; u8 max_rport_retry_count; + u16 rport_priv_size; u16 link_speed; u16 link_supported_speeds; u16 lro_xid; -- cgit v1.2.3-70-g09d2 From fdb068c6cd6e30d43664f856d3530715a5742713 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:19:47 -0700 Subject: [SCSI] libfcoe: convert FIP to lock with mutex instead of spin lock It turns out most of the FIP work is now done from worker threads or process context now, so there's no need to use a spin lock. Change to use mutex instead of spin lock and delayed_work instead of a timer. This will make it nicer for the VN_port to VN_port feature that will interact more with the libfc layers requiring that spinlocks not be held. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 116 +++++++++++++++++++++----------------------- include/scsi/libfcoe.h | 9 +--- 2 files changed, 57 insertions(+), 68 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index f009191063f..e510888e78c 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -113,7 +113,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip) fip->state = FIP_ST_LINK_WAIT; fip->mode = FIP_ST_AUTO; INIT_LIST_HEAD(&fip->fcfs); - spin_lock_init(&fip->lock); + mutex_init(&fip->ctlr_mutex); fip->flogi_oxid = FC_XID_UNKNOWN; setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip); INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work); @@ -159,10 +159,10 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) cancel_work_sync(&fip->recv_work); skb_queue_purge(&fip->fip_recv_list); - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); fip->state = FIP_ST_DISABLED; fcoe_ctlr_reset_fcfs(fip); - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); del_timer_sync(&fip->timer); cancel_work_sync(&fip->timer_work); } @@ -255,19 +255,19 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) */ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) { - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) { - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); fc_linkup(fip->lp); } else if (fip->state == FIP_ST_LINK_WAIT) { fip->state = fip->mode; - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); if (fip->state == FIP_ST_AUTO) LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); fc_linkup(fip->lp); fcoe_ctlr_solicit(fip, NULL); } else - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); } EXPORT_SYMBOL(fcoe_ctlr_link_up); @@ -300,11 +300,11 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) int link_dropped; LIBFCOE_FIP_DBG(fip, "link down.\n"); - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); fcoe_ctlr_reset(fip); link_dropped = fip->state != FIP_ST_LINK_WAIT; fip->state = FIP_ST_LINK_WAIT; - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); if (link_dropped) fc_linkdown(fip->lp); @@ -577,12 +577,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) unsigned long sel_time = 0; struct fcoe_dev_stats *stats; + stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); + list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2; if (fip->sel_fcf == fcf) { if (time_after(jiffies, deadline)) { - stats = per_cpu_ptr(fip->lp->dev_stats, - smp_processor_id()); stats->MissDiscAdvCount++; printk(KERN_INFO "libfcoe: host%d: " "Missing Discovery Advertisement " @@ -601,8 +601,6 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) WARN_ON(!fip->fcf_count); fip->fcf_count--; kfree(fcf); - stats = per_cpu_ptr(fip->lp->dev_stats, - smp_processor_id()); stats->VLinkFailureCount++; } else { if (time_after(next_timer, deadline)) @@ -612,6 +610,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) sel_time = fcf->time; } } + put_cpu(); if (sel_time && !fip->sel_fcf && !fip->sel_time) { sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); fip->sel_time = sel_time; @@ -768,7 +767,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) if (fcoe_ctlr_parse_adv(fip, skb, &new)) return; - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); first = list_empty(&fip->fcfs); found = NULL; list_for_each_entry(fcf, &fip->fcfs, list) { @@ -847,7 +846,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) mod_timer(&fip->timer, fip->sel_time); } out: - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); } /** @@ -1108,11 +1107,12 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, if (is_vn_port) fc_lport_reset(vn_port); else { - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); per_cpu_ptr(lport->dev_stats, - smp_processor_id())->VLinkFailureCount++; + get_cpu())->VLinkFailureCount++; + put_cpu(); fcoe_ctlr_reset(fip); - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); fc_lport_reset(fip->lp); fcoe_ctlr_solicit(fip, NULL); @@ -1166,7 +1166,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len) goto drop; - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); state = fip->state; if (state == FIP_ST_AUTO) { fip->map_dest = 0; @@ -1174,7 +1174,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) state = FIP_ST_ENABLED; LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); } - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); if (state != FIP_ST_ENABLED) goto drop; @@ -1240,19 +1240,38 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip) /** * fcoe_ctlr_timeout() - FIP timeout handler * @arg: The FCoE controller that timed out - * - * Ages FCFs. Triggers FCF selection if possible. Sends keep-alives. */ static void fcoe_ctlr_timeout(unsigned long arg) { struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; + + schedule_work(&fip->timer_work); +} + +/** + * fcoe_ctlr_timer_work() - Worker thread function for timer work + * @work: Handle to a FCoE controller + * + * Ages FCFs. Triggers FCF selection if possible. + * Sends keep-alives and resets. + */ +static void fcoe_ctlr_timer_work(struct work_struct *work) +{ + struct fcoe_ctlr *fip; + struct fc_lport *vport; + u8 *mac; + u8 reset = 0; + u8 send_ctlr_ka = 0; + u8 send_port_ka = 0; struct fcoe_fcf *sel; struct fcoe_fcf *fcf; unsigned long next_timer; - spin_lock_bh(&fip->lock); + fip = container_of(work, struct fcoe_ctlr, timer_work); + + mutex_lock(&fip->ctlr_mutex); if (fip->state == FIP_ST_DISABLED) { - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); return; } @@ -1286,7 +1305,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) "FIP Fibre-Channel Forwarder timed out. " "Starting FCF discovery.\n", fip->lp->host->host_no); - fip->reset_req = 1; + reset = 1; schedule_work(&fip->timer_work); } } @@ -1294,7 +1313,7 @@ static void fcoe_ctlr_timeout(unsigned long arg) if (sel && !sel->fd_flags) { if (time_after_eq(jiffies, fip->ctlr_ka_time)) { fip->ctlr_ka_time = jiffies + sel->fka_period; - fip->send_ctlr_ka = 1; + send_ctlr_ka = 1; } if (time_after(next_timer, fip->ctlr_ka_time)) next_timer = fip->ctlr_ka_time; @@ -1302,37 +1321,14 @@ static void fcoe_ctlr_timeout(unsigned long arg) if (time_after_eq(jiffies, fip->port_ka_time)) { fip->port_ka_time = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); - fip->send_port_ka = 1; + send_port_ka = 1; } if (time_after(next_timer, fip->port_ka_time)) next_timer = fip->port_ka_time; } if (!list_empty(&fip->fcfs)) mod_timer(&fip->timer, next_timer); - if (fip->send_ctlr_ka || fip->send_port_ka) - schedule_work(&fip->timer_work); - spin_unlock_bh(&fip->lock); -} - -/** - * fcoe_ctlr_timer_work() - Worker thread function for timer work - * @work: Handle to a FCoE controller - * - * Sends keep-alives and resets which must not - * be called from the timer directly, since they use a mutex. - */ -static void fcoe_ctlr_timer_work(struct work_struct *work) -{ - struct fcoe_ctlr *fip; - struct fc_lport *vport; - u8 *mac; - int reset; - - fip = container_of(work, struct fcoe_ctlr, timer_work); - spin_lock_bh(&fip->lock); - reset = fip->reset_req; - fip->reset_req = 0; - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); if (reset) { fc_lport_reset(fip->lp); @@ -1340,12 +1336,10 @@ static void fcoe_ctlr_timer_work(struct work_struct *work) fcoe_ctlr_solicit(fip, NULL); } - if (fip->send_ctlr_ka) { - fip->send_ctlr_ka = 0; + if (send_ctlr_ka) fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr); - } - if (fip->send_port_ka) { - fip->send_port_ka = 0; + + if (send_port_ka) { mutex_lock(&fip->lp->lp_mutex); mac = fip->get_src_addr(fip->lp); fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac); @@ -1402,9 +1396,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && fip->flogi_oxid == ntohs(fh->fh_ox_id)) { - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) { - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); return -EINVAL; } fip->state = FIP_ST_NON_FIP; @@ -1424,13 +1418,13 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, fip->map_dest = 0; } fip->flogi_oxid = FC_XID_UNKNOWN; - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id); } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { /* * Save source MAC for point-to-point responses. */ - spin_lock_bh(&fip->lock); + mutex_lock(&fip->ctlr_mutex); if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) { memcpy(fip->dest_addr, sa, ETH_ALEN); fip->map_dest = 0; @@ -1439,7 +1433,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, "Setting non-FIP mode\n"); fip->state = FIP_ST_NON_FIP; } - spin_unlock_bh(&fip->lock); + mutex_unlock(&fip->ctlr_mutex); } return 0; } diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 81aee1c4c2f..7d18b500f2c 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -75,14 +75,12 @@ enum fip_state { * @flogi_count: number of FLOGI attempts in AUTO mode. * @map_dest: use the FC_MAP mode for destination MAC addresses. * @spma: supports SPMA server-provided MACs mode - * @send_ctlr_ka: need to send controller keep alive - * @send_port_ka: need to send port keep alives * @dest_addr: MAC address of the selected FC forwarder. * @ctl_src_addr: the native MAC address of our local port. * @send: LLD-supplied function to handle sending FIP Ethernet frames * @update_mac: LLD-supplied function to handle changes to MAC addresses. * @get_src_addr: LLD-supplied function to supply a source MAC address. - * @lock: lock protecting this structure. + * @ctlr_mutex: lock protecting this structure. * * This structure is used by all FCoE drivers. It contains information * needed by all FCoE low-level drivers (LLDs) as well as internal state @@ -106,18 +104,15 @@ struct fcoe_ctlr { u16 user_mfs; u16 flogi_oxid; u8 flogi_count; - u8 reset_req; u8 map_dest; u8 spma; - u8 send_ctlr_ka; - u8 send_port_ka; u8 dest_addr[ETH_ALEN]; u8 ctl_src_addr[ETH_ALEN]; void (*send)(struct fcoe_ctlr *, struct sk_buff *); void (*update_mac)(struct fc_lport *, u8 *addr); u8 * (*get_src_addr)(struct fc_lport *); - spinlock_t lock; + struct mutex ctlr_mutex; }; /** -- cgit v1.2.3-70-g09d2 From 0685230c59b5482e04ab50e7afc51119ceaba651 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:19:53 -0700 Subject: [SCSI] libfc: add discovery-private pointer for LLD For VN_port to VN_port mode, FIP will do discovery and needs a way to find its state from the local port or discovery structure. It seems that any other LLD that implements its own discovery would also need something like this. Replace disc->lport with disc->priv, and use container_of to find the lport. We could use disc->priv for that, but container_of is smaller and faster. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_disc.c | 14 +++++++------- drivers/scsi/libfc/fc_libfc.h | 2 +- include/scsi/libfc.h | 9 +++++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index d0fa9a0ddc8..04474556f2d 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -65,7 +65,7 @@ void fc_disc_stop_rports(struct fc_disc *disc) struct fc_lport *lport; struct fc_rport_priv *rdata; - lport = disc->lport; + lport = fc_disc_lport(disc); mutex_lock(&disc->disc_mutex); list_for_each_entry_rcu(rdata, &disc->rports, peers) @@ -96,7 +96,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, LIST_HEAD(disc_ports); struct fc_disc_port *dp, *next; - lport = disc->lport; + lport = fc_disc_lport(disc); FC_DISC_DBG(disc, "Received an RSCN event\n"); @@ -275,7 +275,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, */ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) { - struct fc_lport *lport = disc->lport; + struct fc_lport *lport = fc_disc_lport(disc); struct fc_rport_priv *rdata; FC_DISC_DBG(disc, "Discovery complete\n"); @@ -313,7 +313,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) */ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) { - struct fc_lport *lport = disc->lport; + struct fc_lport *lport = fc_disc_lport(disc); unsigned long delay = 0; FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n", @@ -353,7 +353,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) static void fc_disc_gpn_ft_req(struct fc_disc *disc) { struct fc_frame *fp; - struct fc_lport *lport = disc->lport; + struct fc_lport *lport = fc_disc_lport(disc); WARN_ON(!fc_lport_test_ready(lport)); @@ -396,7 +396,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) struct fc_rport_identifiers ids; struct fc_rport_priv *rdata; - lport = disc->lport; + lport = fc_disc_lport(disc); disc->seq_count++; /* @@ -733,7 +733,7 @@ int fc_disc_init(struct fc_lport *lport) mutex_init(&disc->disc_mutex); INIT_LIST_HEAD(&disc->rports); - disc->lport = lport; + disc->priv = lport; return 0; } diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h index f5c0ca4b6ef..16d2162dda1 100644 --- a/drivers/scsi/libfc/fc_libfc.h +++ b/drivers/scsi/libfc/fc_libfc.h @@ -52,7 +52,7 @@ extern unsigned int fc_debug_logging; #define FC_DISC_DBG(disc, fmt, args...) \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \ printk(KERN_INFO "host%u: disc: " fmt, \ - (disc)->lport->host->host_no, \ + fc_disc_lport(disc)->host->host_no, \ ##args)) #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index fcbee8c38b0..5f64e593cca 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -739,7 +739,7 @@ struct libfc_function_template { * @buf_len: Length of the discovery buffer * @disc_id: Discovery ID * @rports: List of discovered remote ports - * @lport: The local port that discovery is for + * @priv: Private pointer for use by discovery code * @disc_mutex: Mutex that protects the discovery context * @partial_buf: Partial name buffer (if names are returned * in multiple frames) @@ -755,7 +755,7 @@ struct fc_disc { u16 disc_id; struct list_head rports; - struct fc_lport *lport; + void *priv; struct mutex disc_mutex; struct fc_gpn_ft_resp partial_buf; struct delayed_work disc_work; @@ -1003,6 +1003,11 @@ void fc_rport_terminate_io(struct fc_rport *); *****************************/ int fc_disc_init(struct fc_lport *); +static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc) +{ + return container_of(disc, struct fc_lport, disc); +} + /* * FCP LAYER *****************************/ -- cgit v1.2.3-70-g09d2 From 3d902ac09a2812b359edf633425d1327a18399e9 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:19:58 -0700 Subject: [SCSI] libfcoe: fcoe: fnic: change fcoe_ctlr_init interface to specify mode There are three modes that libfcoe currently supports, and a new one is coming. Change the fcoe_ctlr_init() interface to add the mode desired. This should not change any functionality. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 2 +- drivers/scsi/fcoe/libfcoe.c | 4 ++-- drivers/scsi/fnic/fnic_main.c | 4 ++-- include/scsi/libfcoe.h | 11 ++++++++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index a120962b25b..9d64e08305c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -357,7 +357,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) /* * Initialize FIP. */ - fcoe_ctlr_init(&fcoe->ctlr); + fcoe_ctlr_init(&fcoe->ctlr, FIP_MODE_AUTO); fcoe->ctlr.send = fcoe_fip_send; fcoe->ctlr.update_mac = fcoe_update_src_mac; fcoe->ctlr.get_src_addr = fcoe_get_src_mac; diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index e510888e78c..76056e4c929 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -108,10 +108,10 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) * fcoe_ctlr_init() - Initialize the FCoE Controller instance * @fip: The FCoE controller to initialize */ -void fcoe_ctlr_init(struct fcoe_ctlr *fip) +void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) { fip->state = FIP_ST_LINK_WAIT; - fip->mode = FIP_ST_AUTO; + fip->mode = mode; INIT_LIST_HEAD(&fip->fcfs); mutex_init(&fip->ctlr_mutex); fip->flogi_oxid = FC_XID_UNKNOWN; diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 265e73d9cd6..d0fe1c3345b 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -617,7 +617,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev, fnic->ctlr.send = fnic_eth_send; fnic->ctlr.update_mac = fnic_update_mac; fnic->ctlr.get_src_addr = fnic_get_mac; - fcoe_ctlr_init(&fnic->ctlr); if (fnic->config.flags & VFCF_FIP_CAPABLE) { shost_printk(KERN_INFO, fnic->lport->host, "firmware supports FIP\n"); @@ -625,10 +624,11 @@ static int __devinit fnic_probe(struct pci_dev *pdev, vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0); vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS); vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); + fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO); } else { shost_printk(KERN_INFO, fnic->lport->host, "firmware uses non-FIP mode\n"); - fnic->ctlr.mode = FIP_ST_NON_FIP; + fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP); } fnic->state = FNIC_IN_FC_MODE; diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 7d18b500f2c..1a84a3182da 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -54,6 +54,15 @@ enum fip_state { FIP_ST_ENABLED, }; +/* + * Modes: + * The mode is the state that is to be entered after link up. + * It must not change after fcoe_ctlr_init() sets it. + */ +#define FIP_MODE_AUTO FIP_ST_AUTO +#define FIP_MODE_NON_FIP FIP_ST_NON_FIP +#define FIP_MODE_FABRIC FIP_ST_ENABLED + /** * struct fcoe_ctlr - FCoE Controller and FIP state * @state: internal FIP state for network link and FIP or non-FIP mode. @@ -152,7 +161,7 @@ struct fcoe_fcf { }; /* FIP API functions */ -void fcoe_ctlr_init(struct fcoe_ctlr *); +void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state); void fcoe_ctlr_destroy(struct fcoe_ctlr *); void fcoe_ctlr_link_up(struct fcoe_ctlr *); int fcoe_ctlr_link_down(struct fcoe_ctlr *); -- cgit v1.2.3-70-g09d2 From 3726f3584e113697b68d3d4ff1ecf1042a06f800 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:03 -0700 Subject: [SCSI] libfc: Add local port point-to-multipoint flag For VN_port to VN_port mode, the transport sets the port_id and there's no lport FLOGI. This is similar to FC loop mode. Add a point_to_multipoint flag that indicates the local port is in point-to-multipoint mode. This skips FLOGI and discovery. It also skips resetting the port_id on resets other than link down. Add function fc_lport_set_local_id() that sets the local port_id. This is called by libfcoe on behalf of the low-level driver to set the port_id when the link comes up. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 36 +++++++++++++++++++++++++++++++++++- include/scsi/libfc.h | 2 ++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 79c9e3ccd34..f7bff2cad4e 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -754,6 +754,34 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, lport->tt.lport_set_port_id(lport, port_id, fp); } +/** + * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint + * @lport: The local port which will have its Port ID set. + * @port_id: The new port ID. + * + * Called by the lower-level driver when transport sets the local port_id. + * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and + * discovery to be skipped. + */ +void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id) +{ + mutex_lock(&lport->lp_mutex); + + fc_lport_set_port_id(lport, port_id, NULL); + + switch (lport->state) { + case LPORT_ST_RESET: + case LPORT_ST_FLOGI: + if (port_id) + fc_lport_enter_ready(lport); + break; + default: + break; + } + mutex_unlock(&lport->lp_mutex); +} +EXPORT_SYMBOL(fc_lport_set_local_id); + /** * fc_lport_recv_flogi_req() - Receive a FLOGI request * @sp_in: The sequence the FLOGI is on @@ -954,7 +982,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport) lport->tt.exch_mgr_reset(lport, 0, 0); fc_host_fabric_name(lport->host) = 0; - if (lport->port_id) + if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up)) fc_lport_set_port_id(lport, 0, NULL); } @@ -1536,6 +1564,12 @@ void fc_lport_enter_flogi(struct fc_lport *lport) fc_lport_state_enter(lport, LPORT_ST_FLOGI); + if (lport->point_to_multipoint) { + if (lport->port_id) + fc_lport_enter_ready(lport); + return; + } + fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) return fc_lport_error(lport, fp); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 5f64e593cca..bd0560509ce 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -846,6 +846,7 @@ struct fc_lport { u32 lro_enabled:1; u32 does_npiv:1; u32 npiv_enabled:1; + u32 point_to_multipoint:1; u32 mfs; u8 max_retry_count; u8 max_rport_retry_count; @@ -991,6 +992,7 @@ int fc_set_mfs(struct fc_lport *, u32 mfs); struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize); struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id); int fc_lport_bsg_request(struct fc_bsg_job *); +void fc_lport_set_local_id(struct fc_lport *, u32 port_id); /* * REMOTE PORT LAYER -- cgit v1.2.3-70-g09d2 From a7b12a279faaad26837276065104a1f9cf60e962 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:08 -0700 Subject: [SCSI] libfc: add FLOGI state to rport for VN2VN The FIP proposal for VN_port to VN_port point-to-multipoint operation requires a FLOGI be sent to each remote port. The FLOGI is sent with the assigned S_ID and D_IDs of the local and remote ports. This and the response get FIP-encapsulated for Ethernet. Add FLOGI state to the remote port state machine. This will be skipped if not in point-to-multipoint mode. To reduce a little duplication between PLOGI and FLOGI response handling, added fc_rport_login_complete(), which handles the parameters for the rdata struct. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 4 +- drivers/scsi/libfc/fc_rport.c | 290 ++++++++++++++++++++++++++++++++++++++++-- include/scsi/fc/fc_els.h | 2 + include/scsi/libfc.h | 4 + 4 files changed, 286 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f7bff2cad4e..ec9850c4617 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -906,10 +906,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: - recv = fc_lport_recv_flogi_req; + if (!lport->point_to_multipoint) + recv = fc_lport_recv_flogi_req; break; case ELS_LOGO: - fh = fc_frame_header_get(fp); if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) recv = fc_lport_recv_logo_req; break; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 6d68482649c..4d6adf29b4f 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -60,6 +60,7 @@ struct workqueue_struct *rport_event_queue; +static void fc_rport_enter_flogi(struct fc_rport_priv *); static void fc_rport_enter_plogi(struct fc_rport_priv *); static void fc_rport_enter_prli(struct fc_rport_priv *); static void fc_rport_enter_rtv(struct fc_rport_priv *); @@ -82,6 +83,8 @@ static void fc_rport_work(struct work_struct *); static const char *fc_rport_state_names[] = { [RPORT_ST_INIT] = "Init", + [RPORT_ST_FLOGI] = "FLOGI", + [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT", [RPORT_ST_PLOGI] = "PLOGI", [RPORT_ST_PRLI] = "PRLI", [RPORT_ST_RTV] = "RTV", @@ -207,7 +210,7 @@ EXPORT_SYMBOL(fc_set_rport_loss_tmo); /** * fc_plogi_get_maxframe() - Get the maximum payload from the common service * parameters in a FLOGI frame - * @flp: The FLOGI payload + * @flp: The FLOGI or PLOGI payload * @maxval: The maximum frame size upper limit; this may be less than what * is in the service parameters */ @@ -344,7 +347,7 @@ static void fc_rport_work(struct work_struct *work) rdata->major_retries++; rdata->event = RPORT_EV_NONE; FC_RPORT_DBG(rdata, "work restart\n"); - fc_rport_enter_plogi(rdata); + fc_rport_enter_flogi(rdata); mutex_unlock(&rdata->rp_mutex); } else { FC_RPORT_DBG(rdata, "work delete\n"); @@ -397,7 +400,7 @@ int fc_rport_login(struct fc_rport_priv *rdata) break; default: FC_RPORT_DBG(rdata, "Login to port\n"); - fc_rport_enter_plogi(rdata); + fc_rport_enter_flogi(rdata); break; } mutex_unlock(&rdata->rp_mutex); @@ -499,6 +502,9 @@ static void fc_rport_timeout(struct work_struct *work) mutex_lock(&rdata->rp_mutex); switch (rdata->rp_state) { + case RPORT_ST_FLOGI: + fc_rport_enter_flogi(rdata); + break; case RPORT_ST_PLOGI: fc_rport_enter_plogi(rdata); break; @@ -514,6 +520,7 @@ static void fc_rport_timeout(struct work_struct *work) case RPORT_ST_ADISC: fc_rport_enter_adisc(rdata); break; + case RPORT_ST_PLOGI_WAIT: case RPORT_ST_READY: case RPORT_ST_INIT: case RPORT_ST_DELETE: @@ -538,6 +545,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) fc_rport_state(rdata), rdata->retries); switch (rdata->rp_state) { + case RPORT_ST_FLOGI: case RPORT_ST_PLOGI: case RPORT_ST_LOGO: rdata->flags &= ~FC_RP_STARTED; @@ -550,6 +558,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) case RPORT_ST_ADISC: fc_rport_enter_logo(rdata); break; + case RPORT_ST_PLOGI_WAIT: case RPORT_ST_DELETE: case RPORT_ST_READY: case RPORT_ST_INIT: @@ -592,7 +601,260 @@ static void fc_rport_error_retry(struct fc_rport_priv *rdata, } /** - * fc_rport_plogi_recv_resp() - Handler for ELS PLOGI responses + * fc_rport_login_complete() - Handle parameters and completion of p-mp login. + * @rdata: The remote port which we logged into or which logged into us. + * @fp: The FLOGI or PLOGI request or response frame + * + * Returns non-zero error if a problem is detected with the frame. + * Does not free the frame. + * + * This is only used in point-to-multipoint mode for FIP currently. + */ +static int fc_rport_login_complete(struct fc_rport_priv *rdata, + struct fc_frame *fp) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_els_flogi *flogi; + unsigned int e_d_tov; + u16 csp_flags; + + flogi = fc_frame_payload_get(fp, sizeof(*flogi)); + if (!flogi) + return -EINVAL; + + csp_flags = ntohs(flogi->fl_csp.sp_features); + + if (fc_frame_payload_op(fp) == ELS_FLOGI) { + if (csp_flags & FC_SP_FT_FPORT) { + FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n"); + return -EINVAL; + } + } else { + + /* + * E_D_TOV is not valid on an incoming FLOGI request. + */ + e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov); + if (csp_flags & FC_SP_FT_EDTR) + e_d_tov /= 1000000; + if (e_d_tov > rdata->e_d_tov) + rdata->e_d_tov = e_d_tov; + } + rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs); + return 0; +} + +/** + * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode + * @sp: The sequence that the FLOGI was on + * @fp: The FLOGI response frame + * @rp_arg: The remote port that received the FLOGI response + */ +void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, + void *rp_arg) +{ + struct fc_rport_priv *rdata = rp_arg; + struct fc_lport *lport = rdata->local_port; + struct fc_els_flogi *flogi; + unsigned int r_a_tov; + + FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp)); + + if (fp == ERR_PTR(-FC_EX_CLOSED)) + return; + + mutex_lock(&rdata->rp_mutex); + + if (rdata->rp_state != RPORT_ST_FLOGI) { + FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state " + "%s\n", fc_rport_state(rdata)); + if (IS_ERR(fp)) + goto err; + goto out; + } + + if (IS_ERR(fp)) { + fc_rport_error(rdata, fp); + goto err; + } + + if (fc_frame_payload_op(fp) != ELS_LS_ACC) + goto bad; + if (fc_rport_login_complete(rdata, fp)) + goto bad; + + flogi = fc_frame_payload_get(fp, sizeof(*flogi)); + if (!flogi) + goto bad; + r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov); + if (r_a_tov > rdata->r_a_tov) + rdata->r_a_tov = r_a_tov; + + if (rdata->ids.port_name < lport->wwpn) + fc_rport_enter_plogi(rdata); + else + fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); +out: + fc_frame_free(fp); +err: + mutex_unlock(&rdata->rp_mutex); + kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); + return; +bad: + FC_RPORT_DBG(rdata, "Bad FLOGI response\n"); + fc_rport_error_retry(rdata, fp); + goto out; +} + +/** + * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp + * @rdata: The remote port to send a FLOGI to + * + * Locking Note: The rport lock is expected to be held before calling + * this routine. + */ +static void fc_rport_enter_flogi(struct fc_rport_priv *rdata) +{ + struct fc_lport *lport = rdata->local_port; + struct fc_frame *fp; + + if (!lport->point_to_multipoint) + return fc_rport_enter_plogi(rdata); + + FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n", + fc_rport_state(rdata)); + + fc_rport_state_enter(rdata, RPORT_ST_FLOGI); + + fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); + if (!fp) + return fc_rport_error_retry(rdata, fp); + + if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI, + fc_rport_flogi_resp, rdata, + 2 * lport->r_a_tov)) + fc_rport_error_retry(rdata, NULL); + else + kref_get(&rdata->kref); +} + +/** + * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode + * @lport: The local port that received the PLOGI request + * @sp: The sequence that the PLOGI request was on + * @rx_fp: The PLOGI request frame + */ +static void fc_rport_recv_flogi_req(struct fc_lport *lport, + struct fc_seq *sp, struct fc_frame *rx_fp) +{ + struct fc_disc *disc; + struct fc_els_flogi *flp; + struct fc_rport_priv *rdata; + struct fc_frame *fp = rx_fp; + struct fc_exch *ep; + struct fc_frame_header *fh; + struct fc_seq_els_data rjt_data; + u32 sid, f_ctl; + + rjt_data.fp = NULL; + fh = fc_frame_header_get(fp); + sid = ntoh24(fh->fh_s_id); + + FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); + + disc = &lport->disc; + mutex_lock(&disc->disc_mutex); + + if (!lport->point_to_multipoint) { + rjt_data.reason = ELS_RJT_UNSUP; + rjt_data.explan = ELS_EXPL_NONE; + goto reject; + } + + flp = fc_frame_payload_get(fp, sizeof(*flp)); + if (!flp) { + rjt_data.reason = ELS_RJT_LOGIC; + rjt_data.explan = ELS_EXPL_INV_LEN; + goto reject; + } + + rdata = lport->tt.rport_lookup(lport, sid); + if (!rdata) { + rjt_data.reason = ELS_RJT_FIP; + rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; + goto reject; + } + mutex_lock(&rdata->rp_mutex); + + FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n", + fc_rport_state(rdata)); + + switch (rdata->rp_state) { + case RPORT_ST_INIT: + case RPORT_ST_LOGO: + case RPORT_ST_DELETE: + mutex_unlock(&rdata->rp_mutex); + rjt_data.reason = ELS_RJT_FIP; + rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; + goto reject; + case RPORT_ST_FLOGI: + case RPORT_ST_PLOGI_WAIT: + case RPORT_ST_PLOGI: + break; + case RPORT_ST_PRLI: + case RPORT_ST_RTV: + case RPORT_ST_READY: + case RPORT_ST_ADISC: + /* + * Set the remote port to be deleted and to then restart. + * This queues work to be sure exchanges are reset. + */ + fc_rport_enter_delete(rdata, RPORT_EV_LOGO); + mutex_unlock(&rdata->rp_mutex); + rjt_data.reason = ELS_RJT_BUSY; + rjt_data.explan = ELS_EXPL_NONE; + goto reject; + } + if (fc_rport_login_complete(rdata, fp)) { + mutex_unlock(&rdata->rp_mutex); + rjt_data.reason = ELS_RJT_LOGIC; + rjt_data.explan = ELS_EXPL_NONE; + goto reject; + } + fc_frame_free(rx_fp); + + fp = fc_frame_alloc(lport, sizeof(*flp)); + if (!fp) + goto out; + + sp = lport->tt.seq_start_next(sp); + fc_flogi_fill(lport, fp); + flp = fc_frame_payload_get(fp, sizeof(*flp)); + flp->fl_cmd = ELS_LS_ACC; + + f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; + ep = fc_seq_exch(sp); + fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, + FC_TYPE_ELS, f_ctl, 0); + lport->tt.seq_send(lport, sp, fp); + + if (rdata->ids.port_name < lport->wwpn) + fc_rport_enter_plogi(rdata); + else + fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); +out: + mutex_unlock(&rdata->rp_mutex); + mutex_unlock(&disc->disc_mutex); + return; + +reject: + mutex_unlock(&disc->disc_mutex); + lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); +} + +/** + * fc_rport_plogi_resp() - Handler for ELS PLOGI responses * @sp: The sequence the PLOGI is on * @fp: The PLOGI response frame * @rdata_arg: The remote port that sent the PLOGI response @@ -607,7 +869,6 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_rport_priv *rdata = rdata_arg; struct fc_lport *lport = rdata->local_port; struct fc_els_flogi *plp = NULL; - unsigned int tov; u16 csp_seq; u16 cssp_seq; u8 op; @@ -635,11 +896,8 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); - tov = ntohl(plp->fl_csp.sp_e_d_tov); - if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR) - tov /= 1000000; - if (tov > rdata->e_d_tov) - rdata->e_d_tov = tov; + if (lport->point_to_multipoint) + fc_rport_login_complete(rdata, fp); csp_seq = ntohs(plp->fl_csp.sp_tot_seq); cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); if (cssp_seq < csp_seq) @@ -677,6 +935,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { + FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__); fc_rport_error_retry(rdata, fp); return; } @@ -1041,7 +1300,7 @@ static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); - fc_rport_enter_plogi(rdata); + fc_rport_enter_flogi(rdata); } else { FC_RPORT_DBG(rdata, "ADISC OK\n"); fc_rport_enter_ready(rdata); @@ -1291,12 +1550,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_seq_els_data els_data; /* - * Handle PLOGI and LOGO requests separately, since they + * Handle FLOGI, PLOGI and LOGO requests separately, since they * don't require prior login. * Check for unsupported opcodes first and reject them. * For some ops, it would be incorrect to reject with "PLOGI required". */ switch (fc_frame_payload_op(fp)) { + case ELS_FLOGI: + fc_rport_recv_flogi_req(lport, sp, fp); + break; case ELS_PLOGI: fc_rport_recv_plogi_req(lport, sp, fp); break; @@ -1386,6 +1648,9 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, case RPORT_ST_INIT: FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); break; + case RPORT_ST_PLOGI_WAIT: + FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n"); + break; case RPORT_ST_PLOGI: FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); if (rdata->ids.port_name < lport->wwpn) { @@ -1403,6 +1668,7 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, "- ignored for now\n", rdata->rp_state); /* XXX TBD - should reset */ break; + case RPORT_ST_FLOGI: case RPORT_ST_DELETE: case RPORT_ST_LOGO: FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", diff --git a/include/scsi/fc/fc_els.h b/include/scsi/fc/fc_els.h index 70a7e92a766..481abbd48e3 100644 --- a/include/scsi/fc/fc_els.h +++ b/include/scsi/fc/fc_els.h @@ -191,6 +191,7 @@ enum fc_els_rjt_reason { ELS_RJT_UNAB = 0x09, /* unable to perform command request */ ELS_RJT_UNSUP = 0x0b, /* command not supported */ ELS_RJT_INPROG = 0x0e, /* command already in progress */ + ELS_RJT_FIP = 0x20, /* FIP error */ ELS_RJT_VENDOR = 0xff, /* vendor specific error */ }; @@ -212,6 +213,7 @@ enum fc_els_rjt_explan { ELS_EXPL_UNAB_DATA = 0x2a, /* unable to supply requested data */ ELS_EXPL_UNSUPR = 0x2c, /* Request not supported */ ELS_EXPL_INV_LEN = 0x2d, /* Invalid payload length */ + ELS_EXPL_NOT_NEIGHBOR = 0x62, /* VN2VN_Port not in neighbor set */ /* TBD - above definitions incomplete */ }; diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index bd0560509ce..24b91c92205 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -97,6 +97,8 @@ enum fc_disc_event { /** * enum fc_rport_state - Remote port states * @RPORT_ST_INIT: Initialized + * @RPORT_ST_FLOGI: Waiting for FLOGI completion for point-to-multipoint + * @RPORT_ST_PLOGI_WAIT: Waiting for peer to login for point-to-multipoint * @RPORT_ST_PLOGI: Waiting for PLOGI completion * @RPORT_ST_PRLI: Waiting for PRLI completion * @RPORT_ST_RTV: Waiting for RTV completion @@ -107,6 +109,8 @@ enum fc_disc_event { */ enum fc_rport_state { RPORT_ST_INIT, + RPORT_ST_FLOGI, + RPORT_ST_PLOGI_WAIT, RPORT_ST_PLOGI, RPORT_ST_PRLI, RPORT_ST_RTV, -- cgit v1.2.3-70-g09d2 From f60e12e9c778c8256a646f80603d1b88ba5ce891 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:14 -0700 Subject: [SCSI] libfc: track FIP exchanges When an exchange is received with a FIP encapsulation, we need to know that the response must be sent via FIP and what the original ELS opcode was. This becomes important for VN2VN mode, where we may receive FLOGI or LOGO from several peer VN_ports, and the LS_ACC or LS_RJT must be sent FIP-encapsulated with the correct sub-type. Add a field to the struct fc_frame, fr_encaps, to indicate the encapsulation values. That term is chosen to be neutral and LLD-agnostic in case non-FCoE/FIP LLDs might find it useful. The frame fr_encaps is transferred from the ingress frame to the exchange by fc_exch_recv_req(), and back to the outgoing frame by fc_seq_send(). This is taking the last byte in the skb->cb array. If needed, we could combine the info in sof, eof, flags, and encaps together into one field, but it'd be better to do that if and when its needed. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 2 ++ include/scsi/fc_frame.h | 3 +++ include/scsi/libfc.h | 2 ++ 3 files changed, 7 insertions(+) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 104e0fba7c4..61eabd3ce43 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -464,6 +464,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, f_ctl = ntoh24(fh->fh_f_ctl); fc_exch_setup_hdr(ep, fp, f_ctl); + fr_encaps(fp) = ep->encaps; /* * update sequence count if this frame is carrying @@ -1259,6 +1260,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, sp = fr_seq(fp); /* sequence will be held */ ep = fc_seq_exch(sp); fc_seq_send_ack(sp, fp); + ep->encaps = fr_encaps(fp); /* * Call the receive function. diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h index 15427fab8a5..29dd97d5b53 100644 --- a/include/scsi/fc_frame.h +++ b/include/scsi/fc_frame.h @@ -51,6 +51,7 @@ #define fr_sof(fp) (fr_cb(fp)->fr_sof) #define fr_eof(fp) (fr_cb(fp)->fr_eof) #define fr_flags(fp) (fr_cb(fp)->fr_flags) +#define fr_encaps(fp) (fr_cb(fp)->fr_encaps) #define fr_max_payload(fp) (fr_cb(fp)->fr_max_payload) #define fr_fsp(fp) (fr_cb(fp)->fr_fsp) #define fr_crc(fp) (fr_cb(fp)->fr_crc) @@ -69,6 +70,7 @@ struct fcoe_rcv_info { u8 fr_sof; /* start of frame delimiter */ u8 fr_eof; /* end of frame delimiter */ u8 fr_flags; /* flags - see below */ + u8 fr_encaps; /* LLD encapsulation info (e.g. FIP) */ u8 granted_mac[ETH_ALEN]; /* FCoE MAC address */ }; @@ -97,6 +99,7 @@ static inline void fc_frame_init(struct fc_frame *fp) fr_dev(fp) = NULL; fr_seq(fp) = NULL; fr_flags(fp) = 0; + fr_encaps(fp) = 0; } struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 24b91c92205..8d297f9a0a4 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -412,6 +412,7 @@ struct fc_seq { * @esb_stat: ESB exchange status * @r_a_tov: Resouce allocation time out value (in msecs) * @seq_id: The next sequence ID to use + * @encaps: encapsulation information for lower-level driver * @f_ctl: F_CTL flags for the sequence * @fh_type: The frame type * @class: The class of service @@ -443,6 +444,7 @@ struct fc_exch { u32 esb_stat; u32 r_a_tov; u8 seq_id; + u8 encaps; u32 f_ctl; u8 fh_type; enum fc_class class; -- cgit v1.2.3-70-g09d2 From edcbb4395ecd2f2731fbf38ecbff5be0316513cb Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:19 -0700 Subject: [SCSI] libfcoe: add protocol description of FIP VN2VN mode The FC-BB-6 committee is proposing a new FIP usage model called VN_port to VN_port mode. It allows VN_ports to discover each other over a loss-free L2 Ethernet without any FCF or Fibre-channel fabric services. This is point-to-multipoint. There is also a variant of this called point-to-point which provides for making sure there is just one pair of ports operating over the Ethernet fabric. This patch defines the new message type and subtypes as well as one new descriptor type used by VN2VN mode. These are all still at the proposed stage and subject to change. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- include/scsi/fc/fc_fip.h | 46 +++++++++++++++++++++++++++++++++++++++++++--- include/scsi/fc/fc_ns.h | 7 +++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/include/scsi/fc/fc_fip.h b/include/scsi/fc/fc_fip.h index 17baa19380f..ae25d4ab254 100644 --- a/include/scsi/fc/fc_fip.h +++ b/include/scsi/fc/fc_fip.h @@ -17,9 +17,12 @@ #ifndef _FC_FIP_H_ #define _FC_FIP_H_ +#include + /* * This version is based on: * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf + * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal) */ #define FIP_DEF_PRI 128 /* default selection priority */ @@ -28,12 +31,25 @@ #define FIP_VN_KA_PERIOD 90000 /* required VN_port keep-alive period (mS) */ #define FIP_FCF_FUZZ 100 /* random time added by FCF (mS) */ +/* + * VN2VN proposed-standard values. + */ +#define FIP_VN_FC_MAP 0x0efd00 /* MAC OUI for VN2VN use */ +#define FIP_VN_PROBE_WAIT 100 /* interval between VN2VN probes (ms) */ +#define FIP_VN_ANN_WAIT 400 /* interval between VN2VN announcements (ms) */ +#define FIP_VN_RLIM_INT 10000 /* interval between probes when rate limited */ +#define FIP_VN_RLIM_COUNT 10 /* number of probes before rate limiting */ +#define FIP_VN_BEACON_INT 8000 /* interval between VN2VN beacons */ +#define FIP_VN_BEACON_FUZZ 100 /* random time to add to beacon period (ms) */ + /* * Multicast MAC addresses. T11-adopted. */ -#define FIP_ALL_FCOE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 }) -#define FIP_ALL_ENODE_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 }) -#define FIP_ALL_FCF_MACS ((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) +#define FIP_ALL_FCOE_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 0 }) +#define FIP_ALL_ENODE_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 1 }) +#define FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 }) +#define FIP_ALL_VN2VN_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 4 }) +#define FIP_ALL_P2P_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 5 }) #define FIP_VER 1 /* version for fip_header */ @@ -60,6 +76,7 @@ enum fip_opcode { FIP_OP_LS = 2, /* Link Service request or reply */ FIP_OP_CTRL = 3, /* Keep Alive / Link Reset */ FIP_OP_VLAN = 4, /* VLAN discovery */ + FIP_OP_VN2VN = 5, /* VN2VN operation */ FIP_OP_VENDOR_MIN = 0xfff8, /* min vendor-specific opcode */ FIP_OP_VENDOR_MAX = 0xfffe, /* max vendor-specific opcode */ }; @@ -96,12 +113,24 @@ enum fip_vlan_subcode { FIP_SC_VL_REP = 2, /* reply */ }; +/* + * Subcodes for FIP_OP_VN2VN. + */ +enum fip_vn2vn_subcode { + FIP_SC_VN_PROBE_REQ = 1, /* probe request */ + FIP_SC_VN_PROBE_REP = 2, /* probe reply */ + FIP_SC_VN_CLAIM_NOTIFY = 3, /* claim notification */ + FIP_SC_VN_CLAIM_REP = 4, /* claim response */ + FIP_SC_VN_BEACON = 5, /* beacon */ +}; + /* * flags in header fip_flags. */ enum fip_flag { FIP_FL_FPMA = 0x8000, /* supports FPMA fabric-provided MACs */ FIP_FL_SPMA = 0x4000, /* supports SPMA server-provided MACs */ + FIP_FL_REC_OR_P2P = 0x0008, /* configured addr or point-to-point */ FIP_FL_AVAIL = 0x0004, /* available for FLOGI/ELP */ FIP_FL_SOL = 0x0002, /* this is a solicited message */ FIP_FL_FPORT = 0x0001, /* sent from an F port */ @@ -130,6 +159,7 @@ enum fip_desc_type { FIP_DT_FKA = 12, /* advertisement keep-alive period */ FIP_DT_VENDOR = 13, /* vendor ID */ FIP_DT_VLAN = 14, /* vlan number */ + FIP_DT_FC4F = 15, /* FC-4 features */ FIP_DT_LIMIT, /* max defined desc_type + 1 */ FIP_DT_VENDOR_BASE = 128, /* first vendor-specific desc_type */ }; @@ -228,6 +258,16 @@ enum fip_fka_flags { /* FIP_DT_FKA flags */ +/* + * FIP_DT_FC4F - FC-4 features. + */ +struct fip_fc4_feat { + struct fip_desc fd_desc; + __u8 fd_resvd[2]; + struct fc_ns_fts fd_fts; + struct fc_ns_ff fd_ff; +} __attribute__((packed)); + /* * FIP_DT_VENDOR descriptor. */ diff --git a/include/scsi/fc/fc_ns.h b/include/scsi/fc/fc_ns.h index e7d3ac497d7..185015dd116 100644 --- a/include/scsi/fc/fc_ns.h +++ b/include/scsi/fc/fc_ns.h @@ -99,6 +99,13 @@ struct fc_ns_fts { __be32 ff_type_map[FC_NS_TYPES / FC_NS_BPW]; /* bitmap of FC-4 types */ }; +/* + * FC4-features object. + */ +struct fc_ns_ff { + __be32 fd_feat[FC_NS_TYPES * 4 / FC_NS_BPW]; /* 4-bits per FC-type */ +}; + /* * GID_PT request. */ -- cgit v1.2.3-70-g09d2 From 9b651da900ccfe5581befb46eb06ef781a1d7e74 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:24 -0700 Subject: [SCSI] libfcoe: add state change debugging Enhancement: add debug messages at all state transitions. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 48 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 76056e4c929..11f3db5e506 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -80,6 +80,40 @@ do { \ printk(KERN_INFO "host%d: fip: " fmt, \ (fip)->lp->host->host_no, ##args);) +static const char *fcoe_ctlr_states[] = { + [FIP_ST_DISABLED] = "DISABLED", + [FIP_ST_LINK_WAIT] = "LINK_WAIT", + [FIP_ST_AUTO] = "AUTO", + [FIP_ST_NON_FIP] = "NON_FIP", + [FIP_ST_ENABLED] = "ENABLED", +}; + +static const char *fcoe_ctlr_state(enum fip_state state) +{ + const char *cp = "unknown"; + + if (state < ARRAY_SIZE(fcoe_ctlr_states)) + cp = fcoe_ctlr_states[state]; + if (!cp) + cp = "unknown"; + return cp; +} + +/** + * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state. + * @fip: The FCoE controller + * @state: The new state + */ +static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state) +{ + if (state == fip->state) + return; + if (fip->lp) + LIBFCOE_FIP_DBG(fip, "state %s -> %s\n", + fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state)); + fip->state = state; +} + /** * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid * @fcf: The FCF to check @@ -110,7 +144,7 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) */ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) { - fip->state = FIP_ST_LINK_WAIT; + fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT); fip->mode = mode; INIT_LIST_HEAD(&fip->fcfs); mutex_init(&fip->ctlr_mutex); @@ -160,7 +194,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) skb_queue_purge(&fip->fip_recv_list); mutex_lock(&fip->ctlr_mutex); - fip->state = FIP_ST_DISABLED; + fcoe_ctlr_set_state(fip, FIP_ST_DISABLED); fcoe_ctlr_reset_fcfs(fip); mutex_unlock(&fip->ctlr_mutex); del_timer_sync(&fip->timer); @@ -260,7 +294,7 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) mutex_unlock(&fip->ctlr_mutex); fc_linkup(fip->lp); } else if (fip->state == FIP_ST_LINK_WAIT) { - fip->state = fip->mode; + fcoe_ctlr_set_state(fip, fip->mode); mutex_unlock(&fip->ctlr_mutex); if (fip->state == FIP_ST_AUTO) LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); @@ -303,7 +337,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) mutex_lock(&fip->ctlr_mutex); fcoe_ctlr_reset(fip); link_dropped = fip->state != FIP_ST_LINK_WAIT; - fip->state = FIP_ST_LINK_WAIT; + fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT); mutex_unlock(&fip->ctlr_mutex); if (link_dropped) @@ -1170,7 +1204,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) state = fip->state; if (state == FIP_ST_AUTO) { fip->map_dest = 0; - fip->state = FIP_ST_ENABLED; + fcoe_ctlr_set_state(fip, FIP_ST_ENABLED); state = FIP_ST_ENABLED; LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); } @@ -1401,7 +1435,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, mutex_unlock(&fip->ctlr_mutex); return -EINVAL; } - fip->state = FIP_ST_NON_FIP; + fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP); LIBFCOE_FIP_DBG(fip, "received FLOGI LS_ACC using non-FIP mode\n"); @@ -1431,7 +1465,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, if (fip->state == FIP_ST_AUTO) LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. " "Setting non-FIP mode\n"); - fip->state = FIP_ST_NON_FIP; + fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP); } mutex_unlock(&fip->ctlr_mutex); } -- cgit v1.2.3-70-g09d2 From e10f8c667b874a57512c936089092a3d1ef7ab8a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:30 -0700 Subject: [SCSI] libfcoe: fcoe: fnic: add FIP VN2VN point-to-multipoint support The FC-BB-6 committee is proposing a new FIP usage model called VN_port to VN_port mode. It allows VN_ports to discover each other over a loss-free L2 Ethernet without any FCF or Fibre-channel fabric services. This is point-to-multipoint. There is also a variant of this called point-to-point which provides for making sure there is just one pair of ports operating over the Ethernet fabric. We add these new states: VNMP_START, _PROBE1, _PROBE2, _CLAIM, and _UP. These usually go quickly in that sequence. After waiting a random amount of time up to 100 ms in START, we select a pseudo-random proposed locally-unique port ID and send out probes in states PROBE1 and PROBE2, 100 ms apart. If no probe responses are heard, we proceed to CLAIM state 400 ms later and send a claim notification. We wait another 400 ms to receive claim responses, which give us a list of the other nodes on the network, including their FC-4 capabilities. After another 400 ms we go to VNMP_UP state and should start interoperating with any of the nodes for whic we receivec claim responses. More details are in the spec.j Add the new mode as FIP_MODE_VN2VN. The driver must specify explicitly that it wants to operate in this mode. There is no automatic detection between point-to-multipoint and fabric mode, and the local port initialization is affected, so it isn't anticipated that there will ever be any such automatic switchover. It may eventually be possible to have both fabric and VN2VN modes on the same L2 network, which may be done by two separate local VN_ports (lports). When in VN2VN mode, FIP replaces libfc's fabric-oriented discovery module with its own simple code that adds remote ports as they are discovered from incoming claim notifications and responses. These hooks are placed by fcoe_disc_init(). A linear list of discovered vn_ports is maintained under the fcoe_ctlr struct. It is expected to be short for now, and accessed infrequently. It is kept under RCU for lock-ordering reasons. The lport and/or rport mutexes may be held when we need to lookup a fcoe_vnport during an ELS send. Change fcoe_ctlr_encaps() to lookup the destination vn_port in the list of peers for the destination MAC address of the FIP-encapsulated frame. Add a new function fcoe_disc_init() to initialize just the discovery portion of libfcoe for VN2VN mode. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 16 +- drivers/scsi/fcoe/libfcoe.c | 1075 ++++++++++++++++++++++++++++++++++++++--- drivers/scsi/fnic/fnic_main.c | 7 +- include/scsi/libfcoe.h | 42 +- 4 files changed, 1071 insertions(+), 69 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 9d64e08305c..216aba375fe 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -315,7 +315,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, dev_uc_add(netdev, flogi_maddr); if (fip->spma) dev_uc_add(netdev, fip->ctl_src_addr); - dev_mc_add(netdev, FIP_ALL_ENODE_MACS); + if (fip->mode == FIP_MODE_VN2VN) { + dev_mc_add(netdev, FIP_ALL_VN2VN_MACS); + dev_mc_add(netdev, FIP_ALL_P2P_MACS); + } else + dev_mc_add(netdev, FIP_ALL_ENODE_MACS); /* * setup the receive function from ethernet driver @@ -401,7 +405,11 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe) dev_uc_del(netdev, flogi_maddr); if (fip->spma) dev_uc_del(netdev, fip->ctl_src_addr); - dev_mc_del(netdev, FIP_ALL_ENODE_MACS); + if (fip->mode == FIP_MODE_VN2VN) { + dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); + dev_mc_del(netdev, FIP_ALL_P2P_MACS); + } else + dev_mc_del(netdev, FIP_ALL_ENODE_MACS); /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; @@ -967,7 +975,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } /* Initialize the library */ - rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ); + rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1); if (rc) { FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " "interface\n"); @@ -2533,6 +2541,8 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, switch (op) { case ELS_FLOGI: case ELS_FDISC: + if (lport->point_to_multipoint) + break; return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp, fip, timeout); case ELS_LOGO: diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 11f3db5e506..79df78f2b08 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -54,7 +55,15 @@ static void fcoe_ctlr_timeout(unsigned long); static void fcoe_ctlr_timer_work(struct work_struct *); static void fcoe_ctlr_recv_work(struct work_struct *); +static void fcoe_ctlr_vn_start(struct fcoe_ctlr *); +static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *); +static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *); +static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *); + static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; +static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; +static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS; +static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS; unsigned int libfcoe_debug_logging; module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); @@ -86,6 +95,11 @@ static const char *fcoe_ctlr_states[] = { [FIP_ST_AUTO] = "AUTO", [FIP_ST_NON_FIP] = "NON_FIP", [FIP_ST_ENABLED] = "ENABLED", + [FIP_ST_VNMP_START] = "VNMP_START", + [FIP_ST_VNMP_PROBE1] = "VNMP_PROBE1", + [FIP_ST_VNMP_PROBE2] = "VNMP_PROBE2", + [FIP_ST_VNMP_CLAIM] = "VNMP_CLAIM", + [FIP_ST_VNMP_UP] = "VNMP_UP", }; static const char *fcoe_ctlr_state(enum fip_state state) @@ -295,11 +309,25 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) fc_linkup(fip->lp); } else if (fip->state == FIP_ST_LINK_WAIT) { fcoe_ctlr_set_state(fip, fip->mode); - mutex_unlock(&fip->ctlr_mutex); - if (fip->state == FIP_ST_AUTO) + switch (fip->mode) { + default: + LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode); + /* fall-through */ + case FIP_MODE_AUTO: LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); - fc_linkup(fip->lp); - fcoe_ctlr_solicit(fip, NULL); + /* fall-through */ + case FIP_MODE_FABRIC: + case FIP_MODE_NON_FIP: + mutex_unlock(&fip->ctlr_mutex); + fc_linkup(fip->lp); + fcoe_ctlr_solicit(fip, NULL); + break; + case FIP_MODE_VN2VN: + fcoe_ctlr_vn_start(fip); + mutex_unlock(&fip->ctlr_mutex); + fc_linkup(fip->lp); + break; + } } else mutex_unlock(&fip->ctlr_mutex); } @@ -423,6 +451,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, * @fip: The FCoE controller for the ELS frame * @dtype: The FIP descriptor type for the frame * @skb: The FCoE ELS frame including FC header but no FCoE headers + * @d_id: The destination port ID. * * Returns non-zero error code on failure. * @@ -433,7 +462,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, * Ethernet header. The tailroom is for the FIP MAC descriptor. */ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, - u8 dtype, struct sk_buff *skb) + u8 dtype, struct sk_buff *skb, u32 d_id) { struct fip_encaps_head { struct ethhdr eth; @@ -445,21 +474,24 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, size_t dlen; u16 fip_flags; - fcf = fip->sel_fcf; - if (!fcf) - return -ENODEV; - - /* set flags according to both FCF and lport's capability on SPMA */ - fip_flags = fcf->flags; - fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : FIP_FL_FPMA; - if (!fip_flags) - return -ENODEV; - dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); - memset(cap, 0, sizeof(*cap)); - memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN); + + if (lport->point_to_multipoint) { + if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest)) + return -ENODEV; + } else { + fcf = fip->sel_fcf; + if (!fcf) + return -ENODEV; + fip_flags = fcf->flags; + fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : + FIP_FL_FPMA; + if (!fip_flags) + return -ENODEV; + memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN); + } memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN); cap->eth.h_proto = htons(ETH_P_FIP); @@ -503,19 +535,22 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, * * The caller must check that the length is a multiple of 4. * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes). + * The the skb must also be an fc_frame. */ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, struct sk_buff *skb) { + struct fc_frame *fp; struct fc_frame_header *fh; u16 old_xid; u8 op; u8 mac[ETH_ALEN]; + fp = container_of(skb, struct fc_frame, skb); fh = (struct fc_frame_header *)skb->data; op = *(u8 *)(fh + 1); - if (op == ELS_FLOGI) { + if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) { old_xid = fip->flogi_oxid; fip->flogi_oxid = ntohs(fh->fh_ox_id); if (fip->state == FIP_ST_AUTO) { @@ -533,9 +568,8 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, if (fip->state == FIP_ST_NON_FIP) return 0; - if (!fip->sel_fcf) + if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN) goto drop; - switch (op) { case ELS_FLOGI: op = FIP_DT_FLOGI; @@ -546,36 +580,49 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, op = FIP_DT_FDISC; break; case ELS_LOGO: - if (fip->state != FIP_ST_ENABLED) - return 0; - if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) - return 0; + if (fip->mode == FIP_MODE_VN2VN) { + if (fip->state != FIP_ST_VNMP_UP) + return -EINVAL; + if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI) + return -EINVAL; + } else { + if (fip->state != FIP_ST_ENABLED) + return 0; + if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) + return 0; + } op = FIP_DT_LOGO; break; case ELS_LS_ACC: - if (fip->flogi_oxid == FC_XID_UNKNOWN) - return 0; - if (!ntoh24(fh->fh_s_id)) - return 0; - if (fip->state == FIP_ST_AUTO) - return 0; /* - * Here we must've gotten an SID by accepting an FLOGI + * If non-FIP, we may have gotten an SID by accepting an FLOGI * from a point-to-point connection. Switch to using * the source mac based on the SID. The destination * MAC in this case would have been set by receving the * FLOGI. */ - fip->flogi_oxid = FC_XID_UNKNOWN; - fc_fcoe_set_mac(mac, fh->fh_d_id); - fip->update_mac(lport, mac); + if (fip->state == FIP_ST_NON_FIP) { + if (fip->flogi_oxid == FC_XID_UNKNOWN) + return 0; + fip->flogi_oxid = FC_XID_UNKNOWN; + fc_fcoe_set_mac(mac, fh->fh_d_id); + fip->update_mac(lport, mac); + } + /* fall through */ + case ELS_LS_RJT: + op = fr_encaps(fp); + if (op) + break; return 0; default: - if (fip->state != FIP_ST_ENABLED) + if (fip->state != FIP_ST_ENABLED && + fip->state != FIP_ST_VNMP_UP) goto drop; return 0; } - if (fcoe_ctlr_encaps(fip, lport, op, skb)) + LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n", + op, ntoh24(fh->fh_d_id)); + if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id))) goto drop; fip->send(fip, skb); return -EINPROGRESS; @@ -717,8 +764,9 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); if (!is_valid_ether_addr(fcf->fcf_mac)) { - LIBFCOE_FIP_DBG(fip, "Invalid MAC address " - "in FIP adv\n"); + LIBFCOE_FIP_DBG(fip, + "Invalid MAC addr %pM in FIP adv\n", + fcf->fcf_mac); return -EINVAL; } desc_mask &= ~BIT(FIP_DT_MAC); @@ -944,12 +992,6 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) memcpy(granted_mac, ((struct fip_mac_desc *)desc)->fd_mac, ETH_ALEN); - if (!is_valid_ether_addr(granted_mac)) { - LIBFCOE_FIP_DBG(fip, "Invalid MAC address " - "in FIP ELS\n"); - goto drop; - } - memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN); break; case FIP_DT_FLOGI: case FIP_DT_FDISC: @@ -990,10 +1032,20 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) goto drop; els_op = *(u8 *)(fh + 1); - if (els_dtype == FIP_DT_FLOGI && sub == FIP_SC_REP && - fip->flogi_oxid == ntohs(fh->fh_ox_id) && - els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac)) - fip->flogi_oxid = FC_XID_UNKNOWN; + if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) && + sub == FIP_SC_REP && els_op == ELS_LS_ACC && + fip->mode != FIP_MODE_VN2VN) { + if (!is_valid_ether_addr(granted_mac)) { + LIBFCOE_FIP_DBG(fip, + "Invalid MAC address %pM in FIP ELS\n", + granted_mac); + goto drop; + } + memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN); + + if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) + fip->flogi_oxid = FC_XID_UNKNOWN; + } if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) && (!(1U << FIP_DT_MAC & desc_mask)))) { @@ -1012,6 +1064,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) fr_sof(fp) = FC_SOF_I3; fr_eof(fp) = FC_EOF_T; fr_dev(fp) = lport; + fr_encaps(fp) = els_dtype; stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->RxFrames++; @@ -1188,8 +1241,13 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) if (skb->len < sizeof(*fiph)) goto drop; eh = eth_hdr(skb); - if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, FIP_ALL_ENODE_MACS)) + if (fip->mode == FIP_MODE_VN2VN) { + if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && + compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) && + compare_ether_addr(eh->h_dest, fcoe_all_p2p)) + goto drop; + } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && + compare_ether_addr(eh->h_dest, fcoe_all_enode)) goto drop; fiph = (struct fip_header *)skb->data; op = ntohs(fiph->fip_op); @@ -1209,13 +1267,22 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); } mutex_unlock(&fip->ctlr_mutex); - if (state != FIP_ST_ENABLED) + + if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN) + return fcoe_ctlr_vn_recv(fip, skb); + + if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP && + state != FIP_ST_VNMP_CLAIM) goto drop; if (op == FIP_OP_LS) { fcoe_ctlr_recv_els(fip, skb); /* consumes skb */ return 0; } + + if (state != FIP_ST_ENABLED) + goto drop; + if (op == FIP_OP_DISC && sub == FIP_SC_ADV) fcoe_ctlr_recv_adv(fip, skb); else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) @@ -1302,7 +1369,8 @@ static void fcoe_ctlr_timer_work(struct work_struct *work) unsigned long next_timer; fip = container_of(work, struct fcoe_ctlr, timer_work); - + if (fip->mode == FIP_MODE_VN2VN) + return fcoe_ctlr_vn_timeout(fip); mutex_lock(&fip->ctlr_mutex); if (fip->state == FIP_ST_DISABLED) { mutex_unlock(&fip->ctlr_mutex); @@ -1340,7 +1408,6 @@ static void fcoe_ctlr_timer_work(struct work_struct *work) "Starting FCF discovery.\n", fip->lp->host->host_no); reset = 1; - schedule_work(&fip->timer_work); } } @@ -1514,27 +1581,917 @@ u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], } EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); +/** + * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv + * @rdata: libfc remote port + */ +static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata) +{ + return (struct fcoe_rport *)(rdata + 1); +} + +/** + * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply. + * @fip: The FCoE controller + * @sub: sub-opcode for probe request, reply, or advertisement. + * @dest: The destination Ethernet MAC address + * @min_len: minimum size of the Ethernet payload to be sent + */ +static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, + enum fip_vn2vn_subcode sub, + const u8 *dest, size_t min_len) +{ + struct sk_buff *skb; + struct fip_frame { + struct ethhdr eth; + struct fip_header fip; + struct fip_mac_desc mac; + struct fip_wwn_desc wwnn; + struct fip_vn_desc vn; + } __attribute__((packed)) *frame; + struct fip_fc4_feat *ff; + struct fip_size_desc *size; + u32 fcp_feat; + size_t len; + size_t dlen; + + len = sizeof(*frame); + dlen = 0; + if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) { + dlen = sizeof(struct fip_fc4_feat) + + sizeof(struct fip_size_desc); + len += dlen; + } + dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn); + len = max(len, min_len + sizeof(struct ethhdr)); + + skb = dev_alloc_skb(len); + if (!skb) + return; + + frame = (struct fip_frame *)skb->data; + memset(frame, 0, len); + memcpy(frame->eth.h_dest, dest, ETH_ALEN); + memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN); + frame->eth.h_proto = htons(ETH_P_FIP); + + frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); + frame->fip.fip_op = htons(FIP_OP_VN2VN); + frame->fip.fip_subcode = sub; + frame->fip.fip_dl_len = htons(dlen / FIP_BPW); + + frame->mac.fd_desc.fip_dtype = FIP_DT_MAC; + frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW; + memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); + + frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME; + frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW; + put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn); + + frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID; + frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW; + hton24(frame->vn.fd_mac, FIP_VN_FC_MAP); + hton24(frame->vn.fd_mac + 3, fip->port_id); + hton24(frame->vn.fd_fc_id, fip->port_id); + put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn); + + /* + * For claims, add FC-4 features. + * TBD: Add interface to get fc-4 types and features from libfc. + */ + if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) { + ff = (struct fip_fc4_feat *)(frame + 1); + ff->fd_desc.fip_dtype = FIP_DT_FC4F; + ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW; + ff->fd_fts = fip->lp->fcts; + + fcp_feat = 0; + if (fip->lp->service_params & FCP_SPPF_INIT_FCN) + fcp_feat |= FCP_FEAT_INIT; + if (fip->lp->service_params & FCP_SPPF_TARG_FCN) + fcp_feat |= FCP_FEAT_TARG; + fcp_feat <<= (FC_TYPE_FCP * 4) % 32; + ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat); + + size = (struct fip_size_desc *)(ff + 1); + size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE; + size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW; + size->fd_size = htons(fcoe_ctlr_fcoe_size(fip)); + } + + skb_put(skb, len); + skb->protocol = htons(ETH_P_FIP); + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + + fip->send(fip, skb); +} + +/** + * fcoe_ctlr_vn_rport_callback - Event handler for rport events. + * @lport: The lport which is receiving the event + * @rdata: remote port private data + * @event: The event that occured + * + * Locking Note: The rport lock must not be held when calling this function. + */ +static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport, + struct fc_rport_priv *rdata, + enum fc_rport_event event) +{ + struct fcoe_ctlr *fip = lport->disc.priv; + struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); + + LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n", + rdata->ids.port_id, event); + + mutex_lock(&fip->ctlr_mutex); + switch (event) { + case RPORT_EV_READY: + frport->login_count = 0; + break; + case RPORT_EV_LOGO: + case RPORT_EV_FAILED: + case RPORT_EV_STOP: + frport->login_count++; + if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) { + LIBFCOE_FIP_DBG(fip, + "rport FLOGI limited port_id %6.6x\n", + rdata->ids.port_id); + lport->tt.rport_logoff(rdata); + } + break; + default: + break; + } + mutex_unlock(&fip->ctlr_mutex); +} + +static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = { + .event_callback = fcoe_ctlr_vn_rport_callback, +}; + +/** + * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode + * @fip: The FCoE controller + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport) +{ + mutex_lock(&lport->disc.disc_mutex); + lport->disc.disc_callback = NULL; + mutex_unlock(&lport->disc.disc_mutex); +} + +/** + * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode + * @fip: The FCoE controller + * + * Called through the local port template for discovery. + * Called without the ctlr_mutex held. + */ +static void fcoe_ctlr_disc_stop(struct fc_lport *lport) +{ + struct fcoe_ctlr *fip = lport->disc.priv; + + mutex_lock(&fip->ctlr_mutex); + fcoe_ctlr_disc_stop_locked(lport); + mutex_unlock(&fip->ctlr_mutex); +} + +/** + * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode + * @fip: The FCoE controller + * + * Called through the local port template for discovery. + * Called without the ctlr_mutex held. + */ +static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport) +{ + fcoe_ctlr_disc_stop(lport); + lport->tt.rport_flush_queue(); + synchronize_rcu(); +} + +/** + * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id + * @fip: The FCoE controller + * + * Called with fcoe_ctlr lock held. + */ +static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip) +{ + unsigned long wait; + u32 port_id; + + fcoe_ctlr_disc_stop_locked(fip->lp); + + /* + * Get proposed port ID. + * If this is the first try after link up, use any previous port_id. + * If there was none, use the low bits of the port_name. + * On subsequent tries, get the next random one. + * Don't use reserved IDs, use another non-zero value, just as random. + */ + port_id = fip->port_id; + if (fip->probe_tries) + port_id = prandom32(&fip->rnd_state) & 0xffff; + else if (!port_id) + port_id = fip->lp->wwpn & 0xffff; + if (!port_id || port_id == 0xffff) + port_id = 1; + fip->port_id = port_id; + + if (fip->probe_tries < FIP_VN_RLIM_COUNT) { + fip->probe_tries++; + wait = random32() % FIP_VN_PROBE_WAIT; + } else + wait = FIP_VN_RLIM_INT; + mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait)); + fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START); +} + +/** + * fcoe_ctlr_vn_start() - Start in VN2VN mode + * @fip: The FCoE controller + * + * Called with fcoe_ctlr lock held. + */ +static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip) +{ + fip->probe_tries = 0; + prandom32_seed(&fip->rnd_state, fip->lp->wwpn); + fcoe_ctlr_vn_restart(fip); +} + +/** + * fcoe_ctlr_vn_parse - parse probe request or response + * @fip: The FCoE controller + * @skb: incoming packet + * @rdata: buffer for resulting parsed VN entry plus fcoe_rport + * + * Returns non-zero error number on error. + * Does not consume the packet. + */ +static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, + struct sk_buff *skb, + struct fc_rport_priv *rdata) +{ + struct fip_header *fiph; + struct fip_desc *desc = NULL; + struct fip_mac_desc *macd = NULL; + struct fip_wwn_desc *wwn = NULL; + struct fip_vn_desc *vn = NULL; + struct fip_size_desc *size = NULL; + struct fcoe_rport *frport; + size_t rlen; + size_t dlen; + u32 desc_mask = 0; + u32 dtype; + u8 sub; + + memset(rdata, 0, sizeof(*rdata) + sizeof(*frport)); + frport = fcoe_ctlr_rport(rdata); + + fiph = (struct fip_header *)skb->data; + frport->flags = ntohs(fiph->fip_flags); + + sub = fiph->fip_subcode; + switch (sub) { + case FIP_SC_VN_PROBE_REQ: + case FIP_SC_VN_PROBE_REP: + case FIP_SC_VN_BEACON: + desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | + BIT(FIP_DT_VN_ID); + break; + case FIP_SC_VN_CLAIM_NOTIFY: + case FIP_SC_VN_CLAIM_REP: + desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | + BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) | + BIT(FIP_DT_FCOE_SIZE); + break; + default: + LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub); + return -EINVAL; + } + + rlen = ntohs(fiph->fip_dl_len) * 4; + if (rlen + sizeof(*fiph) > skb->len) + return -EINVAL; + + desc = (struct fip_desc *)(fiph + 1); + while (rlen > 0) { + dlen = desc->fip_dlen * FIP_BPW; + if (dlen < sizeof(*desc) || dlen > rlen) + return -EINVAL; + + dtype = desc->fip_dtype; + if (dtype < 32) { + if (!(desc_mask & BIT(dtype))) { + LIBFCOE_FIP_DBG(fip, + "unexpected or duplicated desc " + "desc type %u in " + "FIP VN2VN subtype %u\n", + dtype, sub); + return -EINVAL; + } + desc_mask &= ~BIT(dtype); + } + + switch (dtype) { + case FIP_DT_MAC: + if (dlen != sizeof(struct fip_mac_desc)) + goto len_err; + macd = (struct fip_mac_desc *)desc; + if (!is_valid_ether_addr(macd->fd_mac)) { + LIBFCOE_FIP_DBG(fip, + "Invalid MAC addr %pM in FIP VN2VN\n", + macd->fd_mac); + return -EINVAL; + } + memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN); + break; + case FIP_DT_NAME: + if (dlen != sizeof(struct fip_wwn_desc)) + goto len_err; + wwn = (struct fip_wwn_desc *)desc; + rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn); + break; + case FIP_DT_VN_ID: + if (dlen != sizeof(struct fip_vn_desc)) + goto len_err; + vn = (struct fip_vn_desc *)desc; + memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN); + rdata->ids.port_id = ntoh24(vn->fd_fc_id); + rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn); + break; + case FIP_DT_FC4F: + if (dlen != sizeof(struct fip_fc4_feat)) + goto len_err; + break; + case FIP_DT_FCOE_SIZE: + if (dlen != sizeof(struct fip_size_desc)) + goto len_err; + size = (struct fip_size_desc *)desc; + frport->fcoe_len = ntohs(size->fd_size); + break; + default: + LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " + "in FIP probe\n", dtype); + /* standard says ignore unknown descriptors >= 128 */ + if (dtype < FIP_DT_VENDOR_BASE) + return -EINVAL; + break; + } + desc = (struct fip_desc *)((char *)desc + dlen); + rlen -= dlen; + } + return 0; + +len_err: + LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", + dtype, dlen); + return -EINVAL; +} + +/** + * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification. + * @fip: The FCoE controller + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip) +{ + fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0); + fip->sol_time = jiffies; +} + +/** + * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request. + * @fip: The FCoE controller + * @rdata: parsed remote port with frport from the probe request + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, + struct fc_rport_priv *rdata) +{ + struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); + + if (rdata->ids.port_id != fip->port_id) + return; + + switch (fip->state) { + case FIP_ST_VNMP_CLAIM: + case FIP_ST_VNMP_UP: + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, + frport->enode_mac, 0); + break; + case FIP_ST_VNMP_PROBE1: + case FIP_ST_VNMP_PROBE2: + /* + * Decide whether to reply to the Probe. + * Our selected address is never a "recorded" one, so + * only reply if our WWPN is greater and the + * Probe's REC bit is not set. + * If we don't reply, we will change our address. + */ + if (fip->lp->wwpn > rdata->ids.port_name && + !(frport->flags & FIP_FL_REC_OR_P2P)) { + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, + frport->enode_mac, 0); + break; + } + /* fall through */ + case FIP_ST_VNMP_START: + fcoe_ctlr_vn_restart(fip); + break; + default: + break; + } +} + +/** + * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply. + * @fip: The FCoE controller + * @rdata: parsed remote port with frport from the probe request + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip, + struct fc_rport_priv *rdata) +{ + if (rdata->ids.port_id != fip->port_id) + return; + switch (fip->state) { + case FIP_ST_VNMP_START: + case FIP_ST_VNMP_PROBE1: + case FIP_ST_VNMP_PROBE2: + case FIP_ST_VNMP_CLAIM: + fcoe_ctlr_vn_restart(fip); + break; + case FIP_ST_VNMP_UP: + fcoe_ctlr_vn_send_claim(fip); + break; + default: + break; + } +} + +/** + * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply. + * @fip: The FCoE controller + * @new: newly-parsed remote port with frport as a template for new rdata + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) +{ + struct fc_lport *lport = fip->lp; + struct fc_rport_priv *rdata; + struct fc_rport_identifiers *ids; + struct fcoe_rport *frport; + u32 port_id; + + port_id = new->ids.port_id; + if (port_id == fip->port_id) + return; + + mutex_lock(&lport->disc.disc_mutex); + rdata = lport->tt.rport_create(lport, port_id); + if (!rdata) { + mutex_unlock(&lport->disc.disc_mutex); + return; + } + + rdata->ops = &fcoe_ctlr_vn_rport_ops; + rdata->disc_id = lport->disc.disc_id; + + ids = &rdata->ids; + if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) || + (ids->node_name != -1 && ids->node_name != new->ids.node_name)) + lport->tt.rport_logoff(rdata); + ids->port_name = new->ids.port_name; + ids->node_name = new->ids.node_name; + mutex_unlock(&lport->disc.disc_mutex); + + frport = fcoe_ctlr_rport(rdata); + LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n", + port_id, frport->fcoe_len ? "old" : "new"); + *frport = *fcoe_ctlr_rport(new); + frport->time = 0; +} + +/** + * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address + * @fip: The FCoE controller + * @port_id: The port_id of the remote VN_node + * @mac: buffer which will hold the VN_NODE destination MAC address, if found. + * + * Returns non-zero error if no remote port found. + */ +static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac) +{ + struct fc_lport *lport = fip->lp; + struct fc_rport_priv *rdata; + struct fcoe_rport *frport; + int ret = -1; + + rcu_read_lock(); + rdata = lport->tt.rport_lookup(lport, port_id); + if (rdata) { + frport = fcoe_ctlr_rport(rdata); + memcpy(mac, frport->enode_mac, ETH_ALEN); + ret = 0; + } + rcu_read_unlock(); + return ret; +} + +/** + * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification + * @fip: The FCoE controller + * @new: newly-parsed remote port with frport as a template for new rdata + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, + struct fc_rport_priv *new) +{ + struct fcoe_rport *frport = fcoe_ctlr_rport(new); + + if (frport->flags & FIP_FL_REC_OR_P2P) { + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); + return; + } + switch (fip->state) { + case FIP_ST_VNMP_START: + case FIP_ST_VNMP_PROBE1: + case FIP_ST_VNMP_PROBE2: + if (new->ids.port_id == fip->port_id) + fcoe_ctlr_vn_restart(fip); + break; + case FIP_ST_VNMP_CLAIM: + case FIP_ST_VNMP_UP: + if (new->ids.port_id == fip->port_id) { + if (new->ids.port_name > fip->lp->wwpn) { + fcoe_ctlr_vn_restart(fip); + break; + } + fcoe_ctlr_vn_send_claim(fip); + break; + } + fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac, + min((u32)frport->fcoe_len, + fcoe_ctlr_fcoe_size(fip))); + fcoe_ctlr_vn_add(fip, new); + break; + default: + break; + } +} + +/** + * fcoe_ctlr_vn_claim_resp() - handle received Claim Response + * @fip: The FCoE controller that received the frame + * @new: newly-parsed remote port with frport from the Claim Response + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip, + struct fc_rport_priv *new) +{ + LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n", + new->ids.port_id, fcoe_ctlr_state(fip->state)); + if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM) + fcoe_ctlr_vn_add(fip, new); +} + +/** + * fcoe_ctlr_vn_beacon() - handle received beacon. + * @fip: The FCoE controller that received the frame + * @new: newly-parsed remote port with frport from the Beacon + * + * Called with ctlr_mutex held. + */ +static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, + struct fc_rport_priv *new) +{ + struct fc_lport *lport = fip->lp; + struct fc_rport_priv *rdata; + struct fcoe_rport *frport; + + frport = fcoe_ctlr_rport(new); + if (frport->flags & FIP_FL_REC_OR_P2P) { + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); + return; + } + mutex_lock(&lport->disc.disc_mutex); + rdata = lport->tt.rport_lookup(lport, new->ids.port_id); + if (rdata) + kref_get(&rdata->kref); + mutex_unlock(&lport->disc.disc_mutex); + if (rdata) { + if (rdata->ids.node_name == new->ids.node_name && + rdata->ids.port_name == new->ids.port_name) { + frport = fcoe_ctlr_rport(rdata); + if (!frport->time && fip->state == FIP_ST_VNMP_UP) + lport->tt.rport_login(rdata); + frport->time = jiffies; + } + kref_put(&rdata->kref, lport->tt.rport_destroy); + return; + } + if (fip->state != FIP_ST_VNMP_UP) + return; + + /* + * Beacon from a new neighbor. + * Send a claim notify if one hasn't been sent recently. + * Don't add the neighbor yet. + */ + LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n", + new->ids.port_id); + if (time_after(jiffies, + fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT))) + fcoe_ctlr_vn_send_claim(fip); +} + +/** + * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons + * @fip: The FCoE controller + * + * Called with ctlr_mutex held. + * Called only in state FIP_ST_VNMP_UP. + * Returns the soonest time for next age-out or a time far in the future. + */ +static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip) +{ + struct fc_lport *lport = fip->lp; + struct fc_rport_priv *rdata; + struct fcoe_rport *frport; + unsigned long next_time; + unsigned long deadline; + + next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10); + mutex_lock(&lport->disc.disc_mutex); + list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) { + frport = fcoe_ctlr_rport(rdata); + if (!frport->time) + continue; + deadline = frport->time + + msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10); + if (time_after_eq(jiffies, deadline)) { + frport->time = 0; + LIBFCOE_FIP_DBG(fip, + "port %16.16llx fc_id %6.6x beacon expired\n", + rdata->ids.port_name, rdata->ids.port_id); + lport->tt.rport_logoff(rdata); + } else if (time_before(deadline, next_time)) + next_time = deadline; + } + mutex_unlock(&lport->disc.disc_mutex); + return next_time; +} + +/** + * fcoe_ctlr_vn_recv() - Receive a FIP frame + * @fip: The FCoE controller that received the frame + * @skb: The received FIP frame + * + * Returns non-zero if the frame is dropped. + * Always consumes the frame. + */ +static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) +{ + struct fip_header *fiph; + enum fip_vn2vn_subcode sub; + union { + struct fc_rport_priv rdata; + struct fcoe_rport frport; + } buf; + int rc; + + fiph = (struct fip_header *)skb->data; + sub = fiph->fip_subcode; + + rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata); + if (rc) { + LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc); + goto drop; + } + + mutex_lock(&fip->ctlr_mutex); + switch (sub) { + case FIP_SC_VN_PROBE_REQ: + fcoe_ctlr_vn_probe_req(fip, &buf.rdata); + break; + case FIP_SC_VN_PROBE_REP: + fcoe_ctlr_vn_probe_reply(fip, &buf.rdata); + break; + case FIP_SC_VN_CLAIM_NOTIFY: + fcoe_ctlr_vn_claim_notify(fip, &buf.rdata); + break; + case FIP_SC_VN_CLAIM_REP: + fcoe_ctlr_vn_claim_resp(fip, &buf.rdata); + break; + case FIP_SC_VN_BEACON: + fcoe_ctlr_vn_beacon(fip, &buf.rdata); + break; + default: + LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub); + rc = -1; + break; + } + mutex_unlock(&fip->ctlr_mutex); +drop: + kfree_skb(skb); + return rc; +} + +/** + * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode. + * @fip: The FCoE controller + * + * This should never be called since we don't see RSCNs or other + * fabric-generated ELSes. + */ +static void fcoe_ctlr_disc_recv(struct fc_seq *seq, struct fc_frame *fp, + struct fc_lport *lport) +{ + struct fc_seq_els_data rjt_data; + + rjt_data.fp = NULL; + rjt_data.reason = ELS_RJT_UNSUP; + rjt_data.explan = ELS_EXPL_NONE; + lport->tt.seq_els_rsp_send(seq, ELS_LS_RJT, &rjt_data); + fc_frame_free(fp); +} + +/** + * fcoe_ctlr_disc_recv - start discovery for VN2VN mode. + * @fip: The FCoE controller + * + * This sets a flag indicating that remote ports should be created + * and started for the peers we discover. We use the disc_callback + * pointer as that flag. Peers already discovered are created here. + * + * The lport lock is held during this call. The callback must be done + * later, without holding either the lport or discovery locks. + * The fcoe_ctlr lock may also be held during this call. + */ +static void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *, + enum fc_disc_event), + struct fc_lport *lport) +{ + struct fc_disc *disc = &lport->disc; + struct fcoe_ctlr *fip = disc->priv; + + mutex_lock(&disc->disc_mutex); + disc->disc_callback = callback; + disc->disc_id = (disc->disc_id + 2) | 1; + disc->pending = 1; + schedule_work(&fip->timer_work); + mutex_unlock(&disc->disc_mutex); +} + +/** + * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state. + * @fip: The FCoE controller + * + * Starts the FLOGI and PLOGI login process to each discovered rport for which + * we've received at least one beacon. + * Performs the discovery complete callback. + */ +static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip) +{ + struct fc_lport *lport = fip->lp; + struct fc_disc *disc = &lport->disc; + struct fc_rport_priv *rdata; + struct fcoe_rport *frport; + void (*callback)(struct fc_lport *, enum fc_disc_event); + + mutex_lock(&disc->disc_mutex); + callback = disc->pending ? disc->disc_callback : NULL; + disc->pending = 0; + list_for_each_entry_rcu(rdata, &disc->rports, peers) { + frport = fcoe_ctlr_rport(rdata); + if (frport->time) + lport->tt.rport_login(rdata); + } + mutex_unlock(&disc->disc_mutex); + if (callback) + callback(lport, DISC_EV_SUCCESS); +} + +/** + * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode. + * @fip: The FCoE controller + */ +static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) +{ + unsigned long next_time; + u8 mac[ETH_ALEN]; + u32 new_port_id = 0; + + mutex_lock(&fip->ctlr_mutex); + switch (fip->state) { + case FIP_ST_VNMP_START: + fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1); + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); + next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT); + break; + case FIP_ST_VNMP_PROBE1: + fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2); + fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); + next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); + break; + case FIP_ST_VNMP_PROBE2: + fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM); + new_port_id = fip->port_id; + hton24(mac, FIP_VN_FC_MAP); + hton24(mac + 3, new_port_id); + fip->update_mac(fip->lp, mac); + fcoe_ctlr_vn_send_claim(fip); + next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); + break; + case FIP_ST_VNMP_CLAIM: + /* + * This may be invoked either by starting discovery so don't + * go to the next state unless it's been long enough. + */ + next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT); + if (time_after_eq(jiffies, next_time)) { + fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP); + fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, + fcoe_all_vn2vn, 0); + next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); + fip->port_ka_time = next_time; + } + fcoe_ctlr_vn_disc(fip); + break; + case FIP_ST_VNMP_UP: + next_time = fcoe_ctlr_vn_age(fip); + if (time_after_eq(jiffies, fip->port_ka_time)) { + fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, + fcoe_all_vn2vn, 0); + fip->port_ka_time = jiffies + + msecs_to_jiffies(FIP_VN_BEACON_INT + + (random32() % FIP_VN_BEACON_FUZZ)); + } + if (time_before(fip->port_ka_time, next_time)) + next_time = fip->port_ka_time; + break; + case FIP_ST_LINK_WAIT: + goto unlock; + default: + WARN(1, "unexpected state %d", fip->state); + goto unlock; + } + mod_timer(&fip->timer, next_time); +unlock: + mutex_unlock(&fip->ctlr_mutex); + + /* If port ID is new, notify local port after dropping ctlr_mutex */ + if (new_port_id) + fc_lport_set_local_id(fip->lp, new_port_id); +} + /** * fcoe_libfc_config() - Sets up libfc related properties for local port * @lp: The local port to configure libfc for + * @fip: The FCoE controller in use by the local port * @tt: The libfc function template + * @init_fcp: If non-zero, the FCP portion of libfc should be initialized * * Returns : 0 for success */ -int fcoe_libfc_config(struct fc_lport *lport, - struct libfc_function_template *tt) +int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, + const struct libfc_function_template *tt, int init_fcp) { /* Set the function pointers set by the LLDD */ memcpy(&lport->tt, tt, sizeof(*tt)); - if (fc_fcp_init(lport)) + if (init_fcp && fc_fcp_init(lport)) return -ENOMEM; fc_exch_init(lport); fc_elsct_init(lport); fc_lport_init(lport); + if (fip->mode == FIP_MODE_VN2VN) + lport->rport_priv_size = sizeof(struct fcoe_rport); fc_rport_init(lport); - fc_disc_init(lport); - + if (fip->mode == FIP_MODE_VN2VN) { + lport->point_to_multipoint = 1; + lport->tt.disc_recv_req = fcoe_ctlr_disc_recv; + lport->tt.disc_start = fcoe_ctlr_disc_start; + lport->tt.disc_stop = fcoe_ctlr_disc_stop; + lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final; + mutex_init(&lport->disc.disc_mutex); + INIT_LIST_HEAD(&lport->disc.rports); + lport->disc.priv = fip; + } else { + fc_disc_init(lport); + } return 0; } EXPORT_SYMBOL_GPL(fcoe_libfc_config); - diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index d0fe1c3345b..9eb7a9ebcca 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -673,7 +673,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev, /* Start local port initiatialization */ lp->link_up = 0; - lp->tt = fnic_transport_template; lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; @@ -689,11 +688,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev, fc_set_wwnn(lp, fnic->config.node_wwn); fc_set_wwpn(lp, fnic->config.port_wwn); - fc_lport_init(lp); - fc_exch_init(lp); - fc_elsct_init(lp); - fc_rport_init(lp); - fc_disc_init(lp); + fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0); if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, FCPIO_HOST_EXCH_RANGE_END, NULL)) { diff --git a/include/scsi/libfcoe.h b/include/scsi/libfcoe.h index 1a84a3182da..06f1b5a8ed1 100644 --- a/include/scsi/libfcoe.h +++ b/include/scsi/libfcoe.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,7 @@ #define FCOE_CTLR_START_DELAY 2000 /* mS after first adv. to choose FCF */ #define FCOE_CTRL_SOL_TOV 2000 /* min. solicitation interval (mS) */ #define FCOE_CTLR_FCF_LIMIT 20 /* max. number of FCF entries */ +#define FCOE_CTLR_VN2VN_LOGIN_LIMIT 3 /* max. VN2VN rport login retries */ /** * enum fip_state - internal state of FCoE controller. @@ -45,6 +47,11 @@ * @FIP_ST_AUTO: determining whether to use FIP or non-FIP mode. * @FIP_ST_NON_FIP: non-FIP mode selected. * @FIP_ST_ENABLED: FIP mode selected. + * @FIP_ST_VNMP_START: VN2VN multipath mode start, wait + * @FIP_ST_VNMP_PROBE1: VN2VN sent first probe, listening + * @FIP_ST_VNMP_PROBE2: VN2VN sent second probe, listening + * @FIP_ST_VNMP_CLAIM: VN2VN sent claim, waiting for responses + * @FIP_ST_VNMP_UP: VN2VN multipath mode operation */ enum fip_state { FIP_ST_DISABLED, @@ -52,6 +59,11 @@ enum fip_state { FIP_ST_AUTO, FIP_ST_NON_FIP, FIP_ST_ENABLED, + FIP_ST_VNMP_START, + FIP_ST_VNMP_PROBE1, + FIP_ST_VNMP_PROBE2, + FIP_ST_VNMP_CLAIM, + FIP_ST_VNMP_UP, }; /* @@ -62,6 +74,7 @@ enum fip_state { #define FIP_MODE_AUTO FIP_ST_AUTO #define FIP_MODE_NON_FIP FIP_ST_NON_FIP #define FIP_MODE_FABRIC FIP_ST_ENABLED +#define FIP_MODE_VN2VN FIP_ST_VNMP_START /** * struct fcoe_ctlr - FCoE Controller and FIP state @@ -79,11 +92,14 @@ enum fip_state { * @timer_work: &work_struct for doing keep-alives and resets. * @recv_work: &work_struct for receiving FIP frames. * @fip_recv_list: list of received FIP frames. + * @rnd_state: state for pseudo-random number generator. + * @port_id: proposed or selected local-port ID. * @user_mfs: configured maximum FC frame size, including FC header. * @flogi_oxid: exchange ID of most recent fabric login. * @flogi_count: number of FLOGI attempts in AUTO mode. * @map_dest: use the FC_MAP mode for destination MAC addresses. * @spma: supports SPMA server-provided MACs mode + * @probe_tries: number of FC_IDs probed * @dest_addr: MAC address of the selected FC forwarder. * @ctl_src_addr: the native MAC address of our local port. * @send: LLD-supplied function to handle sending FIP Ethernet frames @@ -110,11 +126,16 @@ struct fcoe_ctlr { struct work_struct timer_work; struct work_struct recv_work; struct sk_buff_head fip_recv_list; + + struct rnd_state rnd_state; + u32 port_id; + u16 user_mfs; u16 flogi_oxid; u8 flogi_count; u8 map_dest; u8 spma; + u8 probe_tries; u8 dest_addr[ETH_ALEN]; u8 ctl_src_addr[ETH_ALEN]; @@ -160,6 +181,24 @@ struct fcoe_fcf { u8 fd_flags:1; }; +/** + * struct fcoe_rport - VN2VN remote port + * @time: time of create or last beacon packet received from node + * @fcoe_len: max FCoE frame size, not including VLAN or Ethernet headers + * @flags: flags from probe or claim + * @login_count: number of unsuccessful rport logins to this port + * @enode_mac: E_Node control MAC address + * @vn_mac: VN_Node assigned MAC address for data + */ +struct fcoe_rport { + unsigned long time; + u16 fcoe_len; + u16 flags; + u8 login_count; + u8 enode_mac[ETH_ALEN]; + u8 vn_mac[ETH_ALEN]; +}; + /* FIP API functions */ void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state); void fcoe_ctlr_destroy(struct fcoe_ctlr *); @@ -172,7 +211,8 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *, /* libfcoe funcs */ u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int); -int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *); +int fcoe_libfc_config(struct fc_lport *, struct fcoe_ctlr *, + const struct libfc_function_template *, int init_fcp); /** * is_fip_mode() - returns true if FIP mode selected. -- cgit v1.2.3-70-g09d2 From 5554345bc5275afed760631277fdab0a5a19472e Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:35 -0700 Subject: [SCSI] libfcoe: Fix FIP ELS encapsulation details for FLOGI responses When sending a FLOGI LS_ACC, which we only do in point-to-multipoint mode, the MAC descriptor should have the granted MAC set to 0x0efd00 || D_ID. When sending an LS_RJT, there should be no MAC descriptor. When sending either an LS_ACC or LS_RJT, the subcode should indicate an reply, not a request. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 79df78f2b08..4865e818117 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -469,11 +469,15 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, struct fip_header fip; struct fip_encaps encaps; } __attribute__((packed)) *cap; + struct fc_frame_header *fh; struct fip_mac_desc *mac; struct fcoe_fcf *fcf; size_t dlen; u16 fip_flags; + u8 op; + fh = (struct fc_frame_header *)skb->data; + op = *(u8 *)(fh + 1); dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); memset(cap, 0, sizeof(*cap)); @@ -481,6 +485,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, if (lport->point_to_multipoint) { if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest)) return -ENODEV; + fip_flags = 0; } else { fcf = fip->sel_fcf; if (!fcf) @@ -497,26 +502,35 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); cap->fip.fip_op = htons(FIP_OP_LS); - cap->fip.fip_subcode = FIP_SC_REQ; - cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW); + if (op == ELS_LS_ACC || op == ELS_LS_RJT) + cap->fip.fip_subcode = FIP_SC_REP; + else + cap->fip.fip_subcode = FIP_SC_REQ; cap->fip.fip_flags = htons(fip_flags); cap->encaps.fd_desc.fip_dtype = dtype; cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; - mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); - memset(mac, 0, sizeof(*mac)); - mac->fd_desc.fip_dtype = FIP_DT_MAC; - mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; - if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) { - memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - } else if (fip_flags & FIP_FL_SPMA) { - LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n"); - memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); - } else { - LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n"); - /* FPMA only FLOGI must leave the MAC desc set to all 0s */ + if (op != ELS_LS_RJT) { + dlen += sizeof(*mac); + mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); + memset(mac, 0, sizeof(*mac)); + mac->fd_desc.fip_dtype = FIP_DT_MAC; + mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; + if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) { + memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); + } else if (fip->mode == FIP_MODE_VN2VN) { + hton24(mac->fd_mac, FIP_VN_FC_MAP); + hton24(mac->fd_mac + 3, fip->port_id); + } else if (fip_flags & FIP_FL_SPMA) { + LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n"); + memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); + } else { + LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n"); + /* FPMA only FLOGI. Must leave the MAC desc zeroed. */ + } } + cap->fip.fip_dl_len = htons(dlen / FIP_BPW); skb->protocol = htons(ETH_P_FIP); skb_reset_mac_header(skb); -- cgit v1.2.3-70-g09d2 From cd229e42eb8cdfdcbe15dfeec39c3641f62de43a Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:40 -0700 Subject: [SCSI] fcoe libfcoe: use correct FC-MAP for VN2VN mode In VN2VN mode, map_dest means to use the default VN2VN OUI. Change code that uses the default FCoE OUI to use the one set in the fcoe_ctlr struct. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 6 ++---- drivers/scsi/fcoe/libfcoe.c | 24 ++++++++++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 216aba375fe..4d3e70ab65b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1534,11 +1534,9 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) /* fill up mac and fcoe headers */ eh = eth_hdr(skb); eh->h_proto = htons(ETH_P_FCOE); + memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN); if (fcoe->ctlr.map_dest) - fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); - else - /* insert GW address */ - memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN); + memcpy(eh->h_dest + 3, fh->fh_d_id, 3); if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN)) memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN); diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 4865e818117..4de8ced1fee 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -152,6 +152,20 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) return (fcf->flags & flags) == flags; } +/** + * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses + * @fip: The FCoE controller + */ +static void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip) +{ + if (fip->mode == FIP_MODE_VN2VN) + hton24(fip->dest_addr, FIP_VN_FC_MAP); + else + hton24(fip->dest_addr, FIP_DEF_FC_MAP); + hton24(fip->dest_addr + 3, 0); + fip->map_dest = 1; +} + /** * fcoe_ctlr_init() - Initialize the FCoE Controller instance * @fip: The FCoE controller to initialize @@ -345,7 +359,7 @@ static void fcoe_ctlr_reset(struct fcoe_ctlr *fip) fip->port_ka_time = 0; fip->sol_time = 0; fip->flogi_oxid = FC_XID_UNKNOWN; - fip->map_dest = 0; + fcoe_ctlr_map_dest(fip); } /** @@ -573,11 +587,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, fip->flogi_count++; if (fip->flogi_count < 3) goto drop; - fip->map_dest = 1; + fcoe_ctlr_map_dest(fip); return 0; } if (fip->state == FIP_ST_NON_FIP) - fip->map_dest = 1; + fcoe_ctlr_map_dest(fip); } if (fip->state == FIP_ST_NON_FIP) @@ -1411,6 +1425,7 @@ static void fcoe_ctlr_timer_work(struct work_struct *work) "Fibre-Channel Forwarder MAC %pM\n", fip->lp->host->host_no, sel->fcf_mac); memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN); + fip->map_dest = 0; fip->port_ka_time = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); fip->ctlr_ka_time = jiffies + sel->fka_period; @@ -1527,7 +1542,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, * Otherwise we use the FCoE gateway addr */ if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { - fip->map_dest = 1; + fcoe_ctlr_map_dest(fip); } else { memcpy(fip->dest_addr, sa, ETH_ALEN); fip->map_dest = 0; @@ -2426,6 +2441,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) new_port_id = fip->port_id; hton24(mac, FIP_VN_FC_MAP); hton24(mac + 3, new_port_id); + fcoe_ctlr_map_dest(fip); fip->update_mac(fip->lp, mac); fcoe_ctlr_vn_send_claim(fip); next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); -- cgit v1.2.3-70-g09d2 From 1dd454d9e5205f9a61d51fb97159afeffa0a506c Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:46 -0700 Subject: [SCSI] fcoe: config via separate create_vn2vn module parameter Add module parameter create_vn2vn that behaves like the create parameter except that the new instance is created in FIP vn2vn mode. This can be replaced once we change create to allow modifying per-instance attributes before starting the instance. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 4d3e70ab65b..ab6ea60f2ae 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -117,9 +117,14 @@ static void fcoe_recv_frame(struct sk_buff *skb); static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *); -module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR); +module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR); __MODULE_PARM_TYPE(create, "string"); MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface"); +module_param_call(create_vn2vn, fcoe_create, NULL, + (void *)FIP_MODE_VN2VN, S_IWUSR); +__MODULE_PARM_TYPE(create_vn2vn, "string"); +MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance " + "on an Ethernet interface"); module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR); __MODULE_PARM_TYPE(destroy, "string"); MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface"); @@ -341,10 +346,12 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, /** * fcoe_interface_create() - Create a FCoE interface on a net device * @netdev: The net device to create the FCoE interface on + * @fip_mode: The mode to use for FIP * * Returns: pointer to a struct fcoe_interface or NULL on error */ -static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) +static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, + enum fip_state fip_mode) { struct fcoe_interface *fcoe; int err; @@ -361,7 +368,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) /* * Initialize FIP. */ - fcoe_ctlr_init(&fcoe->ctlr, FIP_MODE_AUTO); + fcoe_ctlr_init(&fcoe->ctlr, fip_mode); fcoe->ctlr.send = fcoe_fip_send; fcoe->ctlr.update_mac = fcoe_update_src_mac; fcoe->ctlr.get_src_addr = fcoe_get_src_mac; @@ -2088,6 +2095,7 @@ static void fcoe_destroy_work(struct work_struct *work) */ static int fcoe_create(const char *buffer, struct kernel_param *kp) { + enum fip_state fip_mode = (enum fip_state)(long)kp->arg; int rc; struct fcoe_interface *fcoe; struct fc_lport *lport; @@ -2129,7 +2137,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) goto out_putdev; } - fcoe = fcoe_interface_create(netdev); + fcoe = fcoe_interface_create(netdev, fip_mode); if (!fcoe) { rc = -ENOMEM; goto out_putdev; -- cgit v1.2.3-70-g09d2 From 079ecd8cfe95dfd28b74f3a00d66fdbcdfc8c611 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:51 -0700 Subject: [SCSI] libfc: eliminate rport LOGO state The LOGO state hasn't been used in a while, except in a brief transition to DELETE state while holding the rport mutex. All port LOGO responses have been ignored as well as any timeout if we don't get a response. So this patch just removes LOGO state and simplifies the response handler. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_rport.c | 88 +++++++++++-------------------------------- include/scsi/libfc.h | 2 - 2 files changed, 22 insertions(+), 68 deletions(-) diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 4d6adf29b4f..c06d63e4a00 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -89,7 +89,6 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_PRLI] = "PRLI", [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", - [RPORT_ST_LOGO] = "LOGO", [RPORT_ST_ADISC] = "ADISC", [RPORT_ST_DELETE] = "Delete", }; @@ -514,9 +513,6 @@ static void fc_rport_timeout(struct work_struct *work) case RPORT_ST_RTV: fc_rport_enter_rtv(rdata); break; - case RPORT_ST_LOGO: - fc_rport_enter_logo(rdata); - break; case RPORT_ST_ADISC: fc_rport_enter_adisc(rdata); break; @@ -547,7 +543,6 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) switch (rdata->rp_state) { case RPORT_ST_FLOGI: case RPORT_ST_PLOGI: - case RPORT_ST_LOGO: rdata->flags &= ~FC_RP_STARTED; fc_rport_enter_delete(rdata, RPORT_EV_FAILED); break; @@ -791,7 +786,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, switch (rdata->rp_state) { case RPORT_ST_INIT: - case RPORT_ST_LOGO: case RPORT_ST_DELETE: mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_FIP; @@ -1036,52 +1030,6 @@ err: kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); } -/** - * fc_rport_logo_resp() - Handler for logout (LOGO) responses - * @sp: The sequence the LOGO was on - * @fp: The LOGO response frame - * @rdata_arg: The remote port that sent the LOGO response - * - * Locking Note: This function will be called without the rport lock - * held, but it will lock, call an _enter_* function or fc_rport_error - * and then unlock the rport. - */ -static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - u8 op; - - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp)); - - if (rdata->rp_state != RPORT_ST_LOGO) { - FC_RPORT_DBG(rdata, "Received a LOGO response, but in state " - "%s\n", fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error_retry(rdata, fp); - goto err; - } - - op = fc_frame_payload_op(fp); - if (op != ELS_LS_ACC) - FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n", - op); - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); -} - /** * fc_rport_enter_prli() - Send Process Login (PRLI) request * @rdata: The remote port to send the PRLI request to @@ -1223,6 +1171,24 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) kref_get(&rdata->kref); } +/** + * fc_rport_logo_resp() - Handler for logout (LOGO) responses + * @sp: The sequence the LOGO was on + * @fp: The LOGO response frame + * @lport_arg: The local port + */ +static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, + void *lport_arg) +{ + struct fc_lport *lport = lport_arg; + + FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did, + "Received a LOGO %s\n", fc_els_resp_type(fp)); + if (IS_ERR(fp)) + return; + fc_frame_free(fp); +} + /** * fc_rport_enter_logo() - Send a logout (LOGO) request * @rdata: The remote port to send the LOGO request to @@ -1235,23 +1201,14 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; - FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n", + FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n", fc_rport_state(rdata)); - fc_rport_state_enter(rdata, RPORT_ST_LOGO); - fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); - if (!fp) { - fc_rport_error_retry(rdata, fp); + if (!fp) return; - } - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, - fc_rport_logo_resp, rdata, - 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); + (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, + fc_rport_logo_resp, lport, 0); } /** @@ -1670,7 +1627,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, break; case RPORT_ST_FLOGI: case RPORT_ST_DELETE: - case RPORT_ST_LOGO: FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", fc_rport_state(rdata)); mutex_unlock(&rdata->rp_mutex); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 8d297f9a0a4..e6f07fba432 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -103,7 +103,6 @@ enum fc_disc_event { * @RPORT_ST_PRLI: Waiting for PRLI completion * @RPORT_ST_RTV: Waiting for RTV completion * @RPORT_ST_READY: Ready for use - * @RPORT_ST_LOGO: Remote port logout (LOGO) sent * @RPORT_ST_ADISC: Discover Address sent * @RPORT_ST_DELETE: Remote port being deleted */ @@ -115,7 +114,6 @@ enum fc_rport_state { RPORT_ST_PRLI, RPORT_ST_RTV, RPORT_ST_READY, - RPORT_ST_LOGO, RPORT_ST_ADISC, RPORT_ST_DELETE, }; -- cgit v1.2.3-70-g09d2 From 251748a99e631a2c46edcf9e519cfc60fae8153d Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:20:56 -0700 Subject: [SCSI] libfc: add fc_frame_sid() and fc_frame_did() functions To pave the way for eliminating exchanges from incoming requests, add simple inline fc_frame_sid() and fc_frame_did() functions which get the FC_IDs from the frame header. This can be almost as efficient as getting them from the sequence/exchange. Move ntohll, htonll, ntoh24 and hton24 to since we need them there and that's included by Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 12 ++++-------- drivers/scsi/libfc/fc_rport.c | 26 ++++++------------------- include/scsi/fc_frame.h | 45 ++++++++++++++++++++++++++++++++++++++++++- include/scsi/libfc.h | 18 ----------------- 4 files changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index ec9850c4617..be3c2cee829 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -800,7 +800,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, struct fc_lport *lport) { struct fc_frame *fp; - struct fc_frame_header *fh; struct fc_seq *sp; struct fc_exch *ep; struct fc_els_flogi *flp; @@ -813,8 +812,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); - fh = fc_frame_header_get(rx_fp); - remote_fid = ntoh24(fh->fh_s_id); + remote_fid = fc_frame_sid(rx_fp); flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); if (!flp) goto out; @@ -910,7 +908,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, recv = fc_lport_recv_flogi_req; break; case ELS_LOGO: - if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) + if (fc_frame_sid(fp) == FC_FID_FLOGI) recv = fc_lport_recv_logo_req; break; case ELS_RSCN: @@ -1468,7 +1466,6 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, void *lp_arg) { struct fc_lport *lport = lp_arg; - struct fc_frame_header *fh; struct fc_els_flogi *flp; u32 did; u16 csp_flags; @@ -1496,8 +1493,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, goto err; } - fh = fc_frame_header_get(fp); - did = ntoh24(fh->fh_d_id); + did = fc_frame_did(fp); if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { flp = fc_frame_payload_get(fp, sizeof(*flp)); if (flp) { @@ -1523,7 +1519,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, "Port (%6.6x) entered " "point-to-point mode\n", lport->host->host_no, did); - fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id), + fc_lport_ptp_setup(lport, fc_frame_sid(fp), get_unaligned_be64( &flp->fl_wwpn), get_unaligned_be64( diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index c06d63e4a00..12349316682 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -747,13 +747,11 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; struct fc_exch *ep; - struct fc_frame_header *fh; struct fc_seq_els_data rjt_data; u32 sid, f_ctl; rjt_data.fp = NULL; - fh = fc_frame_header_get(fp); - sid = ntoh24(fh->fh_s_id); + sid = fc_frame_sid(fp); FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); @@ -1430,17 +1428,14 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp) { struct fc_rport_priv *rdata; - struct fc_frame_header *fh; struct fc_seq_els_data els_data; els_data.fp = NULL; els_data.reason = ELS_RJT_UNAB; els_data.explan = ELS_EXPL_PLOGI_REQD; - fh = fc_frame_header_get(fp); - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id)); + rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp)); if (!rdata) { mutex_unlock(&lport->disc.disc_mutex); goto reject; @@ -1555,14 +1550,12 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; struct fc_exch *ep; - struct fc_frame_header *fh; struct fc_els_flogi *pl; struct fc_seq_els_data rjt_data; u32 sid, f_ctl; rjt_data.fp = NULL; - fh = fc_frame_header_get(fp); - sid = ntoh24(fh->fh_s_id); + sid = fc_frame_sid(fp); FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); @@ -1682,7 +1675,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_lport *lport = rdata->local_port; struct fc_exch *ep; struct fc_frame *fp; - struct fc_frame_header *fh; struct { struct fc_els_prli prli; struct fc_els_spp spp; @@ -1698,12 +1690,10 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, u32 roles = FC_RPORT_ROLE_UNKNOWN; rjt_data.fp = NULL; - fh = fc_frame_header_get(rx_fp); - FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", fc_rport_state(rdata)); - len = fr_len(rx_fp) - sizeof(*fh); + len = fr_len(rx_fp) - sizeof(struct fc_frame_header); pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); if (!pp) goto reject_len; @@ -1817,7 +1807,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; - struct fc_frame_header *fh; struct fc_exch *ep; struct fc_frame *fp; struct { @@ -1832,12 +1821,11 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, struct fc_seq_els_data rjt_data; rjt_data.fp = NULL; - fh = fc_frame_header_get(rx_fp); FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", fc_rport_state(rdata)); - len = fr_len(rx_fp) - sizeof(*fh); + len = fr_len(rx_fp) - sizeof(struct fc_frame_header); pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); if (!pp) goto reject_len; @@ -1901,14 +1889,12 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_seq *sp, struct fc_frame *fp) { - struct fc_frame_header *fh; struct fc_rport_priv *rdata; u32 sid; lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); - fh = fc_frame_header_get(fp); - sid = ntoh24(fh->fh_s_id); + sid = fc_frame_sid(fp); mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, sid); diff --git a/include/scsi/fc_frame.h b/include/scsi/fc_frame.h index 29dd97d5b53..4ad02041b66 100644 --- a/include/scsi/fc_frame.h +++ b/include/scsi/fc_frame.h @@ -30,6 +30,23 @@ #include +/* some helpful macros */ + +#define ntohll(x) be64_to_cpu(x) +#define htonll(x) cpu_to_be64(x) + +static inline u32 ntoh24(const u8 *p) +{ + return (p[0] << 16) | (p[1] << 8) | p[2]; +} + +static inline void hton24(u8 *p, u32 v) +{ + p[0] = (v >> 16) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = v & 0xff; +} + /* * The fc_frame interface is used to pass frame data between functions. * The frame includes the data buffer, length, and SOF / EOF delimiter types. @@ -137,6 +154,16 @@ static inline int fc_frame_is_linear(struct fc_frame *fp) return !skb_is_nonlinear(fp_skb(fp)); } +/* + * Get frame header from message in fc_frame structure. + * This version doesn't do a length check. + */ +static inline +struct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp) +{ + return (struct fc_frame_header *)fr_hdr(fp); +} + /* * Get frame header from message in fc_frame structure. * This hides a cast and provides a place to add some checking. @@ -145,7 +172,23 @@ static inline struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp) { WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header)); - return (struct fc_frame_header *) fr_hdr(fp); + return __fc_frame_header_get(fp); +} + +/* + * Get source FC_ID (S_ID) from frame header in message. + */ +static inline u32 fc_frame_sid(const struct fc_frame *fp) +{ + return ntoh24(__fc_frame_header_get(fp)->fh_s_id); +} + +/* + * Get destination FC_ID (D_ID) from frame header in message. + */ +static inline u32 fc_frame_did(const struct fc_frame *fp) +{ + return ntoh24(__fc_frame_header_get(fp)->fh_d_id); } /* diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index e6f07fba432..f1ce793f33b 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -42,24 +42,6 @@ #define FC_EX_TIMEOUT 1 /* Exchange timeout */ #define FC_EX_CLOSED 2 /* Exchange closed */ -/* some helpful macros */ - -#define ntohll(x) be64_to_cpu(x) -#define htonll(x) cpu_to_be64(x) - - -static inline u32 ntoh24(const u8 *p) -{ - return (p[0] << 16) | (p[1] << 8) | p[2]; -} - -static inline void hton24(u8 *p, u32 v) -{ - p[0] = (v >> 16) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = v & 0xff; -} - /** * enum fc_lport_state - Local port states * @LPORT_ST_DISABLED: Disabled -- cgit v1.2.3-70-g09d2 From 24f089e2f2c800f88039e9d536d558ec6e349fad Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:21:01 -0700 Subject: [SCSI] libfc: add fc_fill_reply_hdr() and fc_fill_hdr() Add functions to fill in an FC header given a request header. These reduces code lines in fc_lport and fc_rport and works without an exchange/sequence assigned. fc_fill_reply_hdr() fills a header for a final reply frame. fc_fill_hdr() which is similar but allows specifying the f_ctl parameter. Add defines for F_CTL values FC_FCTL_REQ and FC_FCTL_RESP. These can be used for most request and response sequences. v2 of patch adds a line to copy the frame encapsulation info from the received frame. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_elsct.c | 2 +- drivers/scsi/libfc/fc_fcp.c | 6 ++-- drivers/scsi/libfc/fc_libfc.c | 78 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 39 +++++++--------------- drivers/scsi/libfc/fc_rport.c | 64 +++++++++-------------------------- include/scsi/fc_encode.h | 7 ++++ include/scsi/libfc.h | 4 +++ 7 files changed, 121 insertions(+), 79 deletions(-) diff --git a/drivers/scsi/libfc/fc_elsct.c b/drivers/scsi/libfc/fc_elsct.c index e9412b710fa..9b25969e2ad 100644 --- a/drivers/scsi/libfc/fc_elsct.c +++ b/drivers/scsi/libfc/fc_elsct.c @@ -64,7 +64,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, } fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + FC_FCTL_REQ, 0); return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); } diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 61a12970bd1..eac4d09314e 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1108,7 +1108,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, rpriv->local_port->port_id, FC_TYPE_FCP, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + FC_FCTL_REQ, 0); seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy, fsp, 0); @@ -1381,7 +1381,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp) fr_seq(fp) = fsp->seq_ptr; fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, rpriv->local_port->port_id, FC_TYPE_ELS, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + FC_FCTL_REQ, 0); if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC, fc_fcp_rec_resp, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV))) { @@ -1639,7 +1639,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, rpriv->local_port->port_id, FC_TYPE_FCP, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); + FC_FCTL_REQ, 0); seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL, fsp, jiffies_to_msecs(FC_SCSI_REC_TOV)); diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index 39f4b6ab04b..6a48c28e442 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -23,6 +23,7 @@ #include #include +#include #include "fc_libfc.h" @@ -132,3 +133,80 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, } return copy_len; } + +/** + * fc_fill_hdr() - fill FC header fields based on request + * @fp: reply frame containing header to be filled in + * @in_fp: request frame containing header to use in filling in reply + * @r_ctl: R_CTL value for header + * @f_ctl: F_CTL value for header, with 0 pad + * @seq_cnt: sequence count for the header, ignored if frame has a sequence + * @parm_offset: parameter / offset value + */ +void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, + enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset) +{ + struct fc_frame_header *fh; + struct fc_frame_header *in_fh; + struct fc_seq *sp; + u32 fill; + + fh = __fc_frame_header_get(fp); + in_fh = __fc_frame_header_get(in_fp); + + if (f_ctl & FC_FC_END_SEQ) { + fill = -fr_len(fp) & 3; + if (fill) { + /* TODO, this may be a problem with fragmented skb */ + memset(skb_put(fp_skb(fp), fill), 0, fill); + f_ctl |= fill; + } + fr_eof(fp) = FC_EOF_T; + } else { + WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ + fr_eof(fp) = FC_EOF_N; + } + + fh->fh_r_ctl = r_ctl; + memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id)); + memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id)); + fh->fh_type = in_fh->fh_type; + hton24(fh->fh_f_ctl, f_ctl); + fh->fh_ox_id = in_fh->fh_ox_id; + fh->fh_rx_id = in_fh->fh_rx_id; + fh->fh_cs_ctl = 0; + fh->fh_df_ctl = 0; + fh->fh_parm_offset = htonl(parm_offset); + + sp = fr_seq(in_fp); + if (sp) { + fr_seq(fp) = sp; + fh->fh_seq_id = sp->id; + seq_cnt = sp->cnt; + } else { + fh->fh_seq_id = 0; + } + fh->fh_seq_cnt = ntohs(seq_cnt); + fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3; + fr_encaps(fp) = fr_encaps(in_fp); +} +EXPORT_SYMBOL(fc_fill_hdr); + +/** + * fc_fill_reply_hdr() - fill FC reply header fields based on request + * @fp: reply frame containing header to be filled in + * @in_fp: request frame containing header to use in filling in reply + * @r_ctl: R_CTL value for reply + * @parm_offset: parameter / offset value + */ +void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, + enum fc_rctl r_ctl, u32 parm_offset) +{ + struct fc_seq *sp; + + sp = fr_seq(in_fp); + if (sp) + fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp); + fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset); +} +EXPORT_SYMBOL(fc_fill_reply_hdr); diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index be3c2cee829..e50a6606d4b 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -405,11 +405,9 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, struct fc_lport *lport) { struct fc_frame *fp; - struct fc_exch *ep = fc_seq_exch(sp); unsigned int len; void *pp; void *dp; - u32 f_ctl; FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", fc_lport_state(lport)); @@ -425,11 +423,8 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, dp = fc_frame_payload_get(fp, len); memcpy(dp, pp, len); *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); } fc_frame_free(in_fp); } @@ -447,7 +442,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, struct fc_lport *lport) { struct fc_frame *fp; - struct fc_exch *ep = fc_seq_exch(sp); struct fc_els_rnid *req; struct { struct fc_els_rnid_resp rnid; @@ -457,7 +451,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, struct fc_seq_els_data rjt_data; u8 fmt; size_t len; - u32 f_ctl; FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", fc_lport_state(lport)); @@ -490,12 +483,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, memcpy(&rp->gen, &lport->rnid_gen, sizeof(rp->gen)); } - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); } } fc_frame_free(in_fp); @@ -800,14 +789,13 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, struct fc_lport *lport) { struct fc_frame *fp; + struct fc_frame_header *fh; struct fc_seq *sp; - struct fc_exch *ep; struct fc_els_flogi *flp; struct fc_els_flogi *new_flp; u64 remote_wwpn; u32 remote_fid; u32 local_fid; - u32 f_ctl; FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); @@ -843,7 +831,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, fp = fc_frame_alloc(lport, sizeof(*flp)); if (fp) { - sp = lport->tt.seq_start_next(fr_seq(rx_fp)); new_flp = fc_frame_payload_get(fp, sizeof(*flp)); fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); new_flp->fl_cmd = (u8) ELS_LS_ACC; @@ -852,11 +839,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, * Send the response. If this fails, the originator should * repeat the sequence. */ - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + fh = fc_frame_header_get(fp); + hton24(fh->fh_s_id, local_fid); + hton24(fh->fh_d_id, remote_fid); + lport->tt.frame_send(lport, fp); } else { fc_lport_error(lport, fp); @@ -1731,8 +1718,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job, hton24(fh->fh_d_id, did); hton24(fh->fh_s_id, lport->port_id); fh->fh_type = FC_TYPE_ELS; - hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | - FC_FC_END_SEQ | FC_FC_SEQ_INIT); + hton24(fh->fh_f_ctl, FC_FCTL_REQ); fh->fh_cs_ctl = 0; fh->fh_df_ctl = 0; fh->fh_parm_offset = 0; @@ -1791,8 +1777,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job, hton24(fh->fh_d_id, did); hton24(fh->fh_s_id, lport->port_id); fh->fh_type = FC_TYPE_CT; - hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ | - FC_FC_END_SEQ | FC_FC_SEQ_INIT); + hton24(fh->fh_f_ctl, FC_FCTL_REQ); fh->fh_cs_ctl = 0; fh->fh_df_ctl = 0; fh->fh_parm_offset = 0; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 12349316682..59879512321 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -746,9 +746,8 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, struct fc_els_flogi *flp; struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; - struct fc_exch *ep; struct fc_seq_els_data rjt_data; - u32 sid, f_ctl; + u32 sid; rjt_data.fp = NULL; sid = fc_frame_sid(fp); @@ -813,7 +812,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, rjt_data.explan = ELS_EXPL_NONE; goto reject; } - fc_frame_free(rx_fp); fp = fc_frame_alloc(lport, sizeof(*flp)); if (!fp) @@ -824,11 +822,8 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, flp = fc_frame_payload_get(fp, sizeof(*flp)); flp->fl_cmd = ELS_LS_ACC; - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); if (rdata->ids.port_name < lport->wwpn) fc_rport_enter_plogi(rdata); @@ -837,12 +832,13 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, out: mutex_unlock(&rdata->rp_mutex); mutex_unlock(&disc->disc_mutex); + fc_frame_free(rx_fp); return; reject: mutex_unlock(&disc->disc_mutex); lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); + fc_frame_free(rx_fp); } /** @@ -1310,10 +1306,8 @@ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, { struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; - struct fc_exch *ep = fc_seq_exch(sp); struct fc_els_adisc *adisc; struct fc_seq_els_data rjt_data; - u32 f_ctl; FC_RPORT_DBG(rdata, "Received ADISC request\n"); @@ -1332,11 +1326,8 @@ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, fc_adisc_fill(lport, fp); adisc = fc_frame_payload_get(fp, sizeof(*adisc)); adisc->adisc_cmd = ELS_LS_ACC; - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); drop: fc_frame_free(in_fp); } @@ -1356,13 +1347,11 @@ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, { struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; - struct fc_exch *ep = fc_seq_exch(sp); struct fc_els_rls *rls; struct fc_els_rls_resp *rsp; struct fc_els_lesb *lesb; struct fc_seq_els_data rjt_data; struct fc_host_statistics *hst; - u32 f_ctl; FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n", fc_rport_state(rdata)); @@ -1399,11 +1388,8 @@ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, lesb->lesb_inv_crc = htonl(hst->invalid_crc_count); } - sp = lport->tt.seq_start_next(sp); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); goto out; out_rjt: @@ -1549,10 +1535,9 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, struct fc_disc *disc; struct fc_rport_priv *rdata; struct fc_frame *fp = rx_fp; - struct fc_exch *ep; struct fc_els_flogi *pl; struct fc_seq_els_data rjt_data; - u32 sid, f_ctl; + u32 sid; rjt_data.fp = NULL; sid = fc_frame_sid(fp); @@ -1632,27 +1617,21 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, * Get session payload size from incoming PLOGI. */ rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); - fc_frame_free(rx_fp); /* * Send LS_ACC. If this fails, the originator should retry. */ - sp = lport->tt.seq_start_next(sp); - if (!sp) - goto out; fp = fc_frame_alloc(lport, sizeof(*pl)); if (!fp) goto out; fc_plogi_fill(lport, fp, ELS_LS_ACC); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); fc_rport_enter_prli(rdata); out: mutex_unlock(&rdata->rp_mutex); + fc_frame_free(rx_fp); return; reject: @@ -1673,7 +1652,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, struct fc_seq *sp, struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; - struct fc_exch *ep; struct fc_frame *fp; struct { struct fc_els_prli prli; @@ -1685,7 +1663,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, unsigned int plen; enum fc_els_spp_resp resp; struct fc_seq_els_data rjt_data; - u32 f_ctl; u32 fcp_parm; u32 roles = FC_RPORT_ROLE_UNKNOWN; @@ -1714,8 +1691,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, rjt_data.explan = ELS_EXPL_INSUF_RES; goto reject; } - sp = lport->tt.seq_start_next(sp); - WARN_ON(!sp); pp = fc_frame_payload_get(fp, len); WARN_ON(!pp); memset(pp, 0, len); @@ -1768,12 +1743,8 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, /* * Send LS_ACC. If this fails, the originator should retry. */ - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); switch (rdata->rp_state) { case RPORT_ST_PRLI: @@ -1817,7 +1788,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, struct fc_els_spp *spp; /* response spp */ unsigned int len; unsigned int plen; - u32 f_ctl; struct fc_seq_els_data rjt_data; rjt_data.fp = NULL; @@ -1859,11 +1829,9 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ; - f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT; ep = fc_seq_exch(sp); fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, f_ctl, 0); + FC_TYPE_ELS, FC_FCTL_RESP, 0); lport->tt.seq_send(lport, sp, fp); goto drop; diff --git a/include/scsi/fc_encode.h b/include/scsi/fc_encode.h index 9b4867c9c2d..6d293c846a4 100644 --- a/include/scsi/fc_encode.h +++ b/include/scsi/fc_encode.h @@ -21,6 +21,13 @@ #define _FC_ENCODE_H_ #include +/* + * F_CTL values for simple requests and responses. + */ +#define FC_FCTL_REQ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT) +#define FC_FCTL_RESP (FC_FC_EX_CTX | FC_FC_LAST_SEQ | \ + FC_FC_END_SEQ | FC_FC_SEQ_INIT) + struct fc_ns_rft { struct fc_ns_fid fid; /* port ID object */ struct fc_ns_fts fts; /* FC4-types object */ diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index f1ce793f33b..a6414ec6380 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -1027,6 +1027,10 @@ struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did, void *arg, u32 timer_msec); void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *); void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *); +void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *, + enum fc_rctl, u32 parm_offset); +void fc_fill_hdr(struct fc_frame *, const struct fc_frame *, + enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset); /* -- cgit v1.2.3-70-g09d2 From 239e81048b7dcd27448db40c845f88ac7c68424e Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:21:07 -0700 Subject: [SCSI] libfc: add interface to allocate a sequence for incoming requests For incoming ELS and FCP requests, we often don't require an exchange and sequence, however, sometimes we do. For those cases, (primarily FCP requests for targets) add a function to set up the exchange and sequence. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 25 +++++++++++++++++++++++++ include/scsi/libfc.h | 7 +++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 61eabd3ce43..027042a6de3 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1230,6 +1230,28 @@ free: fc_frame_free(rx_fp); } +/** + * fc_seq_assign() - Assign exchange and sequence for incoming request + * @lport: The local port that received the request + * @fp: The request frame + * + * On success, the sequence pointer will be returned and also in fr_seq(@fp). + */ +static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) +{ + struct fc_exch_mgr_anchor *ema; + + WARN_ON(lport != fr_dev(fp)); + WARN_ON(fr_seq(fp)); + fr_seq(fp) = NULL; + + list_for_each_entry(ema, &lport->ema_list, ema_list) + if ((!ema->match || ema->match(fp)) && + fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE) + break; + return fr_seq(fp); +} + /** * fc_exch_recv_req() - Handler for an incoming request where is other * end is originating the sequence @@ -2283,6 +2305,9 @@ int fc_exch_init(struct fc_lport *lport) if (!lport->tt.seq_exch_abort) lport->tt.seq_exch_abort = fc_seq_exch_abort; + if (!lport->tt.seq_assign) + lport->tt.seq_assign = fc_seq_assign; + return 0; } EXPORT_SYMBOL(fc_exch_init); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index a6414ec6380..605f1d7861a 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -555,6 +555,13 @@ struct libfc_function_template { */ struct fc_seq *(*seq_start_next)(struct fc_seq *); + /* + * Assign a sequence for an incoming request frame. + * + * STATUS: OPTIONAL + */ + struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *); + /* * Reset an exchange manager, completing all sequences and exchanges. * If s_id is non-zero, reset only exchanges originating from that FID. -- cgit v1.2.3-70-g09d2 From 922611569572d3c1aa0ed6491d21583fb3fcca22 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 20 Jul 2010 15:21:12 -0700 Subject: [SCSI] libfc: don't require a local exchange for incoming requests Incoming requests shouldn't require a local exchange if we're just going to reply with one or two frames and don't expect anything further. Don't allocate exchanges for such requests until requested by the upper-layer protocol. The sequence is always NULL for new requests, so remove that as an argument to request handlers. Also change the first argument to lport->tt.seq_els_rsp_send from the sequence pointer to the received frame pointer, to supply the exchange IDs and destination ID info. Signed-off-by: Joe Eykholt Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 9 +- drivers/scsi/libfc/fc_disc.c | 19 ++--- drivers/scsi/libfc/fc_exch.c | 188 ++++++++++++++++++++++-------------------- drivers/scsi/libfc/fc_lport.c | 58 +++++-------- drivers/scsi/libfc/fc_rport.c | 112 +++++++++---------------- include/scsi/libfc.h | 16 ++-- 6 files changed, 174 insertions(+), 228 deletions(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 4de8ced1fee..2c265fe9ab3 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -2341,20 +2341,19 @@ drop: /** * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode. - * @fip: The FCoE controller + * @lport: The local port + * @fp: The received frame * * This should never be called since we don't see RSCNs or other * fabric-generated ELSes. */ -static void fcoe_ctlr_disc_recv(struct fc_seq *seq, struct fc_frame *fp, - struct fc_lport *lport) +static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp) { struct fc_seq_els_data rjt_data; - rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_UNSUP; rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(seq, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); fc_frame_free(fp); } diff --git a/drivers/scsi/libfc/fc_disc.c b/drivers/scsi/libfc/fc_disc.c index 04474556f2d..32f67c4b03f 100644 --- a/drivers/scsi/libfc/fc_disc.c +++ b/drivers/scsi/libfc/fc_disc.c @@ -75,15 +75,13 @@ void fc_disc_stop_rports(struct fc_disc *disc) /** * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) - * @sp: The sequence of the RSCN exchange + * @disc: The discovery object to which the RSCN applies * @fp: The RSCN frame - * @lport: The local port that the request will be sent on * * Locking Note: This function expects that the disc_mutex is locked * before it is called. */ -static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_disc *disc) +static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) { struct fc_lport *lport; struct fc_els_rscn *rp; @@ -151,7 +149,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, break; } } - lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); /* * If not doing a complete rediscovery, do GPN_ID on @@ -177,25 +175,22 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, return; reject: FC_DISC_DBG(disc, "Received a bad RSCN frame\n"); - rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); fc_frame_free(fp); } /** * fc_disc_recv_req() - Handle incoming requests - * @sp: The sequence of the request exchange - * @fp: The request frame * @lport: The local port receiving the request + * @fp: The request frame * * Locking Note: This function is called from the EM and will lock * the disc_mutex before calling the handler for the * request. */ -static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_lport *lport) +static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp) { u8 op; struct fc_disc *disc = &lport->disc; @@ -204,7 +199,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp, switch (op) { case ELS_RSCN: mutex_lock(&disc->disc_mutex); - fc_disc_recv_rscn_req(sp, fp, disc); + fc_disc_recv_rscn_req(disc, fp); mutex_unlock(&disc->disc_mutex); break; default: diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 027042a6de3..b8560ad8cf6 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -129,11 +129,11 @@ struct fc_exch_mgr_anchor { }; static void fc_exch_rrq(struct fc_exch *); -static void fc_seq_ls_acc(struct fc_seq *); -static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, +static void fc_seq_ls_acc(struct fc_frame *); +static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason, enum fc_els_rjt_explan); -static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *); -static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *); +static void fc_exch_els_rec(struct fc_frame *); +static void fc_exch_els_rrq(struct fc_frame *); /* * Internal implementation notes. @@ -1003,28 +1003,30 @@ static void fc_exch_set_addr(struct fc_exch *ep, /** * fc_seq_els_rsp_send() - Send an ELS response using infomation from * the existing sequence/exchange. - * @sp: The sequence/exchange to get information from + * @fp: The received frame * @els_cmd: The ELS command to be sent * @els_data: The ELS data to be sent + * + * The received frame is not freed. */ -static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, +static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd, struct fc_seq_els_data *els_data) { switch (els_cmd) { case ELS_LS_RJT: - fc_seq_ls_rjt(sp, els_data->reason, els_data->explan); + fc_seq_ls_rjt(fp, els_data->reason, els_data->explan); break; case ELS_LS_ACC: - fc_seq_ls_acc(sp); + fc_seq_ls_acc(fp); break; case ELS_RRQ: - fc_exch_els_rrq(sp, els_data->fp); + fc_exch_els_rrq(fp); break; case ELS_REC: - fc_exch_els_rec(sp, els_data->fp); + fc_exch_els_rec(fp); break; default: - FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd); + FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd); } } @@ -1253,11 +1255,13 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) } /** - * fc_exch_recv_req() - Handler for an incoming request where is other - * end is originating the sequence + * fc_exch_recv_req() - Handler for an incoming request * @lport: The local port that received the request * @mp: The EM that the exchange is on * @fp: The request frame + * + * This is used when the other end is originating the exchange + * and the sequence. */ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, struct fc_frame *fp) @@ -1275,8 +1279,17 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, fc_frame_free(fp); return; } + fr_dev(fp) = lport; + + BUG_ON(fr_seq(fp)); /* XXX remove later */ + + /* + * If the RX_ID is 0xffff, don't allocate an exchange. + * The upper-level protocol may request one later, if needed. + */ + if (fh->fh_rx_id == htons(FC_XID_UNKNOWN)) + return lport->tt.lport_recv(lport, fp); - fr_seq(fp) = NULL; reject = fc_seq_lookup_recip(lport, mp, fp); if (reject == FC_RJT_NONE) { sp = fr_seq(fp); /* sequence will be held */ @@ -1298,7 +1311,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, if (ep->resp) ep->resp(sp, fp, ep->arg); else - lport->tt.lport_recv(lport, sp, fp); + lport->tt.lport_recv(lport, fp); fc_exch_release(ep); /* release from lookup */ } else { FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n", @@ -1566,53 +1579,55 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) /** * fc_seq_ls_acc() - Accept sequence with LS_ACC - * @req_sp: The request sequence + * @rx_fp: The received frame, not freed here. * * If this fails due to allocation or transmit congestion, assume the * originator will repeat the sequence. */ -static void fc_seq_ls_acc(struct fc_seq *req_sp) +static void fc_seq_ls_acc(struct fc_frame *rx_fp) { - struct fc_seq *sp; + struct fc_lport *lport; struct fc_els_ls_acc *acc; struct fc_frame *fp; - sp = fc_seq_start_next(req_sp); - fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); - if (fp) { - acc = fc_frame_payload_get(fp, sizeof(*acc)); - memset(acc, 0, sizeof(*acc)); - acc->la_cmd = ELS_LS_ACC; - fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); - } + lport = fr_dev(rx_fp); + fp = fc_frame_alloc(lport, sizeof(*acc)); + if (!fp) + return; + acc = fc_frame_payload_get(fp, sizeof(*acc)); + memset(acc, 0, sizeof(*acc)); + acc->la_cmd = ELS_LS_ACC; + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); } /** * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT - * @req_sp: The request sequence + * @rx_fp: The received frame, not freed here. * @reason: The reason the sequence is being rejected - * @explan: The explaination for the rejection + * @explan: The explanation for the rejection * * If this fails due to allocation or transmit congestion, assume the * originator will repeat the sequence. */ -static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason, +static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason, enum fc_els_rjt_explan explan) { - struct fc_seq *sp; + struct fc_lport *lport; struct fc_els_ls_rjt *rjt; struct fc_frame *fp; - sp = fc_seq_start_next(req_sp); - fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt)); - if (fp) { - rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - memset(rjt, 0, sizeof(*rjt)); - rjt->er_cmd = ELS_LS_RJT; - rjt->er_reason = reason; - rjt->er_explan = explan; - fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); - } + lport = fr_dev(rx_fp); + fp = fc_frame_alloc(lport, sizeof(*rjt)); + if (!fp) + return; + rjt = fc_frame_payload_get(fp, sizeof(*rjt)); + memset(rjt, 0, sizeof(*rjt)); + rjt->er_cmd = ELS_LS_RJT; + rjt->er_reason = reason; + rjt->er_explan = explan; + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); } /** @@ -1714,18 +1729,34 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) } EXPORT_SYMBOL(fc_exch_mgr_reset); +/** + * fc_exch_lookup() - find an exchange + * @lport: The local port + * @xid: The exchange ID + * + * Returns exchange pointer with hold for caller, or NULL if not found. + */ +static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid) +{ + struct fc_exch_mgr_anchor *ema; + + list_for_each_entry(ema, &lport->ema_list, ema_list) + if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid) + return fc_exch_find(ema->mp, xid); + return NULL; +} + /** * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests - * @sp: The sequence the REC is on - * @rfp: The REC frame + * @rfp: The REC frame, not freed here. * * Note that the requesting port may be different than the S_ID in the request. */ -static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) +static void fc_exch_els_rec(struct fc_frame *rfp) { + struct fc_lport *lport; struct fc_frame *fp; struct fc_exch *ep; - struct fc_exch_mgr *em; struct fc_els_rec *rp; struct fc_els_rec_acc *acc; enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; @@ -1734,6 +1765,7 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) u16 rxid; u16 oxid; + lport = fr_dev(rfp); rp = fc_frame_payload_get(rfp, sizeof(*rp)); explan = ELS_EXPL_INV_LEN; if (!rp) @@ -1742,35 +1774,19 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) rxid = ntohs(rp->rec_rx_id); oxid = ntohs(rp->rec_ox_id); - /* - * Currently it's hard to find the local S_ID from the exchange - * manager. This will eventually be fixed, but for now it's easier - * to lookup the subject exchange twice, once as if we were - * the initiator, and then again if we weren't. - */ - em = fc_seq_exch(sp)->em; - ep = fc_exch_find(em, oxid); + ep = fc_exch_lookup(lport, + sid == fc_host_port_id(lport->host) ? oxid : rxid); explan = ELS_EXPL_OXID_RXID; - if (ep && ep->oid == sid) { - if (ep->rxid != FC_XID_UNKNOWN && - rxid != FC_XID_UNKNOWN && - ep->rxid != rxid) - goto rel; - } else { - if (ep) - fc_exch_release(ep); - ep = NULL; - if (rxid != FC_XID_UNKNOWN) - ep = fc_exch_find(em, rxid); - if (!ep) - goto reject; - } - - fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); - if (!fp) { - fc_exch_done(sp); + if (!ep) + goto reject; + if (ep->oid != sid || oxid != ep->oxid) + goto rel; + if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid) + goto rel; + fp = fc_frame_alloc(lport, sizeof(*acc)); + if (!fp) goto out; - } + acc = fc_frame_payload_get(fp, sizeof(*acc)); memset(acc, 0, sizeof(*acc)); acc->reca_cmd = ELS_LS_ACC; @@ -1785,18 +1801,16 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | ESB_ST_SEQ_INIT | ESB_ST_COMPLETE)); - sp = fc_seq_start_next(sp); - fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); + fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); out: fc_exch_release(ep); - fc_frame_free(rfp); return; rel: fc_exch_release(ep); reject: - fc_seq_ls_rjt(sp, reason, explan); - fc_frame_free(rfp); + fc_seq_ls_rjt(rfp, reason, explan); } /** @@ -1971,20 +1985,20 @@ retry: spin_unlock_bh(&ep->ex_lock); } - /** * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests - * @sp: The sequence that the RRQ is on - * @fp: The RRQ frame + * @fp: The RRQ frame, not freed here. */ -static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) +static void fc_exch_els_rrq(struct fc_frame *fp) { + struct fc_lport *lport; struct fc_exch *ep = NULL; /* request or subject exchange */ struct fc_els_rrq *rp; u32 sid; u16 xid; enum fc_els_rjt_explan explan; + lport = fr_dev(fp); rp = fc_frame_payload_get(fp, sizeof(*rp)); explan = ELS_EXPL_INV_LEN; if (!rp) @@ -1993,11 +2007,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) /* * lookup subject exchange. */ - ep = fc_seq_exch(sp); sid = ntoh24(rp->rrq_s_id); /* subject source */ - xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); - ep = fc_exch_find(ep->em, xid); - + xid = fc_host_port_id(lport->host) == sid ? + ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); + ep = fc_exch_lookup(lport, xid); explan = ELS_EXPL_OXID_RXID; if (!ep) goto reject; @@ -2028,15 +2041,14 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) /* * Send LS_ACC. */ - fc_seq_ls_acc(sp); + fc_seq_ls_acc(fp); goto out; unlock_reject: spin_unlock_bh(&ep->ex_lock); reject: - fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan); + fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan); out: - fc_frame_free(fp); if (ep) fc_exch_release(ep); /* drop hold from fc_exch_find */ } @@ -2267,7 +2279,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) fc_exch_recv_seq_resp(ema->mp, fp); else if (f_ctl & FC_FC_SEQ_CTX) fc_exch_recv_resp(ema->mp, fp); - else + else /* no EX_CTX and no SEQ_CTX */ fc_exch_recv_req(lport, ema->mp, fp); break; default: diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e50a6606d4b..1998c03634d 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -375,34 +375,31 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) /** * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. - * @sp: The sequence in the RLIR exchange - * @fp: The RLIR request frame * @lport: Fibre Channel local port recieving the RLIR + * @fp: The RLIR request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */ -static void fc_lport_recv_rlir_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_lport *lport) +static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) { FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", fc_lport_state(lport)); - lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_frame_free(fp); } /** * fc_lport_recv_echo_req() - Handle received ECHO request - * @sp: The sequence in the ECHO exchange - * @fp: ECHO request frame * @lport: The local port recieving the ECHO + * @fp: ECHO request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */ -static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, - struct fc_lport *lport) +static void fc_lport_recv_echo_req(struct fc_lport *lport, + struct fc_frame *in_fp) { struct fc_frame *fp; unsigned int len; @@ -431,15 +428,14 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp, /** * fc_lport_recv_rnid_req() - Handle received Request Node ID data request - * @sp: The sequence in the RNID exchange - * @fp: The RNID request frame * @lport: The local port recieving the RNID + * @fp: The RNID request frame * * Locking Note: The lport lock is expected to be held before calling * this function. */ -static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, - struct fc_lport *lport) +static void fc_lport_recv_rnid_req(struct fc_lport *lport, + struct fc_frame *in_fp) { struct fc_frame *fp; struct fc_els_rnid *req; @@ -457,10 +453,9 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, req = fc_frame_payload_get(in_fp, sizeof(*req)); if (!req) { - rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); } else { fmt = req->rnid_fmt; len = sizeof(*rp); @@ -492,17 +487,15 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, /** * fc_lport_recv_logo_req() - Handle received fabric LOGO request - * @sp: The sequence in the LOGO exchange - * @fp: The LOGO request frame * @lport: The local port recieving the LOGO + * @fp: The LOGO request frame * * Locking Note: The lport lock is exected to be held before calling * this function. */ -static void fc_lport_recv_logo_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_lport *lport) +static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) { - lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_lport_enter_reset(lport); fc_frame_free(fp); } @@ -773,9 +766,8 @@ EXPORT_SYMBOL(fc_lport_set_local_id); /** * fc_lport_recv_flogi_req() - Receive a FLOGI request - * @sp_in: The sequence the FLOGI is on - * @rx_fp: The FLOGI frame * @lport: The local port that recieved the request + * @rx_fp: The FLOGI frame * * A received FLOGI request indicates a point-to-point connection. * Accept it with the common service parameters indicating our N port. @@ -784,13 +776,11 @@ EXPORT_SYMBOL(fc_lport_set_local_id); * Locking Note: The lport lock is expected to be held before calling * this function. */ -static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, - struct fc_frame *rx_fp, - struct fc_lport *lport) +static void fc_lport_recv_flogi_req(struct fc_lport *lport, + struct fc_frame *rx_fp) { struct fc_frame *fp; struct fc_frame_header *fh; - struct fc_seq *sp; struct fc_els_flogi *flp; struct fc_els_flogi *new_flp; u64 remote_wwpn; @@ -850,16 +840,13 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in, } fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, get_unaligned_be64(&flp->fl_wwnn)); - out: - sp = fr_seq(rx_fp); fc_frame_free(rx_fp); } /** * fc_lport_recv_req() - The generic lport request handler * @lport: The local port that received the request - * @sp: The sequence the request is on * @fp: The request frame * * This function will see if the lport handles the request or @@ -868,11 +855,10 @@ out: * Locking Note: This function should not be called with the lport * lock held becuase it will grab the lock. */ -static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, - struct fc_frame *fp) +static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); - void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *); + void (*recv)(struct fc_lport *, struct fc_frame *); mutex_lock(&lport->lp_mutex); @@ -912,19 +898,13 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, break; } - recv(sp, fp, lport); + recv(lport, fp); } else { FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", fr_eof(fp)); fc_frame_free(fp); } mutex_unlock(&lport->lp_mutex); - - /* - * The common exch_done for all request may not be good - * if any request requires longer hold on exhange. XXX - */ - lport->tt.exch_done(sp); } /** diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 59879512321..25479cc7f17 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -68,14 +68,10 @@ static void fc_rport_enter_ready(struct fc_rport_priv *); static void fc_rport_enter_logo(struct fc_rport_priv *); static void fc_rport_enter_adisc(struct fc_rport_priv *); -static void fc_rport_recv_plogi_req(struct fc_lport *, - struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prli_req(struct fc_rport_priv *, - struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_prlo_req(struct fc_rport_priv *, - struct fc_seq *, struct fc_frame *); -static void fc_rport_recv_logo_req(struct fc_lport *, - struct fc_seq *, struct fc_frame *); +static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *); +static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *); +static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *); +static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *); static void fc_rport_timeout(struct work_struct *); static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); @@ -736,11 +732,10 @@ static void fc_rport_enter_flogi(struct fc_rport_priv *rdata) /** * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode * @lport: The local port that received the PLOGI request - * @sp: The sequence that the PLOGI request was on * @rx_fp: The PLOGI request frame */ static void fc_rport_recv_flogi_req(struct fc_lport *lport, - struct fc_seq *sp, struct fc_frame *rx_fp) + struct fc_frame *rx_fp) { struct fc_disc *disc; struct fc_els_flogi *flp; @@ -749,7 +744,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, struct fc_seq_els_data rjt_data; u32 sid; - rjt_data.fp = NULL; sid = fc_frame_sid(fp); FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); @@ -817,7 +811,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, if (!fp) goto out; - sp = lport->tt.seq_start_next(sp); fc_flogi_fill(lport, fp); flp = fc_frame_payload_get(fp, sizeof(*flp)); flp->fl_cmd = ELS_LS_ACC; @@ -837,7 +830,7 @@ out: reject: mutex_unlock(&disc->disc_mutex); - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); fc_frame_free(rx_fp); } @@ -1296,13 +1289,12 @@ static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) /** * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests * @rdata: The remote port that sent the ADISC request - * @sp: The sequence the ADISC request was on * @in_fp: The ADISC request frame * * Locking Note: Called with the lport and rport locks held. */ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, - struct fc_seq *sp, struct fc_frame *in_fp) + struct fc_frame *in_fp) { struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -1313,10 +1305,9 @@ static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); if (!adisc) { - rjt_data.fp = NULL; rjt_data.reason = ELS_RJT_PROT; rjt_data.explan = ELS_EXPL_INV_LEN; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); goto drop; } @@ -1335,14 +1326,13 @@ drop: /** * fc_rport_recv_rls_req() - Handle received Read Link Status request * @rdata: The remote port that sent the RLS request - * @sp: The sequence that the RLS was on * @rx_fp: The PRLI request frame * * Locking Note: The rport lock is expected to be held before calling * this function. */ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, - struct fc_seq *sp, struct fc_frame *rx_fp) + struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; @@ -1393,8 +1383,7 @@ static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, goto out; out_rjt: - rjt_data.fp = NULL; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); out: fc_frame_free(rx_fp); } @@ -1402,7 +1391,6 @@ out: /** * fc_rport_recv_els_req() - Handler for validated ELS requests * @lport: The local port that received the ELS request - * @sp: The sequence that the ELS request was on * @fp: The ELS request frame * * Handle incoming ELS requests that require port login. @@ -1410,16 +1398,11 @@ out: * * Locking Note: Called with the lport lock held. */ -static void fc_rport_recv_els_req(struct fc_lport *lport, - struct fc_seq *sp, struct fc_frame *fp) +static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_rport_priv *rdata; struct fc_seq_els_data els_data; - els_data.fp = NULL; - els_data.reason = ELS_RJT_UNAB; - els_data.explan = ELS_EXPL_PLOGI_REQD; - mutex_lock(&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp)); if (!rdata) { @@ -1442,24 +1425,24 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, switch (fc_frame_payload_op(fp)) { case ELS_PRLI: - fc_rport_recv_prli_req(rdata, sp, fp); + fc_rport_recv_prli_req(rdata, fp); break; case ELS_PRLO: - fc_rport_recv_prlo_req(rdata, sp, fp); + fc_rport_recv_prlo_req(rdata, fp); break; case ELS_ADISC: - fc_rport_recv_adisc_req(rdata, sp, fp); + fc_rport_recv_adisc_req(rdata, fp); break; case ELS_RRQ: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_RRQ, &els_data); + lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL); + fc_frame_free(fp); break; case ELS_REC: - els_data.fp = fp; - lport->tt.seq_els_rsp_send(sp, ELS_REC, &els_data); + lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL); + fc_frame_free(fp); break; case ELS_RLS: - fc_rport_recv_rls_req(rdata, sp, fp); + fc_rport_recv_rls_req(rdata, fp); break; default: fc_frame_free(fp); /* can't happen */ @@ -1470,20 +1453,20 @@ static void fc_rport_recv_els_req(struct fc_lport *lport, return; reject: - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + els_data.reason = ELS_RJT_UNAB; + els_data.explan = ELS_EXPL_PLOGI_REQD; + lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); fc_frame_free(fp); } /** * fc_rport_recv_req() - Handler for requests - * @sp: The sequence the request was on - * @fp: The request frame * @lport: The local port that received the request + * @fp: The request frame * * Locking Note: Called with the lport lock held. */ -void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, - struct fc_lport *lport) +void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_seq_els_data els_data; @@ -1495,13 +1478,13 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, */ switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: - fc_rport_recv_flogi_req(lport, sp, fp); + fc_rport_recv_flogi_req(lport, fp); break; case ELS_PLOGI: - fc_rport_recv_plogi_req(lport, sp, fp); + fc_rport_recv_plogi_req(lport, fp); break; case ELS_LOGO: - fc_rport_recv_logo_req(lport, sp, fp); + fc_rport_recv_logo_req(lport, fp); break; case ELS_PRLI: case ELS_PRLO: @@ -1509,14 +1492,13 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, case ELS_RRQ: case ELS_REC: case ELS_RLS: - fc_rport_recv_els_req(lport, sp, fp); + fc_rport_recv_els_req(lport, fp); break; default: - fc_frame_free(fp); - els_data.fp = NULL; els_data.reason = ELS_RJT_UNSUP; els_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &els_data); + lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); + fc_frame_free(fp); break; } } @@ -1524,13 +1506,12 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, /** * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests * @lport: The local port that received the PLOGI request - * @sp: The sequence that the PLOGI request was on * @rx_fp: The PLOGI request frame * * Locking Note: The rport lock is held before calling this function. */ static void fc_rport_recv_plogi_req(struct fc_lport *lport, - struct fc_seq *sp, struct fc_frame *rx_fp) + struct fc_frame *rx_fp) { struct fc_disc *disc; struct fc_rport_priv *rdata; @@ -1539,7 +1520,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport, struct fc_seq_els_data rjt_data; u32 sid; - rjt_data.fp = NULL; sid = fc_frame_sid(fp); FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); @@ -1635,21 +1615,20 @@ out: return; reject: - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); fc_frame_free(fp); } /** * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests * @rdata: The remote port that sent the PRLI request - * @sp: The sequence that the PRLI was on * @rx_fp: The PRLI request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, - struct fc_seq *sp, struct fc_frame *rx_fp) + struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; struct fc_frame *fp; @@ -1666,7 +1645,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, u32 fcp_parm; u32 roles = FC_RPORT_ROLE_UNKNOWN; - rjt_data.fp = NULL; FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", fc_rport_state(rdata)); @@ -1759,7 +1737,7 @@ reject_len: rjt_data.reason = ELS_RJT_PROT; rjt_data.explan = ELS_EXPL_INV_LEN; reject: - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); drop: fc_frame_free(rx_fp); } @@ -1767,18 +1745,15 @@ drop: /** * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests * @rdata: The remote port that sent the PRLO request - * @sp: The sequence that the PRLO was on * @rx_fp: The PRLO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, - struct fc_seq *sp, struct fc_frame *rx_fp) { struct fc_lport *lport = rdata->local_port; - struct fc_exch *ep; struct fc_frame *fp; struct { struct fc_els_prlo prlo; @@ -1790,8 +1765,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, unsigned int plen; struct fc_seq_els_data rjt_data; - rjt_data.fp = NULL; - FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", fc_rport_state(rdata)); @@ -1814,8 +1787,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, goto reject; } - sp = lport->tt.seq_start_next(sp); - WARN_ON(!sp); pp = fc_frame_payload_get(fp, len); WARN_ON(!pp); memset(pp, 0, len); @@ -1829,17 +1800,15 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - ep = fc_seq_exch(sp); - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid, - FC_TYPE_ELS, FC_FCTL_RESP, 0); - lport->tt.seq_send(lport, sp, fp); + fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); + lport->tt.frame_send(lport, fp); goto drop; reject_len: rjt_data.reason = ELS_RJT_PROT; rjt_data.explan = ELS_EXPL_INV_LEN; reject: - lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data); + lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); drop: fc_frame_free(rx_fp); } @@ -1847,20 +1816,17 @@ drop: /** * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests * @lport: The local port that received the LOGO request - * @sp: The sequence that the LOGO request was on * @fp: The LOGO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_logo_req(struct fc_lport *lport, - struct fc_seq *sp, - struct fc_frame *fp) +static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) { struct fc_rport_priv *rdata; u32 sid; - lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL); + lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); sid = fc_frame_sid(fp); diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 605f1d7861a..14be49b44e8 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -249,14 +249,12 @@ struct fcoe_dev_stats { /** * struct fc_seq_els_data - ELS data used for passing ELS specific responses - * @fp: The ELS frame * @reason: The reason for rejection * @explan: The explaination of the rejection * * Mainly used by the exchange manager layer. */ struct fc_seq_els_data { - struct fc_frame *fp; enum fc_els_rjt_reason reason; enum fc_els_rjt_explan explan; }; @@ -519,12 +517,11 @@ struct libfc_function_template { struct fc_frame *); /* - * Send an ELS response using infomation from a previous - * exchange and sequence. + * Send an ELS response using infomation from the received frame. * * STATUS: OPTIONAL */ - void (*seq_els_rsp_send)(struct fc_seq *, enum fc_els_cmd, + void (*seq_els_rsp_send)(struct fc_frame *, enum fc_els_cmd, struct fc_seq_els_data *); /* @@ -583,8 +580,7 @@ struct libfc_function_template { * * STATUS: OPTIONAL */ - void (*lport_recv)(struct fc_lport *, struct fc_seq *, - struct fc_frame *); + void (*lport_recv)(struct fc_lport *, struct fc_frame *); /* * Reset the local port. @@ -646,8 +642,7 @@ struct libfc_function_template { * * STATUS: OPTIONAL */ - void (*rport_recv_req)(struct fc_seq *, struct fc_frame *, - struct fc_lport *); + void (*rport_recv_req)(struct fc_lport *, struct fc_frame *); /* * lookup an rport by it's port ID. @@ -693,8 +688,7 @@ struct libfc_function_template { * * STATUS: OPTIONAL */ - void (*disc_recv_req)(struct fc_seq *, struct fc_frame *, - struct fc_lport *); + void (*disc_recv_req)(struct fc_lport *, struct fc_frame *); /* * Start discovery for a local port. -- cgit v1.2.3-70-g09d2 From 54a5b21da9d4d3f58770da5d1c244db9724659ee Mon Sep 17 00:00:00 2001 From: Yi Zou Date: Tue, 20 Jul 2010 15:21:17 -0700 Subject: [SCSI] fcoe: fix offload feature flag change from netdev Currently, when FCoE netdev feature flags are toggled by the LLD, lport's corresponding flags are not updated. This causes the fc_fcp to still try to offload the I/O. This patch adds support of NETDEV_FEAT_CHANGE event in fcoe netdev device notification callback so we can update the lport offload flags appropriately. Signed-off-by: Yi Zou Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 68 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ab6ea60f2ae..cf9d718c731 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -588,6 +588,50 @@ static int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) return -EINVAL; } +/** + * fcoe_netdev_features_change - Updates the lport's offload flags based + * on the LLD netdev's FCoE feature flags + */ +static void fcoe_netdev_features_change(struct fc_lport *lport, + struct net_device *netdev) +{ + mutex_lock(&lport->lp_mutex); + + if (netdev->features & NETIF_F_SG) + lport->sg_supp = 1; + else + lport->sg_supp = 0; + + if (netdev->features & NETIF_F_FCOE_CRC) { + lport->crc_offload = 1; + FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); + } else { + lport->crc_offload = 0; + } + + if (netdev->features & NETIF_F_FSO) { + lport->seq_offload = 1; + lport->lso_max = netdev->gso_max_size; + FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", + lport->lso_max); + } else { + lport->seq_offload = 0; + lport->lso_max = 0; + } + + if (netdev->fcoe_ddp_xid) { + lport->lro_enabled = 1; + lport->lro_xid = netdev->fcoe_ddp_xid; + FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", + lport->lro_xid); + } else { + lport->lro_enabled = 0; + lport->lro_xid = 0; + } + + mutex_unlock(&lport->lp_mutex); +} + /** * fcoe_netdev_config() - Set up net devive for SW FCoE * @lport: The local port that is associated with the net device @@ -624,25 +668,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) return -EINVAL; /* offload features support */ - if (netdev->features & NETIF_F_SG) - lport->sg_supp = 1; + fcoe_netdev_features_change(lport, netdev); - if (netdev->features & NETIF_F_FCOE_CRC) { - lport->crc_offload = 1; - FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); - } - if (netdev->features & NETIF_F_FSO) { - lport->seq_offload = 1; - lport->lso_max = netdev->gso_max_size; - FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", - lport->lso_max); - } - if (netdev->fcoe_ddp_xid) { - lport->lro_enabled = 1; - lport->lro_xid = netdev->fcoe_ddp_xid; - FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", - lport->lro_xid); - } skb_queue_head_init(&port->fcoe_pending_queue); port->fcoe_pending_queue_active = 0; setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); @@ -1861,6 +1888,9 @@ static int fcoe_device_notification(struct notifier_block *notifier, schedule_work(&port->destroy_work); goto out; break; + case NETDEV_FEAT_CHANGE: + fcoe_netdev_features_change(lport, netdev); + break; default: FCOE_NETDEV_DBG(netdev, "Unknown event %ld " "from netdev netlink\n", event); @@ -2056,8 +2086,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV; goto out_putdev; } - list_del(&fcoe->list); fcoe_interface_cleanup(fcoe); + list_del(&fcoe->list); /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(fcoe->ctlr.lp); -- cgit v1.2.3-70-g09d2 From cf4aebcafb44a8810af10006dd4a5fcfb07bb810 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 20 Jul 2010 15:21:22 -0700 Subject: [SCSI] Revert "[SCSI] fcoe: Fix using VLAN ID in creating lport's WWWN/WWPN" This reverts commit cc0136c2e9c10e889cb36e39710c0eb10707b396. That commit introduced vlan id info to WWPN but WWPN needs to remain static as an unique port identifier in the fabric, therefore variable fabric vlan id info doesn't need to be coded inside WWPN. After this revert, port arg to fcoe_wwn_from_mac is always zero but still leaving it as-is okay to later allow users to use NAA 2 scheme with this additional port arg. Note with this patch, existing zoning using WWPN would require re-zoning this time only and later no more re-zoning due to any vlan id changes. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index cf9d718c731..ddd2ca27e00 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -647,7 +647,6 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) u64 wwnn, wwpn; struct fcoe_interface *fcoe; struct fcoe_port *port; - int vid = 0; /* Setup lport private data to point to fcoe softc */ port = lport_priv(lport); @@ -677,20 +676,12 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) fcoe_link_speed_update(lport); if (!lport->vport) { - /* - * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN: - * For WWNN, we use NAA 1 w/ bit 27-16 of word 0 as 0. - * For WWPN, we use NAA 2 w/ bit 27-16 of word 0 from VLAN ID - */ - if (netdev->priv_flags & IFF_802_1Q_VLAN) - vid = vlan_dev_vlan_id(netdev); - if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0); fc_set_wwnn(lport, wwnn); if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, - 2, vid); + 2, 0); fc_set_wwpn(lport, wwpn); } -- cgit v1.2.3-70-g09d2 From 7f985231d274ef3e6e4d56a2939a534906299021 Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Gollapudi Date: Tue, 20 Jul 2010 15:21:27 -0700 Subject: [SCSI] libfc: Add retry logic to lport state machine when receiving LS_RJT Call fc_lport_error to retry upto max retry count when FLOGI/SCR/NS gets rejected. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 63 +++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 1998c03634d..6eb334a8a7f 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1012,38 +1012,24 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) PTR_ERR(fp), fc_lport_state(lport), lport->retry_count); - if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { - /* - * Memory allocation failure, or the exchange timed out. - * Retry after delay - */ - if (lport->retry_count < lport->max_retry_count) { - lport->retry_count++; - if (!fp) - delay = msecs_to_jiffies(500); - else - delay = msecs_to_jiffies(lport->e_d_tov); - - schedule_delayed_work(&lport->retry_work, delay); - } else { - switch (lport->state) { - case LPORT_ST_DISABLED: - case LPORT_ST_READY: - case LPORT_ST_RESET: - case LPORT_ST_RNN_ID: - case LPORT_ST_RSNN_NN: - case LPORT_ST_RSPN_ID: - case LPORT_ST_RFT_ID: - case LPORT_ST_RFF_ID: - case LPORT_ST_SCR: - case LPORT_ST_DNS: - case LPORT_ST_FLOGI: - case LPORT_ST_LOGO: - fc_lport_enter_reset(lport); - break; - } - } - } + if (PTR_ERR(fp) == -FC_EX_CLOSED) + return; + + /* + * Memory allocation failure, or the exchange timed out + * or we received LS_RJT. + * Retry after delay + */ + if (lport->retry_count < lport->max_retry_count) { + lport->retry_count++; + if (!fp) + delay = msecs_to_jiffies(500); + else + delay = msecs_to_jiffies(lport->e_d_tov); + + schedule_delayed_work(&lport->retry_work, delay); + } else + fc_lport_enter_reset(lport); } /** @@ -1461,7 +1447,13 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, } did = fc_frame_did(fp); - if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) { + + if (!did) { + FC_LPORT_DBG(lport, "Bad FLOGI response\n"); + goto out; + } + + if (fc_frame_payload_op(fp) == ELS_LS_ACC) { flp = fc_frame_payload_get(fp, sizeof(*flp)); if (flp) { mfs = ntohs(flp->fl_csp.sp_bb_data) & @@ -1500,9 +1492,8 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, fc_lport_enter_dns(lport); } } - } else { - FC_LPORT_DBG(lport, "Bad FLOGI response\n"); - } + } else + fc_lport_error(lport, fp); out: fc_frame_free(fp); -- cgit v1.2.3-70-g09d2 From 240778e821f596a6954116107c5cc3456df84f81 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Tue, 20 Jul 2010 15:21:33 -0700 Subject: [SCSI] fcoe: remove check for zero fabric name This check prevents FCF selection in NPV mode due to zero fabric name in that case and in turn flogi fails. Though NPV mode should not have this zero and should be fixed there also but spec also does not require initiator to ensure that fabric name must be non-zero, therefore dropping this check to get flogi working in NPV mode. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/libfcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c index 2c265fe9ab3..aa503d83092 100644 --- a/drivers/scsi/fcoe/libfcoe.c +++ b/drivers/scsi/fcoe/libfcoe.c @@ -845,7 +845,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, } if (!fcf->fc_map || (fcf->fc_map & 0x10000)) return -EINVAL; - if (!fcf->switch_name || !fcf->fabric_name) + if (!fcf->switch_name) return -EINVAL; if (desc_mask) { LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n", -- cgit v1.2.3-70-g09d2 From caf19d38607108304cd8cc67ed21378017f69e8a Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 22 Jul 2010 09:36:51 +0900 Subject: [SCSI] sg: fix bio leak with a detached device After blk_rq_map_user is successful, if we find that a device is unavailable (was detached), we must call blk_end_request_all to free bio(s) before blk_rq_unmap_user and blk_put_request. Reported-by: "Dailey, Nate" Signed-off-by: FUJITA Tomonori Tested-by: "Dailey, Nate" Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ef752b248c4..d4549092400 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -729,6 +729,8 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; /* probably out of space --> ENOMEM */ } if (sdp->detached) { + if (srp->bio) + blk_end_request_all(srp->rq, -EIO); sg_finish_rem_req(srp); return -ENODEV; } -- cgit v1.2.3-70-g09d2 From fe4f0bdeea788a8ac049c097895cb2e4044f18b1 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Thu, 22 Jul 2010 16:57:43 +0530 Subject: [SCSI] iscsi_transport: Modidify recovery_tmo from sysfs Added support to modify session->recovery_tmo from sysfs Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Acked-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 43 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b9aec304872..d4b96623aa5 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1783,14 +1783,42 @@ show_priv_session_##field(struct device *dev, \ { \ struct iscsi_cls_session *session = \ iscsi_dev_to_session(dev->parent); \ + if (session->field == -1) \ + return sprintf(buf, "off\n"); \ return sprintf(buf, format"\n", session->field); \ } -#define iscsi_priv_session_attr(field, format) \ +#define iscsi_priv_session_attr_store(field) \ +static ssize_t \ +store_priv_session_##field(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + int val; \ + char *cp; \ + struct iscsi_cls_session *session = \ + iscsi_dev_to_session(dev->parent); \ + if ((session->state == ISCSI_SESSION_FREE) || \ + (session->state == ISCSI_SESSION_FAILED)) \ + return -EBUSY; \ + if (strncmp(buf, "off", 3) == 0) \ + session->field = -1; \ + else { \ + val = simple_strtoul(buf, &cp, 0); \ + if (*cp != '\0' && *cp != '\n') \ + return -EINVAL; \ + session->field = val; \ + } \ + return count; \ +} + +#define iscsi_priv_session_rw_attr(field, format) \ iscsi_priv_session_attr_show(field, format) \ -static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ - NULL) -iscsi_priv_session_attr(recovery_tmo, "%d"); + iscsi_priv_session_attr_store(field) \ +static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO, \ + show_priv_session_##field, \ + store_priv_session_##field) +iscsi_priv_session_rw_attr(recovery_tmo, "%d"); /* * iSCSI host attrs @@ -1821,6 +1849,11 @@ do { \ count++; \ } while (0) +#define SETUP_PRIV_SESSION_RW_ATTR(field) \ +do { \ + priv->session_attrs[count] = &dev_attr_priv_sess_##field; \ + count++; \ +} while (0) #define SETUP_SESSION_RD_ATTR(field, param_flag) \ do { \ @@ -2008,7 +2041,7 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME); SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS); - SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); + SETUP_PRIV_SESSION_RW_ATTR(recovery_tmo); SETUP_PRIV_SESSION_RD_ATTR(state); BUG_ON(count > ISCSI_SESSION_ATTRS); -- cgit v1.2.3-70-g09d2 From c01be6dcb2b5cce4feaf48035be6395e5cd7d47c Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 22 Jul 2010 16:59:49 +0530 Subject: [SCSI] iscsi_transport: wait on session in error handler path wait for session to come online in eh_device_reset_handler and eh_target_reset_handler Signed-off-by: Mike Christie Signed-off-by: Vikas Chaudhary Signed-off-by: Ravi Anand Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 11 ++++++++++- drivers/scsi/scsi_transport_iscsi.c | 32 ++++++++++++++++++++++++++++++++ include/scsi/scsi_transport_iscsi.h | 2 ++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 821384147a4..5529b2a3974 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -2020,6 +2020,11 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) if (!ddb_entry) return ret; + ret = iscsi_block_scsi_eh(cmd); + if (ret) + return ret; + ret = FAILED; + ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun); @@ -2072,11 +2077,15 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) { struct scsi_qla_host *ha = to_qla_host(cmd->device->host); struct ddb_entry *ddb_entry = cmd->device->hostdata; - int stat; + int stat, ret; if (!ddb_entry) return FAILED; + ret = iscsi_block_scsi_eh(cmd); + if (ret) + return ret; + starget_printk(KERN_INFO, scsi_target(cmd->device), "WARM TARGET RESET ISSUED.\n"); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index d4b96623aa5..e84026def1f 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,6 +30,7 @@ #include #include #include +#include #define ISCSI_SESSION_ATTRS 23 #define ISCSI_CONN_ATTRS 13 @@ -534,6 +535,37 @@ static void iscsi_scan_session(struct work_struct *work) atomic_dec(&ihost->nr_scans); } +/** + * iscsi_block_scsi_eh - block scsi eh until session state has transistioned + * cmd: scsi cmd passed to scsi eh handler + * + * If the session is down this function will wait for the recovery + * timer to fire or for the session to be logged back in. If the + * recovery timer fires then FAST_IO_FAIL is returned. The caller + * should pass this error value to the scsi eh. + */ +int iscsi_block_scsi_eh(struct scsi_cmnd *cmd) +{ + struct iscsi_cls_session *session = + starget_to_session(scsi_target(cmd->device)); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&session->lock, flags); + while (session->state != ISCSI_SESSION_LOGGED_IN) { + if (session->state == ISCSI_SESSION_FREE) { + ret = FAST_IO_FAIL; + break; + } + spin_unlock_irqrestore(&session->lock, flags); + msleep(1000); + spin_lock_irqsave(&session->lock, flags); + } + spin_unlock_irqrestore(&session->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh); + static void session_recovery_timedout(struct work_struct *work) { struct iscsi_cls_session *session = diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 349c7f30720..7fff94b3b2a 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -32,6 +32,7 @@ struct scsi_transport_template; struct iscsi_transport; struct iscsi_endpoint; struct Scsi_Host; +struct scsi_cmnd; struct iscsi_cls_conn; struct iscsi_conn; struct iscsi_task; @@ -255,5 +256,6 @@ extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); extern struct iscsi_endpoint *iscsi_create_endpoint(int dd_size); extern void iscsi_destroy_endpoint(struct iscsi_endpoint *ep); extern struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle); +extern int iscsi_block_scsi_eh(struct scsi_cmnd *cmd); #endif -- cgit v1.2.3-70-g09d2 From 17cf2c5d76b468ca03e59c7cf60decfcef6c08c4 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 23 Jul 2010 15:28:22 +0500 Subject: [SCSI] qla2xxx: Don't issue set or get port param MBC if invalid port loop id Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 3a024838850..20eaa1c42ae 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1222,6 +1222,13 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job) return -EINVAL; } + if (fcport->loop_id == FC_NO_LOOP_ID) { + DEBUG2(printk(KERN_ERR "%s(%ld): Invalid port loop id, " + "loop_id = 0x%x\n", + __func__, vha->host_no, fcport->loop_id)); + return -EINVAL; + } + if (port_param->mode) rval = qla2x00_set_idma_speed(vha, fcport->loop_id, port_param->speed, mb); -- cgit v1.2.3-70-g09d2 From d94d10e7277069801b4e31b40770314a8421f996 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 23 Jul 2010 15:28:23 +0500 Subject: [SCSI] qla2xxx: Removed dependency for SRB structure for Marker processing Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 11 ---- drivers/scsi/qla2xxx/qla_gbl.h | 4 +- drivers/scsi/qla2xxx/qla_init.c | 73 +--------------------- drivers/scsi/qla2xxx/qla_iocb.c | 134 +++++----------------------------------- drivers/scsi/qla2xxx/qla_isr.c | 37 ----------- 5 files changed, 19 insertions(+), 240 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2bb187e23db..7f9f86b8140 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -250,16 +250,6 @@ struct srb_iocb { uint32_t lun; uint32_t data; } tmf; - struct { - /* - * values for modif field below are as - * defined in mrk_entry_24xx struct - * for the modifier field in qla_fw.h. - */ - uint8_t modif; - uint16_t lun; - uint32_t data; - } marker; } u; struct timer_list timer; @@ -277,7 +267,6 @@ struct srb_iocb { #define SRB_CT_CMD 5 #define SRB_ADISC_CMD 6 #define SRB_TM_CMD 7 -#define SRB_MARKER_CMD 8 struct srb_ctx { uint16_t type; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 7ae2ee42564..fd299911d7d 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -59,7 +59,6 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t); -extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t); extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, @@ -68,8 +67,7 @@ extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *, struct srb_iocb *); -extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *, - struct srb_iocb *); +extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); extern fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d0b993c8a18..5bc31707037 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -367,58 +367,6 @@ done: return rval; } -static void -qla2x00_async_marker_ctx_done(srb_t *sp) -{ - struct srb_ctx *ctx = sp->ctx; - struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd; - - qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb); - iocb->free(sp); -} - -int -qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif) -{ - struct scsi_qla_host *vha = fcport->vha; - srb_t *sp; - struct srb_ctx *ctx; - struct srb_iocb *mrk; - int rval; - - rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0); - if (!sp) - goto done; - - ctx = sp->ctx; - ctx->type = SRB_MARKER_CMD; - ctx->name = "marker"; - mrk = ctx->u.iocb_cmd; - mrk->u.marker.lun = lun; - mrk->u.marker.modif = modif; - mrk->timeout = qla2x00_async_iocb_timeout; - mrk->done = qla2x00_async_marker_ctx_done; - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - DEBUG2(printk(KERN_DEBUG - "scsi(%ld:%x): Async-marker - loop-id=%x " - "portid=%02x%02x%02x.\n", - fcport->vha->host_no, sp->handle, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa)); - - return rval; - -done_free_sp: - mrk->free(sp); -done: - return rval; -} - void qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) @@ -500,7 +448,8 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport, lun = (uint16_t)iocb->u.tmf.lun; /* Issue Marker IOCB */ - rval = qla2x00_async_marker(fcport, lun, + rval = qla2x00_marker(vha, vha->hw->req_q_map[0], + vha->hw->rsp_q_map[0], fcport->loop_id, lun, flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) { @@ -512,24 +461,6 @@ qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport, return; } -void -qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport, - struct srb_iocb *iocb) -{ - /* - * Currently we dont have any specific post response processing - * for this IOCB. We'll just return success or failed - * depending on whether the IOCB command succeeded or failed. - */ - if (iocb->u.tmf.data) { - DEBUG2_3_11(printk(KERN_WARNING - "%s(%ld): Marker IOCB failed (%x).\n", - __func__, vha->host_no, iocb->u.tmf.data)); - } - - return; -} - /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 5d0e99c2b52..370646f7b3f 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -11,8 +11,6 @@ #include -static request_t *qla2x00_req_pkt(struct scsi_qla_host *, struct req_que *, - struct rsp_que *rsp); static void qla2x00_isp_cmd(struct scsi_qla_host *, struct req_que *); static void qla25xx_set_que(srb_t *, struct rsp_que **); @@ -474,7 +472,7 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); mrk24 = NULL; - mrk = (mrk_entry_t *)qla2x00_req_pkt(vha, req, rsp); + mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0); if (mrk == NULL) { DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n", __func__, base_vha->host_no)); @@ -520,84 +518,6 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, return (ret); } -/** - * qla2x00_req_pkt() - Retrieve a request packet from the request ring. - * @ha: HA context - * - * Note: The caller must hold the hardware lock before calling this routine. - * - * Returns NULL if function failed, else, a pointer to the request packet. - */ -static request_t * -qla2x00_req_pkt(struct scsi_qla_host *vha, struct req_que *req, - struct rsp_que *rsp) -{ - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); - request_t *pkt = NULL; - uint16_t cnt; - uint32_t *dword_ptr; - uint32_t timer; - uint16_t req_cnt = 1; - - /* Wait 1 second for slot. */ - for (timer = HZ; timer; timer--) { - if ((req_cnt + 2) >= req->cnt) { - /* Calculate number of free request entries. */ - if (ha->mqenable) - cnt = (uint16_t) - RD_REG_DWORD(®->isp25mq.req_q_out); - else { - if (IS_QLA82XX(ha)) - cnt = (uint16_t)RD_REG_DWORD( - ®->isp82.req_q_out); - else if (IS_FWI2_CAPABLE(ha)) - cnt = (uint16_t)RD_REG_DWORD( - ®->isp24.req_q_out); - else - cnt = qla2x00_debounce_register( - ISP_REQ_Q_OUT(ha, ®->isp)); - } - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - /* If room for request in request ring. */ - if ((req_cnt + 2) < req->cnt) { - req->cnt--; - pkt = req->ring_ptr; - - /* Zero out packet. */ - dword_ptr = (uint32_t *)pkt; - for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++) - *dword_ptr++ = 0; - - /* Set entry count. */ - pkt->entry_count = 1; - - break; - } - - /* Release ring specific lock */ - spin_unlock_irq(&ha->hardware_lock); - - udelay(2); /* 2 us */ - - /* Check for pending interrupts. */ - /* During init we issue marker directly */ - if (!vha->marker_needed && !vha->flags.init_done) - qla2x00_poll(rsp); - spin_lock_irq(&ha->hardware_lock); - } - if (!pkt) { - DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__)); - } - - return (pkt); -} - /** * qla2x00_isp_cmd() - Modify the request ring pointer. * @ha: HA context @@ -1559,11 +1479,9 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) } /* Generic Control-SRB manipulation functions. */ - -static void * -qla2x00_alloc_iocbs(srb_t *sp) +void * +qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) { - scsi_qla_host_t *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); @@ -1573,6 +1491,10 @@ qla2x00_alloc_iocbs(srb_t *sp) pkt = NULL; req_cnt = 1; + handle = 0; + + if (!sp) + goto skip_cmd_array; /* Check for room in outstanding command list. */ handle = req->current_outstanding_cmd; @@ -1586,10 +1508,18 @@ qla2x00_alloc_iocbs(srb_t *sp) if (index == MAX_OUTSTANDING_COMMANDS) goto queuing_error; + /* Prep command array. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + +skip_cmd_array: /* Check for room on request queue. */ if (req->cnt < req_cnt) { if (ha->mqenable) cnt = RD_REG_DWORD(®->isp25mq.req_q_out); + else if (IS_QLA82XX(ha)) + cnt = RD_REG_DWORD(®->isp82.req_q_out); else if (IS_FWI2_CAPABLE(ha)) cnt = RD_REG_DWORD(®->isp24.req_q_out); else @@ -1606,15 +1536,11 @@ qla2x00_alloc_iocbs(srb_t *sp) goto queuing_error; /* Prep packet */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; req->cnt -= req_cnt; - pkt = req->ring_ptr; memset(pkt, 0, REQUEST_ENTRY_SIZE); pkt->entry_count = req_cnt; pkt->handle = handle; - sp->handle = handle; queuing_error: return pkt; @@ -1794,31 +1720,6 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) } } -static void -qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk) -{ - uint16_t lun; - uint8_t modif; - struct fc_port *fcport = sp->fcport; - scsi_qla_host_t *vha = fcport->vha; - struct srb_ctx *ctx = sp->ctx; - struct srb_iocb *iocb = ctx->u.iocb_cmd; - struct req_que *req = vha->req; - - lun = iocb->u.marker.lun; - modif = iocb->u.marker.modif; - mrk->entry_type = MARKER_TYPE; - mrk->modifier = modif; - if (modif != MK_SYNC_ALL) { - mrk->nport_handle = cpu_to_le16(fcport->loop_id); - mrk->lun[1] = LSB(lun); - mrk->lun[2] = MSB(lun); - host_to_fcp_swap(mrk->lun, sizeof(mrk->lun)); - mrk->vp_index = vha->vp_idx; - mrk->handle = MAKE_HANDLE(req->id, mrk->handle); - } -} - static void qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { @@ -1945,7 +1846,7 @@ qla2x00_start_sp(srb_t *sp) rval = QLA_FUNCTION_FAILED; spin_lock_irqsave(&ha->hardware_lock, flags); - pkt = qla2x00_alloc_iocbs(sp); + pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp); if (!pkt) goto done; @@ -1976,9 +1877,6 @@ qla2x00_start_sp(srb_t *sp) case SRB_TM_CMD: qla24xx_tm_iocb(sp, pkt); break; - case SRB_MARKER_CMD: - qla24xx_marker_iocb(sp, pkt); - break; default: break; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 8a608725eb7..ba971ac1c4e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1238,39 +1238,6 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, iocb->done(sp); } -static void -qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, - struct mrk_entry_24xx *mrk) -{ - const char func[] = "MRK-IOCB"; - const char *type; - fc_port_t *fcport; - srb_t *sp; - struct srb_iocb *iocb; - struct srb_ctx *ctx; - struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk; - - sp = qla2x00_get_sp_from_handle(vha, func, req, mrk); - if (!sp) - return; - - ctx = sp->ctx; - iocb = ctx->u.iocb_cmd; - type = ctx->name; - fcport = sp->fcport; - - if (sts->entry_status) { - iocb->u.marker.data = 1; - DEBUG2(printk(KERN_WARNING - "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n", - fcport->vha->host_no, sp->handle, type, - sts->entry_status)); - DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts))); - } - - iocb->done(sp); -} - /** * qla2x00_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context @@ -1942,10 +1909,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_tm_iocb_entry(vha, rsp->req, (struct tsk_mgmt_entry *)pkt); break; - case MARKER_TYPE: - qla24xx_marker_iocb_entry(vha, rsp->req, - (struct mrk_entry_24xx *)pkt); - break; case CT_IOCB_TYPE: qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); -- cgit v1.2.3-70-g09d2 From 2f0f3f4f06f7cfadebf58b70bd9e7f71d8fd96e4 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 23 Jul 2010 15:28:24 +0500 Subject: [SCSI] qla2xxx: Appropriately log FCP priority data messages Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 36 +++++++++++++++++++++++++++++++++--- drivers/scsi/qla2xxx/qla_init.c | 7 ++----- drivers/scsi/qla2xxx/qla_sup.c | 25 +++++++++++++------------ 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 20eaa1c42ae..d551ae19d4e 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -41,13 +41,28 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) int i, ret, num_valid; uint8_t *bcode; struct qla_fcp_prio_entry *pri_entry; + uint32_t *bcode_val_ptr, bcode_val; ret = 1; num_valid = 0; bcode = (uint8_t *)pri_cfg; + bcode_val_ptr = (uint32_t *)pri_cfg; + bcode_val = (uint32_t)(*bcode_val_ptr); - if (bcode[0x0] != 'H' || bcode[0x1] != 'Q' || bcode[0x2] != 'O' || - bcode[0x3] != 'S') { + if (bcode_val == 0xFFFFFFFF) { + /* No FCP Priority config data in flash */ + DEBUG2(printk(KERN_INFO + "%s: No FCP priority config data.\n", + __func__)); + return 0; + } + + if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' || + bcode[3] != 'S') { + /* Invalid FCP priority data header*/ + DEBUG2(printk(KERN_ERR + "%s: Invalid FCP Priority data header. bcode=0x%x\n", + __func__, bcode_val)); return 0; } if (flag != 1) @@ -60,8 +75,18 @@ qla24xx_fcp_prio_cfg_valid(struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) pri_entry++; } - if (num_valid == 0) + if (num_valid == 0) { + /* No valid FCP priority data entries */ + DEBUG2(printk(KERN_ERR + "%s: No valid FCP Priority data entries.\n", + __func__)); ret = 0; + } else { + /* FCP priority data is valid */ + DEBUG2(printk(KERN_INFO + "%s: Valid FCP priority data. num entries = %d\n", + __func__, num_valid)); + } return ret; } @@ -78,6 +103,11 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job) bsg_job->reply->reply_payload_rcv_len = 0; + if (!IS_QLA24XX_TYPE(ha) || !IS_QLA25XX(ha)) { + ret = -EINVAL; + goto exit_fcp_prio_cfg; + } + if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) || test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5bc31707037..cea491bf0fc 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -566,11 +566,8 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) } } - if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) { - if (qla24xx_read_fcp_prio_cfg(vha)) - qla_printk(KERN_ERR, ha, - "Unable to read FCP priority data.\n"); - } + if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) + qla24xx_read_fcp_prio_cfg(vha); return (rval); } diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index de92504d758..3c5115f6073 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -664,6 +664,11 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + def = 0; + if (IS_QLA25XX(ha)) + def = 1; + else if (IS_QLA81XX(ha)) + def = 2; ha->flt_region_flt = flt_addr; wptr = (uint16_t *)req->ring; flt = (struct qla_flt_header *)req->ring; @@ -691,6 +696,10 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) goto no_flash_data; } + /* Assign FCP prio region since older FLT's may not have it */ + ha->flt_region_fcp_prio = ha->flags.port0 ? + fcp_prio_cfg0[def] : fcp_prio_cfg1[def]; + loc = locations[1]; cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); for ( ; cnt; cnt--, region++) { @@ -773,13 +782,6 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) no_flash_data: /* Use hardcoded defaults. */ loc = locations[0]; - def = 0; - if (IS_QLA24XX_TYPE(ha)) - def = 0; - else if (IS_QLA25XX(ha)) - def = 1; - else if (IS_QLA81XX(ha)) - def = 2; ha->flt_region_fw = def_fw[def]; ha->flt_region_boot = def_boot[def]; ha->flt_region_vpd_nvram = def_vpd_nvram[def]; @@ -790,14 +792,13 @@ no_flash_data: ha->flt_region_fdt = def_fdt[def]; ha->flt_region_npiv_conf = ha->flags.port0 ? def_npiv_conf0[def] : def_npiv_conf1[def]; - ha->flt_region_fcp_prio = ha->flags.port0 ? - fcp_prio_cfg0[def] : fcp_prio_cfg1[def]; done: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " "vpd_nvram=0x%x vpd=0x%x nvram=0x%x fdt=0x%x flt=0x%x " - "npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw, - ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram, - ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf)); + "npiv=0x%x. fcp_prio_cfg=0x%x\n", loc, ha->flt_region_boot, + ha->flt_region_fw, ha->flt_region_vpd_nvram, ha->flt_region_vpd, + ha->flt_region_nvram, ha->flt_region_fdt, ha->flt_region_flt, + ha->flt_region_npiv_conf, ha->flt_region_fcp_prio)); } static void -- cgit v1.2.3-70-g09d2 From e8c72ba51a159f5d1cb195d3fb47262c782939d9 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Fri, 23 Jul 2010 15:28:25 +0500 Subject: [SCSI] qla2xxx: Use GFF_ID to check FCP-SCSI FC4 type before logging into Nx_Ports The default method that qla2xxx uses is the GID_PT nameserver command to get a list of Nx_Ports. This patch adds a GFF_ID call for each port returned by GID_PT to get the FC4 type. If the FC4 type is not FCP SCSI then the qla2xxx driver will not record that port in it's port database. For switches that do not support the GFF_ID command, the behavior will be for qla2xxx to store that port anyways. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 20 ++++++++++++ drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_gs.c | 72 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_init.c | 11 ++++++- 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7f9f86b8140..02c7480c99c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1652,8 +1652,14 @@ typedef struct { uint8_t port_name[WWN_SIZE]; uint8_t fabric_port_name[WWN_SIZE]; uint16_t fp_speed; + uint8_t fc4_type; } sw_info_t; +/* FCP-4 types */ +#define FC4_TYPE_FCP_SCSI 0x08 +#define FC4_TYPE_OTHER 0x0 +#define FC4_TYPE_UNKNOWN 0xff + /* * Fibre channel port type. */ @@ -1697,6 +1703,7 @@ typedef struct fc_port { u32 supported_classes; uint16_t vp_idx; + uint8_t fc4_type; } fc_port_t; /* @@ -1779,6 +1786,9 @@ typedef struct fc_port { #define GPSC_REQ_SIZE (16 + 8) #define GPSC_RSP_SIZE (16 + 2 + 2) +#define GFF_ID_CMD 0x011F +#define GFF_ID_REQ_SIZE (16 + 4) +#define GFF_ID_RSP_SIZE (16 + 128) /* * HBA attribute types. @@ -1980,6 +1990,11 @@ struct ct_sns_req { struct { uint8_t port_name[8]; } gpsc; + + struct { + uint8_t reserved; + uint8_t port_name[3]; + } gff_id; } req; }; @@ -2052,6 +2067,11 @@ struct ct_sns_rsp { uint16_t speeds; uint16_t speed; } gpsc; + +#define GFF_FCP_SCSI_OFFSET 7 + struct { + uint8_t fc4_features[128]; + } gff_id; } rsp; }; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index fd299911d7d..55f4599ade6 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -441,6 +441,7 @@ extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *); extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *); +extern void qla2x00_gff_id(scsi_qla_host_t *, sw_info_t *); extern int qla2x00_rft_id(scsi_qla_host_t *); extern int qla2x00_rff_id(scsi_qla_host_t *); extern int qla2x00_rnn_id(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 872c55f049a..2fabae8daec 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1913,3 +1913,75 @@ qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) return (rval); } + +/** + * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. + * + * @ha: HA context + * @list: switch info entries to populate + * + */ +void +qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) +{ + int rval; + uint16_t i; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + struct qla_hw_data *ha = vha->hw; + uint8_t fcp_scsi_features = 0; + + for (i = 0; i < MAX_FIBRE_DEVICES; i++) { + /* Set default FC4 Type as UNKNOWN so the default is to + * Process this port */ + list[i].fc4_type = FC4_TYPE_UNKNOWN; + + /* Do not attempt GFF_ID if we are not FWI_2 capable */ + if (!IS_FWI2_CAPABLE(ha)) + continue; + + /* Prepare common MS IOCB */ + ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFF_ID_REQ_SIZE, + GFF_ID_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD, + GFF_ID_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare CT arguments -- port_id */ + ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; + ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; + ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + + if (rval != QLA_SUCCESS) { + DEBUG2_3(printk(KERN_INFO + "scsi(%ld): GFF_ID issue IOCB failed " + "(%d).\n", vha->host_no, rval)); + } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, + "GPN_ID") != QLA_SUCCESS) { + DEBUG2_3(printk(KERN_INFO + "scsi(%ld): GFF_ID IOCB status had a " + "failure status code\n", vha->host_no)); + } else { + fcp_scsi_features = + ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; + fcp_scsi_features &= 0x0f; + + if (fcp_scsi_features) + list[i].fc4_type = FC4_TYPE_FCP_SCSI; + else + list[i].fc4_type = FC4_TYPE_OTHER; + } + + /* Last device exit. */ + if (list[i].d_id.b.rsvd_1 != 0) + break; + } +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cea491bf0fc..685c350007b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3078,7 +3078,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha) return (rval); } - /* * qla2x00_find_all_fabric_devs * @@ -3131,6 +3130,10 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) { qla2x00_gpsc(vha, swl); } + + /* If other queries succeeded probe for FC-4 type */ + if (swl) + qla2x00_gff_id(vha, swl); } swl_idx = 0; @@ -3172,6 +3175,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, memcpy(new_fcport->fabric_port_name, swl[swl_idx].fabric_port_name, WWN_SIZE); new_fcport->fp_speed = swl[swl_idx].fp_speed; + new_fcport->fc4_type = swl[swl_idx].fc4_type; if (swl[swl_idx].d_id.b.rsvd_1 != 0) { last_dev = 1; @@ -3233,6 +3237,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) continue; + /* Bypass ports whose FCP-4 type is not FCP_SCSI */ + if (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI && + new_fcport->fc4_type != FC4_TYPE_UNKNOWN) + continue; + /* Locate matching device in database. */ found = 0; list_for_each_entry(fcport, &vha->vp_fcports, list) { -- cgit v1.2.3-70-g09d2 From 0f2d962f4d120e93b4d74d13c2e8038e9e4358b9 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 23 Jul 2010 15:28:26 +0500 Subject: [SCSI] qla2xxx: Check for golden firmware and show version if available Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 18 ++++++++++++++++++ drivers/scsi/qla2xxx/qla_def.h | 2 ++ drivers/scsi/qla2xxx/qla_sup.c | 22 ++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index fd6f7b10054..7ebf365043c 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1186,6 +1186,21 @@ qla2x00_optrom_fw_version_show(struct device *dev, ha->fw_revision[3]); } +static ssize_t +qla2x00_optrom_gold_fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha)) + return snprintf(buf, PAGE_SIZE, "\n"); + + return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n", + ha->gold_fw_version[0], ha->gold_fw_version[1], + ha->gold_fw_version[2], ha->gold_fw_version[3]); +} + static ssize_t qla2x00_total_isp_aborts_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1336,6 +1351,8 @@ static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, qla2x00_optrom_fcode_version_show, NULL); static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, NULL); +static DEVICE_ATTR(optrom_gold_fw_version, S_IRUGO, + qla2x00_optrom_gold_fw_version_show, NULL); static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, NULL); static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, @@ -1376,6 +1393,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_vn_port_mac_address, &dev_attr_fabric_param, &dev_attr_fw_state, + &dev_attr_optrom_gold_fw_version, NULL, }; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 02c7480c99c..7e11ccf0fe8 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2714,6 +2714,8 @@ struct qla_hw_data { uint8_t fcode_revision[16]; uint32_t fw_revision[4]; + uint32_t gold_fw_version[4]; + /* Offsets for flash/nvram access (set to ~0 if not used). */ uint32_t flash_conf_off; uint32_t flash_data_off; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 3c5115f6073..df288dc829e 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -2759,6 +2759,28 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) ha->fw_revision[3] = dcode[3]; } + /* Check for golden firmware and get version if available */ + if (!IS_QLA81XX(ha)) { + /* Golden firmware is not present in non 81XX adapters */ + return ret; + } + + memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version)); + dcode = mbuf; + ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, + ha->flt_region_gold_fw << 2, 32); + + if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF && + dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) { + DEBUG2(qla_printk(KERN_INFO, ha, + "%s(%ld): Unrecognized golden fw at 0x%x.\n", + __func__, vha->host_no, ha->flt_region_gold_fw * 4)); + return ret; + } + + for (i = 4; i < 8; i++) + ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]); + return ret; } -- cgit v1.2.3-70-g09d2 From 5544213be7b4fb693730106a6d70a8cc1aa7cdf6 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jul 2010 15:28:27 +0500 Subject: [SCSI] qla2xxx: Correct extended sense-data handling. Earlier implementation did not take into account the varying sizes of data buffers returned from structures sts_entry_t and sts_entry_24xx. Sense-data after the 20th byte could be incorrect. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ba971ac1c4e..88b5774085a 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1320,8 +1320,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp) } static inline void -qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len, - struct rsp_que *rsp) + +qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, + uint32_t sense_len, struct rsp_que *rsp) { struct scsi_cmnd *cp = sp->cmd; @@ -1330,8 +1331,8 @@ qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len, sp->request_sense_length = sense_len; sp->request_sense_ptr = cp->sense_buffer; - if (sp->request_sense_length > 32) - sense_len = 32; + if (sp->request_sense_length > par_sense_len) + sense_len = par_sense_len; memcpy(cp->sense_buffer, sense_data, sense_len); @@ -1438,7 +1439,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) uint16_t ox_id; uint8_t lscsi_status; int32_t resid; - uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len; + uint32_t sense_len, par_sense_len, rsp_info_len, resid_len, + fw_resid_len; uint8_t *rsp_info, *sense_data; struct qla_hw_data *ha = vha->hw; uint32_t handle; @@ -1496,7 +1498,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) fcport = sp->fcport; ox_id = 0; - sense_len = rsp_info_len = resid_len = fw_resid_len = 0; + sense_len = par_sense_len = rsp_info_len = resid_len = + fw_resid_len = 0; if (IS_FWI2_CAPABLE(ha)) { if (scsi_status & SS_SENSE_LEN_VALID) sense_len = le32_to_cpu(sts24->sense_len); @@ -1510,6 +1513,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) sense_data = sts24->data; host_to_fcp_swap(sts24->data, sizeof(sts24->data)); ox_id = le16_to_cpu(sts24->ox_id); + par_sense_len = sizeof(sts24->data); } else { if (scsi_status & SS_SENSE_LEN_VALID) sense_len = le16_to_cpu(sts->req_sense_length); @@ -1518,13 +1522,16 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) resid_len = le32_to_cpu(sts->residual_length); rsp_info = sts->rsp_info; sense_data = sts->req_sense_data; + par_sense_len = sizeof(sts->req_sense_data); } /* Check for any FCP transport errors. */ if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) { /* Sense data lies beyond any FCP RESPONSE data. */ - if (IS_FWI2_CAPABLE(ha)) + if (IS_FWI2_CAPABLE(ha)) { sense_data += rsp_info_len; + par_sense_len -= rsp_info_len; + } if (rsp_info_len > 3 && rsp_info[3]) { DEBUG2(qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): FCP I/O protocol failure " @@ -1584,7 +1591,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - qla2x00_handle_sense(sp, sense_data, sense_len, rsp); + qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len, + rsp); break; case CS_DATA_UNDERRUN: @@ -1648,7 +1656,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - qla2x00_handle_sense(sp, sense_data, sense_len, rsp); + qla2x00_handle_sense(sp, sense_data, par_sense_len, + sense_len, rsp); } break; -- cgit v1.2.3-70-g09d2 From 03c3f563c55121292022a6e8e213ea54c20a5980 Mon Sep 17 00:00:00 2001 From: Duane Grigsby Date: Fri, 23 Jul 2010 15:28:28 +0500 Subject: [SCSI] qla2xxx: Propogate transport disrupted status for cable pull conditions for faster failover. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 88b5774085a..ffc855f7697 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1692,6 +1692,9 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) break; case CS_RESET: + cp->result = DID_TRANSPORT_DISRUPTED << 16; + break; + case CS_ABORTED: cp->result = DID_RESET << 16; break; -- cgit v1.2.3-70-g09d2 From 14e303d98bcfe4a6075407b531b1df2f237deb28 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jul 2010 15:28:29 +0500 Subject: [SCSI] qla2xxx: Stop firmware before doing init firmware. If BIOS is enabled then drivers init firmware fails since BIOS has done the init once. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 685c350007b..f6b1052a383 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1402,9 +1402,10 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) if (IS_QLA82XX(ha)) { rval = ha->isp_ops->load_risc(vha, &srisc_address); - if (rval == QLA_SUCCESS) + if (rval == QLA_SUCCESS) { + qla2x00_stop_firmware(vha); goto enable_82xx_npiv; - else + } else goto failed; } -- cgit v1.2.3-70-g09d2 From 8867048b486a64125b62f93af13a379d6d575ee2 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Fri, 23 Jul 2010 15:28:30 +0500 Subject: [SCSI] qla2xxx: Add qla2x00_free_fcports() function This function was added to encapsulate freeing the memory for all the fcports associated with a particular vha. Also added a call to qla2x00_free_fcports() to qla2x00_free_device() to free the memory for all the fcports associated with a vha during device removal. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 7 +------ drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_os.c | 13 +++++++++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 7ebf365043c..93a4c20e211 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1827,7 +1827,6 @@ static int qla24xx_vport_delete(struct fc_vport *fc_vport) { scsi_qla_host_t *vha = fc_vport->dd_data; - fc_port_t *fcport, *tfcport; struct qla_hw_data *ha = vha->hw; uint16_t id = vha->vp_idx; @@ -1841,11 +1840,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) scsi_remove_host(vha->host); - list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) { - list_del(&fcport->list); - kfree(fcport); - fcport = NULL; - } + qla2x00_free_fcports(vha); qla24xx_deallocate_vp_id(vha); diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 55f4599ade6..84441e8e267 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -122,6 +122,7 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, extern void qla2x00_free_host(struct scsi_qla_host *); extern void qla2x00_relogin(struct scsi_qla_host *); extern void qla2x00_do_work(struct scsi_qla_host *); +extern void qla2x00_free_fcports(struct scsi_qla_host *); /* * Global Functions in qla_mid.c source file. diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5be8db74896..fcdbf7a0be5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2487,11 +2487,24 @@ qla2x00_free_device(scsi_qla_host_t *vha) qla2x00_free_irqs(vha); + qla2x00_free_fcports(vha); + qla2x00_mem_free(ha); qla2x00_free_queues(ha); } +void qla2x00_free_fcports(struct scsi_qla_host *vha) +{ + fc_port_t *fcport, *tfcport; + + list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) { + list_del(&fcport->list); + kfree(fcport); + fcport = NULL; + } +} + static inline void qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, int defer) -- cgit v1.2.3-70-g09d2 From 9a15eb4b514c526cf3181ce224967ab5d8dafe77 Mon Sep 17 00:00:00 2001 From: Madhuranath Iyengar Date: Fri, 23 Jul 2010 15:28:31 +0500 Subject: [SCSI] qla2xxx: Don't issue set or get port param MBC if remote port is not logged in Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index d551ae19d4e..518fccfbfdb 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1259,6 +1259,13 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job) return -EINVAL; } + if (fcport->flags & FCF_LOGIN_NEEDED) { + DEBUG2(printk(KERN_ERR "%s(%ld): Remote port not logged in, " + "flags = 0x%x\n", + __func__, vha->host_no, fcport->flags)); + return -EINVAL; + } + if (port_param->mode) rval = qla2x00_set_idma_speed(vha, fcport->loop_id, port_param->speed, mb); -- cgit v1.2.3-70-g09d2 From 9bc4f4fb44d22e5edc9369c87585a3b492073b8b Mon Sep 17 00:00:00 2001 From: Harish Zunjarrao Date: Fri, 23 Jul 2010 15:28:32 +0500 Subject: [SCSI] qla2xxx: Add CT passthru support for ISP23xx adapters Signed-off-by: Harish Zunjarrao Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 9 ----- drivers/scsi/qla2xxx/qla_iocb.c | 80 ++++++++++++++++++++++++++++++++++++++- drivers/scsi/qla2xxx/qla_isr.c | 83 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 518fccfbfdb..04ead0620d5 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -396,15 +396,6 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job) char *type = "FC_BSG_HST_CT"; struct srb_ctx *ct; - /* pass through is supported only for ISP 4Gb or higher */ - if (!IS_FWI2_CAPABLE(ha)) { - DEBUG2(qla_printk(KERN_INFO, ha, - "scsi(%ld):Firmware is not capable to support FC " - "CT pass thru\n", vha->host_no)); - rval = -EPERM; - goto done; - } - req_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 370646f7b3f..e27d94713bd 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1764,6 +1764,82 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) (bsg_job->reply_payload.sg_list)); } +static void +qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) +{ + uint16_t avail_dsds; + uint32_t *cur_dsd; + struct scatterlist *sg; + int index; + uint16_t tot_dsds; + scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; + int loop_iterartion = 0; + int cont_iocb_prsnt = 0; + int entry_count = 1; + + memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); + ct_iocb->entry_type = CT_IOCB_TYPE; + ct_iocb->entry_status = 0; + ct_iocb->handle1 = sp->handle; + SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id); + ct_iocb->status = __constant_cpu_to_le16(0); + ct_iocb->control_flags = __constant_cpu_to_le16(0); + ct_iocb->timeout = 0; + ct_iocb->cmd_dsd_count = + __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + ct_iocb->total_dsd_count = + __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); + ct_iocb->req_bytecount = + cpu_to_le32(bsg_job->request_payload.payload_len); + ct_iocb->rsp_bytecount = + cpu_to_le32(bsg_job->reply_payload.payload_len); + + ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->request_payload.sg_list))); + ct_iocb->dseg_req_length = ct_iocb->req_bytecount; + + ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address + (bsg_job->reply_payload.sg_list))); + ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount; + + avail_dsds = 1; + cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address; + index = 0; + tot_dsds = bsg_job->reply_payload.sg_cnt; + + for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { + dma_addr_t sle_dma; + cont_a64_entry_t *cont_pkt; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + /* + * Five DSDs are available in the Cont. + * Type 1 IOCB. + */ + cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; + avail_dsds = 5; + cont_iocb_prsnt = 1; + entry_count++; + } + + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + loop_iterartion++; + avail_dsds--; + } + ct_iocb->entry_count = entry_count; +} + static void qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) { @@ -1867,7 +1943,9 @@ qla2x00_start_sp(srb_t *sp) qla24xx_els_iocb(sp, pkt); break; case SRB_CT_CMD: - qla24xx_ct_iocb(sp, pkt); + IS_FWI2_CAPABLE(ha) ? + qla24xx_ct_iocb(sp, pkt) : + qla2x00_ct_iocb(sp, pkt); break; case SRB_ADISC_CMD: IS_FWI2_CAPABLE(ha) ? diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ffc855f7697..51800332822 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -983,6 +983,86 @@ logio_done: lio->done(sp); } +static void +qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, + sts_entry_t *pkt, int iocb_type) +{ + const char func[] = "CT_IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_ctx *sp_bsg; + struct fc_bsg_job *bsg_job; + uint16_t comp_status; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + + sp_bsg = sp->ctx; + bsg_job = sp_bsg->u.bsg_job; + + type = NULL; + switch (sp_bsg->type) { + case SRB_CT_CMD: + type = "ct pass-through"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + sp_bsg->type); + return; + } + + comp_status = le16_to_cpu(pkt->comp_status); + + /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT + * fc payload to the caller + */ + bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + + if (comp_status != CS_COMPLETE) { + if (comp_status == CS_DATA_UNDERRUN) { + bsg_job->reply->result = DID_OK << 16; + bsg_job->reply->reply_payload_rcv_len = + le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len); + + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): CT pass-through-%s error " + "comp_status-status=0x%x total_byte = 0x%x.\n", + vha->host_no, type, comp_status, + bsg_job->reply->reply_payload_rcv_len)); + } else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld): CT pass-through-%s error " + "comp_status-status=0x%x.\n", + vha->host_no, type, comp_status)); + bsg_job->reply->result = DID_ERROR << 16; + bsg_job->reply->reply_payload_rcv_len = 0; + } + DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt))); + } else { + bsg_job->reply->result = DID_OK << 16;; + bsg_job->reply->reply_payload_rcv_len = + bsg_job->reply_payload.payload_len; + bsg_job->reply_len = 0; + } + + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + + if (sp_bsg->type == SRB_ELS_CMD_HST || sp_bsg->type == SRB_CT_CMD) + kfree(sp->fcport); + + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + bsg_job->job_done(bsg_job); +} + static void qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, struct sts_entry_24xx *pkt, int iocb_type) @@ -1303,6 +1383,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp) qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt); break; + case CT_IOCB_TYPE: + qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING -- cgit v1.2.3-70-g09d2 From 08f71e090d3f0d8136c3f350e5082f9217fb7d5b Mon Sep 17 00:00:00 2001 From: Harish Zunjarrao Date: Fri, 23 Jul 2010 15:28:33 +0500 Subject: [SCSI] qla2xxx: Do not allow ELS Passthru commands for ISP23xx adapters Signed-off-by: Harish Zunjarrao Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 04ead0620d5..6b863f789c4 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -229,7 +229,7 @@ static int qla2x00_process_els(struct fc_bsg_job *bsg_job) { struct fc_rport *rport; - fc_port_t *fcport; + fc_port_t *fcport = NULL; struct Scsi_Host *host; scsi_qla_host_t *vha; struct qla_hw_data *ha; @@ -240,6 +240,29 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) uint16_t nextlid = 0; struct srb_ctx *els; + if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { + rport = bsg_job->rport; + fcport = *(fc_port_t **) rport->dd_data; + host = rport_to_shost(rport); + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_RPT_ELS"; + } else { + host = bsg_job->shost; + vha = shost_priv(host); + ha = vha->hw; + type = "FC_BSG_HST_ELS_NOLOGIN"; + } + + /* pass through is supported only for ISP 4Gb or higher */ + if (!IS_FWI2_CAPABLE(ha)) { + DEBUG2(qla_printk(KERN_INFO, ha, + "scsi(%ld):ELS passthru not supported for ISP23xx based " + "adapters\n", vha->host_no)); + rval = -EPERM; + goto done; + } + /* Multiple SG's are not supported for ELS requests */ if (bsg_job->request_payload.sg_cnt > 1 || bsg_job->reply_payload.sg_cnt > 1) { @@ -254,13 +277,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) /* ELS request for rport */ if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { - rport = bsg_job->rport; - fcport = *(fc_port_t **) rport->dd_data; - host = rport_to_shost(rport); - vha = shost_priv(host); - ha = vha->hw; - type = "FC_BSG_RPT_ELS"; - /* make sure the rport is logged in, * if not perform fabric login */ @@ -272,11 +288,6 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job) goto done; } } else { - host = bsg_job->shost; - vha = shost_priv(host); - ha = vha->hw; - type = "FC_BSG_HST_ELS_NOLOGIN"; - /* Allocate a dummy fcport structure, since functions * preparing the IOCB and mailbox command retrieves port * specific information from fcport structure. For Host based -- cgit v1.2.3-70-g09d2 From 3711333dfbeec1905c2d3521d1ed2ddcdbdbac04 Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 23 Jul 2010 15:28:34 +0500 Subject: [SCSI] qla2xxx: Updates for ISP82xx. Re-organized and cleaned up the ISP82xx specific code. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 4 - drivers/scsi/qla2xxx/qla_mbx.c | 4 +- drivers/scsi/qla2xxx/qla_nx.c | 320 +++++------------------------------------ drivers/scsi/qla2xxx/qla_nx.h | 3 +- 4 files changed, 42 insertions(+), 289 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 84441e8e267..8b0a8ca9508 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -508,16 +508,12 @@ extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); extern int qla82xx_pci_mem_write_2M(struct qla_hw_data *, u64, void *, int); extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *); extern int qla82xx_pci_region_offset(struct pci_dev *, int); -extern int qla82xx_pci_region_len(struct pci_dev *, int); extern int qla82xx_iospace_config(struct qla_hw_data *); /* Initialization related functions */ extern void qla82xx_reset_chip(struct scsi_qla_host *); extern void qla82xx_config_rings(struct scsi_qla_host *); -extern int qla82xx_nvram_config(struct scsi_qla_host *); extern int qla82xx_pinit_from_rom(scsi_qla_host_t *); -extern int qla82xx_load_firmware(scsi_qla_host_t *); -extern int qla82xx_reset_hw(scsi_qla_host_t *); extern void qla82xx_watchdog(scsi_qla_host_t *); /* Firmware and flash related functions */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 2f39e309393..02a4d355db3 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -4111,7 +4111,7 @@ qla82xx_mbx_intr_enable(scsi_qla_host_t *vha) "%s(%ld): entered.\n", __func__, vha->host_no)); memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_TOGGLE_INTR; + mcp->mb[0] = MBC_TOGGLE_INTERRUPT; mcp->mb[1] = 1; mcp->out_mb = MBX_1|MBX_0; @@ -4147,7 +4147,7 @@ qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) "%s(%ld): entered.\n", __func__, vha->host_no)); memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_TOGGLE_INTR; + mcp->mb[0] = MBC_TOGGLE_INTERRUPT; mcp->mb[1] = 0; mcp->out_mb = MBX_1|MBX_0; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index e3e3ebdfe5d..4299df2e082 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -797,179 +797,6 @@ qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, return ret; } -int -qla82xx_wrmem(struct qla_hw_data *ha, u64 off, void *data, int size) -{ - int i, j, ret = 0, loop, sz[2], off0; - u32 temp; - u64 off8, mem_crb, tmpw, word[2] = {0, 0}; -#define MAX_CTL_CHECK 1000 - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) { - mem_crb = QLA82XX_CRB_QDR_NET; - } else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_write_direct(ha, off, - data, size); - } - - off8 = off & 0xfffffff8; - off0 = off & 0x7; - sz[0] = (size < (8 - off0)) ? size : (8 - off0); - sz[1] = size - sz[0]; - loop = ((off0 + size - 1) >> 3) + 1; - - if ((size != 8) || (off0 != 0)) { - for (i = 0; i < loop; i++) { - if (qla82xx_rdmem(ha, off8 + (i << 3), &word[i], 8)) - return -1; - } - } - - switch (size) { - case 1: - tmpw = *((u8 *)data); - break; - case 2: - tmpw = *((u16 *)data); - break; - case 4: - tmpw = *((u32 *)data); - break; - case 8: - default: - tmpw = *((u64 *)data); - break; - } - - word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); - word[0] |= tmpw << (off0 * 8); - - if (loop == 2) { - word[1] &= ~(~0ULL << (sz[1] * 8)); - word[1] |= tmpw >> (sz[0] * 8); - } - - for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - qla_printk(KERN_WARNING, ha, - "%s: Fail to write through agent\n", - QLA2XXX_DRIVER_NAME); - ret = -1; - break; - } - } - return ret; -} - -int -qla82xx_rdmem(struct qla_hw_data *ha, u64 off, void *data, int size) -{ - int i, j = 0, k, start, end, loop, sz[2], off0[2]; - u32 temp; - u64 off8, val, mem_crb, word[2] = {0, 0}; -#define MAX_CTL_CHECK 1000 - - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_read_direct(ha, off, - data, size); - } - - off8 = off & 0xfffffff8; - off0[0] = off & 0x7; - off0[1] = 0; - sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); - sz[1] = size - sz[0]; - loop = ((off0[0] + size - 1) >> 3) + 1; - - for (i = 0; i < loop; i++) { - temp = off8 + (i << 3); - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - qla_printk(KERN_INFO, ha, - "%s: Fail to read through agent\n", - QLA2XXX_DRIVER_NAME); - break; - } - - start = off0[i] >> 2; - end = (off0[i] + sz[i] - 1) >> 2; - for (k = start; k <= end; k++) { - temp = qla82xx_rd_32(ha, - mem_crb + MIU_TEST_AGT_RDDATA(k)); - word[i] |= ((u64)temp << (32 * k)); - } - } - - if (j >= MAX_CTL_CHECK) - return -1; - - if (sz[0] == 8) { - val = word[0]; - } else { - val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | - ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); - } - - switch (size) { - case 1: - *(u8 *)data = val; - break; - case 2: - *(u16 *)data = val; - break; - case 4: - *(u32 *)data = val; - break; - case 8: - *(u64 *)data = val; - break; - } - return 0; -} - #define MTU_FUDGE_FACTOR 100 unsigned long qla82xx_decode_crb_addr(unsigned long addr) { @@ -1347,11 +1174,6 @@ int qla82xx_pinit_from_rom(scsi_qla_host_t *vha) continue; } - if (off == (QLA82XX_CRB_PEG_NET_1 + 0x18)) { - if (!QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) - buf[i].data = 0x1020; - } - qla82xx_wr_32(ha, off, buf[i].data); /* ISP requires much bigger delay to settle down, @@ -1429,12 +1251,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha) } udelay(100); read_lock(&ha->hw_lock); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - } else { - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); - } + qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); read_unlock(&ha->hw_lock); return 0; } @@ -1461,17 +1279,10 @@ qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, off, data, size); } - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - off8 = off & 0xfffffff0; - off0[0] = off & 0xf; - sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); - shift_amount = 4; - } else { - off8 = off & 0xfffffff8; - off0[0] = off & 0x7; - sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]); - shift_amount = 4; - } + off8 = off & 0xfffffff0; + off0[0] = off & 0xf; + sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); + shift_amount = 4; loop = ((off0[0] + size - 1) >> shift_amount) + 1; off0[1] = 0; sz[1] = size - sz[0]; @@ -1551,7 +1362,7 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, u64 off, void *data, int size) { int i, j, ret = 0, loop, sz[2], off0; - int scale, shift_amount, p3p, startword; + int scale, shift_amount, startword; uint32_t temp; uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; @@ -1571,28 +1382,16 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, sz[0] = (size < (8 - off0)) ? size : (8 - off0); sz[1] = size - sz[0]; - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - off8 = off & 0xfffffff0; - loop = (((off & 0xf) + size - 1) >> 4) + 1; - shift_amount = 4; - scale = 2; - p3p = 1; - startword = (off & 0xf)/8; - } else { - off8 = off & 0xfffffff8; - loop = ((off0 + size - 1) >> 3) + 1; - shift_amount = 3; - scale = 1; - p3p = 0; - startword = 0; - } - - if (p3p || (size != 8) || (off0 != 0)) { - for (i = 0; i < loop; i++) { - if (qla82xx_pci_mem_read_2M(ha, off8 + - (i << shift_amount), &word[i * scale], 8)) - return -1; - } + off8 = off & 0xfffffff0; + loop = (((off & 0xf) + size - 1) >> 4) + 1; + shift_amount = 4; + scale = 2; + startword = (off & 0xf)/8; + + for (i = 0; i < loop; i++) { + if (qla82xx_pci_mem_read_2M(ha, off8 + + (i << shift_amount), &word[i * scale], 8)) + return -1; } switch (size) { @@ -1611,26 +1410,16 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, break; } - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - if (sz[0] == 8) { - word[startword] = tmpw; - } else { - word[startword] &= - ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); - word[startword] |= tmpw << (off0 * 8); - } - if (sz[1] != 0) { - word[startword+1] &= ~(~0ULL << (sz[1] * 8)); - word[startword+1] |= tmpw >> (sz[0] * 8); - } + if (sz[0] == 8) { + word[startword] = tmpw; } else { - word[startword] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); + word[startword] &= + ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); word[startword] |= tmpw << (off0 * 8); - - if (loop == 2) { - word[1] &= ~(~0ULL << (sz[1] * 8)); - word[1] |= tmpw >> (sz[0] * 8); - } + } + if (sz[1] != 0) { + word[startword+1] &= ~(~0ULL << (sz[1] * 8)); + word[startword+1] |= tmpw >> (sz[0] * 8); } /* @@ -1647,14 +1436,12 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); temp = (word[i * scale] >> 32) & 0xffffffff; qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - temp = word[i*scale + 1] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_LO, temp); - temp = (word[i*scale + 1] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_HI, temp); - } + temp = word[i*scale + 1] & 0xffffffff; + qla82xx_wr_32(ha, mem_crb + + MIU_TEST_AGT_WRDATA_UPPER_LO, temp); + temp = (word[i*scale + 1] >> 32) & 0xffffffff; + qla82xx_wr_32(ha, mem_crb + + MIU_TEST_AGT_WRDATA_UPPER_HI, temp); temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); @@ -1804,22 +1591,6 @@ int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) return val; } -int qla82xx_pci_region_len(struct pci_dev *pdev, int region) -{ - unsigned long val = 0; - u32 control; - switch (region) { - case 0: - pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); - val = control; - break; - case 1: - val = pci_resource_len(pdev, 0) - - qla82xx_pci_region_offset(pdev, 1); - break; - } - return val; -} int qla82xx_iospace_config(struct qla_hw_data *ha) @@ -1941,12 +1712,6 @@ void qla82xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - icb->version = 1; - icb->frame_payload_size = 2112; - icb->execution_throttle = 8; - icb->exchange_count = 128; - icb->login_retry_count = 8; - WRT_REG_DWORD((unsigned long __iomem *)®->req_q_out[0], 0); WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_in[0], 0); WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_out[0], 0); @@ -1999,11 +1764,8 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha) qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC); read_lock(&ha->hw_lock); - if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) { - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - } else - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d); + qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); + qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); read_unlock(&ha->hw_lock); return 0; } @@ -2256,8 +2018,6 @@ qla82xx_intr_handler(int irq, void *dev_id) if (RD_REG_DWORD(®->host_int)) { stat = RD_REG_DWORD(®->host_status); - if ((stat & HSRX_RISC_INT) == 0) - break; switch (stat & 0xff) { case 0x1: @@ -2332,8 +2092,6 @@ qla82xx_msix_default(int irq, void *dev_id) do { if (RD_REG_DWORD(®->host_int)) { stat = RD_REG_DWORD(®->host_status); - if ((stat & HSRX_RISC_INT) == 0) - break; switch (stat & 0xff) { case 0x1: @@ -2583,12 +2341,6 @@ int qla82xx_load_fw(scsi_qla_host_t *vha) struct fw_blob *blob; struct qla_hw_data *ha = vha->hw; - /* Put both the PEG CMD and RCV PEG to default state - * of 0 before resetting the hardware - */ - qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); - qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); - if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) { qla_printk(KERN_ERR, ha, "%s: Error during CRB Initialization\n", __func__); @@ -2669,6 +2421,12 @@ qla82xx_start_firmware(scsi_qla_host_t *vha) /* scrub dma mask expansion register */ qla82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); + /* Put both the PEG CMD and RCV PEG to default state + * of 0 before resetting the hardware + */ + qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); + qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); + /* Overwrite stale initialization register values */ qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 9a9127efada..420e0773e74 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -816,7 +816,6 @@ struct qla82xx_uri_data_desc{ #define QLA82XX_FLASH_ROMIMAGE 4 #define QLA82XX_UNKNOWN_ROMIMAGE 0xff -#define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50) #define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) #define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) @@ -887,7 +886,7 @@ struct ct6_dsd { struct list_head dsd_list; }; -#define MBC_TOGGLE_INTR 0x10 +#define MBC_TOGGLE_INTERRUPT 0x10 /* Flash offset */ #define FLT_REG_BOOTLOAD_82XX 0x72 -- cgit v1.2.3-70-g09d2 From 4d78c973ef2d21e90ff55f97489d663a0959a93f Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 23 Jul 2010 15:28:35 +0500 Subject: [SCSI] qla2xxx: Rearranged and cleaned up the code for processing the pending commands. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 10 ++++++++-- drivers/scsi/qla2xxx/qla_gbl.h | 5 +++-- drivers/scsi/qla2xxx/qla_init.c | 9 +++++++-- drivers/scsi/qla2xxx/qla_os.c | 41 +++++++---------------------------------- 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 7e11ccf0fe8..84e9c6b48ca 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2981,9 +2981,15 @@ typedef struct scsi_qla_host { #define QLA_DSDS_PER_IOCB 37 +#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) + +enum nexus_wait_type { + WAIT_HOST = 0, + WAIT_TARGET, + WAIT_LUN, +}; + #include "qla_gbl.h" #include "qla_dbg.h" #include "qla_inline.h" - -#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 8b0a8ca9508..4688ad2a559 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -292,7 +292,9 @@ extern int qla24xx_abort_target(struct fc_port *, unsigned int, int); extern int qla24xx_lun_reset(struct fc_port *, unsigned int, int); - +extern int +qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *, unsigned int, + unsigned int, enum nexus_wait_type); extern int qla2x00_system_error(scsi_qla_host_t *); @@ -569,7 +571,6 @@ extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *); extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); extern void qla82xx_start_iocbs(srb_t *); extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); -extern void qla82xx_wait_for_pending_commands(scsi_qla_host_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct fc_bsg_job *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f6b1052a383..9b58a79c4ae 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3833,8 +3833,13 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) } /* Make sure for ISP 82XX IO DMA is complete */ - if (IS_QLA82XX(ha)) - qla82xx_wait_for_pending_commands(vha); + if (IS_QLA82XX(ha)) { + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, + WAIT_HOST) == QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_INFO, ha, + "Done wait for pending commands\n")); + } + } /* Requeue all commands in outstanding command list. */ qla2x00_abort_all_cmds(vha, DID_RESET << 16); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fcdbf7a0be5..86d352ab9c5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -903,24 +903,17 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } -enum nexus_wait_type { - WAIT_HOST = 0, - WAIT_TARGET, - WAIT_LUN, -}; - -static int +int qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, - unsigned int l, srb_t *sp, enum nexus_wait_type type) + unsigned int l, enum nexus_wait_type type) { int cnt, match, status; unsigned long flags; struct qla_hw_data *ha = vha->hw; struct req_que *req; + srb_t *sp; status = QLA_SUCCESS; - if (!sp) - return status; spin_lock_irqsave(&ha->hardware_lock, flags); req = vha->req; @@ -958,24 +951,6 @@ qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, return status; } -void qla82xx_wait_for_pending_commands(scsi_qla_host_t *vha) -{ - int cnt; - srb_t *sp; - struct req_que *req = vha->req; - - DEBUG2(qla_printk(KERN_INFO, vha->hw, - "Waiting for pending commands\n")); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - sp, WAIT_HOST) == QLA_SUCCESS) { - DEBUG2(qla_printk(KERN_INFO, vha->hw, - "Done wait for pending commands\n")); - } - } -} - static char *reset_errors[] = { "HBA not online", "HBA not ready", @@ -1011,7 +986,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, goto eh_reset_failed; err = 3; if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id, - cmd->device->lun, (srb_t *) CMD_SP(cmd), type) != QLA_SUCCESS) + cmd->device->lun, type) != QLA_SUCCESS) goto eh_reset_failed; qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", @@ -1019,7 +994,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, return SUCCESS; - eh_reset_failed: +eh_reset_failed: qla_printk(KERN_INFO, vha->hw, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n" , vha->host_no, cmd->device->id, cmd->device->lun, name, reset_errors[err]); @@ -1069,7 +1044,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) int ret = FAILED; unsigned int id, lun; unsigned long serial; - srb_t *sp = (srb_t *) CMD_SP(cmd); fc_block_scsi_eh(cmd); @@ -1096,7 +1070,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) != + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) != QLA_SUCCESS) ret = FAILED; @@ -1131,7 +1105,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) int ret = FAILED; unsigned int id, lun; unsigned long serial; - srb_t *sp = (srb_t *) CMD_SP(cmd); scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); fc_block_scsi_eh(cmd); @@ -1186,7 +1159,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) } /* Waiting for command to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, sp, WAIT_HOST) == + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) == QLA_SUCCESS) ret = SUCCESS; -- cgit v1.2.3-70-g09d2 From de7c5d059dbd245ad80011725f9c86f560e61fff Mon Sep 17 00:00:00 2001 From: Giridhar Malavali Date: Fri, 23 Jul 2010 15:28:36 +0500 Subject: [SCSI] qla2xxx: Update copyright banner. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 +- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- drivers/scsi/qla2xxx/qla_bsg.h | 2 +- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_dbg.h | 2 +- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_dfs.c | 2 +- drivers/scsi/qla2xxx/qla_fw.h | 2 +- drivers/scsi/qla2xxx/qla_gbl.h | 2 +- drivers/scsi/qla2xxx/qla_gs.c | 2 +- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_inline.h | 2 +- drivers/scsi/qla2xxx/qla_iocb.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 2 +- drivers/scsi/qla2xxx/qla_mid.c | 2 +- drivers/scsi/qla2xxx/qla_nx.c | 2 +- drivers/scsi/qla2xxx/qla_nx.h | 2 +- drivers/scsi/qla2xxx/qla_os.c | 2 +- drivers/scsi/qla2xxx/qla_settings.h | 2 +- drivers/scsi/qla2xxx/qla_sup.c | 2 +- drivers/scsi/qla2xxx/qla_version.h | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 93a4c20e211..d9b431d061b 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 6b863f789c4..9067629817e 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index 1f096dabc01..cc7c52f87a1 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 2afc8a362f2..09614114825 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 916c81f3f55..6cfc28a25eb 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 84e9c6b48ca..3a432ea0c7a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 3a9a6ca4226..6271353e8c5 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 93f83396014..631fefc8482 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 4688ad2a559..b7d940fcbc1 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 2fabae8daec..4c083928c2f 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 9b58a79c4ae..1b7d80b2098 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 84c2fea154d..48f97a92e33 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index e27d94713bd..c9c709e0f1a 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 51800332822..6982ba70e12 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 02a4d355db3..6009b0c6948 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index d1618b4a5e5..642cd79bd03 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 4299df2e082..915b77a6e19 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 420e0773e74..569232b4550 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 86d352ab9c5..50f685415fb 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h index 2801c2664b4..f0b2b9986a5 100644 --- a/drivers/scsi/qla2xxx/qla_settings.h +++ b/drivers/scsi/qla2xxx/qla_settings.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index df288dc829e..76de9574b38 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 9b49b086274..e75ccb91317 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2008 QLogic Corporation + * Copyright (c) 2003-2010 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -- cgit v1.2.3-70-g09d2 From 3dbe756a66afbec6487068d4213ecccc3a18807f Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jul 2010 15:28:37 +0500 Subject: [SCSI] qla2xxx: Cleanup some dead-code and make some functions static. Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 6 ----- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_iocb.c | 2 +- drivers/scsi/qla2xxx/qla_mid.c | 51 +---------------------------------------- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 5 files changed, 5 insertions(+), 60 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index b7d940fcbc1..1a1b281cea3 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -175,10 +175,7 @@ extern int qla2x00_start_scsi(srb_t *sp); extern int qla24xx_start_scsi(srb_t *sp); int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, uint16_t, uint16_t, uint8_t); -int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, - uint16_t, uint16_t, uint8_t); extern int qla2x00_start_sp(srb_t *); -extern void qla2x00_ctx_sp_free(srb_t *); extern uint16_t qla24xx_calc_iocbs(uint16_t); extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); extern int qla24xx_dif_start_scsi(srb_t *); @@ -489,11 +486,8 @@ extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, uint16_t, int, uint8_t); extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, uint16_t, int); -extern int qla25xx_update_req_que(struct scsi_qla_host *, uint8_t, uint8_t); extern void qla2x00_init_response_q_entries(struct rsp_que *); extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); -extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *); -extern int qla25xx_create_queues(struct scsi_qla_host *, uint8_t); extern int qla25xx_delete_queues(struct scsi_qla_host *); extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t); extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1b7d80b2098..d863ed2619b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -64,7 +64,7 @@ qla2x00_ctx_sp_timeout(unsigned long __data) spin_unlock_irqrestore(&ha->hardware_lock, flags); } -void +static void qla2x00_ctx_sp_free(srb_t *sp) { struct srb_ctx *ctx = sp->ctx; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index c9c709e0f1a..d2b299f2c50 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -461,7 +461,7 @@ queuing_error: * * Returns non-zero if a failure occurred, else zero. */ -int +static int __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, struct rsp_que *rsp, uint16_t loop_id, uint16_t lun, uint8_t type) diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 642cd79bd03..9a82c34f620 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -482,7 +482,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req) return ret; } -int +static int qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) { int ret = -1; @@ -497,23 +497,6 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) return ret; } -int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos) -{ - int ret = 0; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[que]; - - req->options |= BIT_3; - req->qos = qos; - ret = qla25xx_init_req_que(vha, req); - if (ret != QLA_SUCCESS) - DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__)); - /* restore options bit */ - req->options &= ~BIT_3; - return ret; -} - - /* Delete all queues for a given vhost */ int qla25xx_delete_queues(struct scsi_qla_host *vha) @@ -740,35 +723,3 @@ que_failed: failed: return 0; } - -int -qla25xx_create_queues(struct scsi_qla_host *vha, uint8_t qos) -{ - uint16_t options = 0; - uint8_t ret = 0; - struct qla_hw_data *ha = vha->hw; - struct rsp_que *rsp; - - options |= BIT_1; - ret = qla25xx_create_rsp_que(ha, options, vha->vp_idx, 0, -1); - if (!ret) { - qla_printk(KERN_WARNING, ha, "Response Que create failed\n"); - return ret; - } else - qla_printk(KERN_INFO, ha, "Response Que:%d created.\n", ret); - rsp = ha->rsp_q_map[ret]; - - options = 0; - if (qos & BIT_7) - options |= BIT_8; - ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, ret, - qos & ~BIT_7); - if (ret) { - vha->req = ha->req_q_map[ret]; - qla_printk(KERN_INFO, ha, "Request Que:%d created.\n", ret); - } else - qla_printk(KERN_WARNING, ha, "Request Que create failed\n"); - rsp->req = ha->req_q_map[ret]; - - return ret; -} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 50f685415fb..aeb2f1b504c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -701,7 +701,7 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) * Success (Adapter is online/no flash ops) : 0 * Failed (Adapter is offline/disabled/flash ops in progress) : 1 */ -int +static int qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha) { int return_status; @@ -3469,7 +3469,7 @@ qla2x00_sp_free_dma(srb_t *sp) CMD_SP(cmd) = NULL; } -void +static void qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp) { struct scsi_cmnd *cmd = sp->cmd; -- cgit v1.2.3-70-g09d2 From 0c470874858e0075f420dcfb3c3570b2057de275 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Fri, 23 Jul 2010 15:28:38 +0500 Subject: [SCSI] qla2xxx: T10 DIF Type 2 support Signed-off-by: Andrew Vasquez Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 ++ drivers/scsi/qla2xxx/qla_iocb.c | 35 +++++++++++++++++++++++++++++++---- drivers/scsi/qla2xxx/qla_mid.c | 5 ++++- drivers/scsi/qla2xxx/qla_os.c | 7 ++++++- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d9b431d061b..420238cc794 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1758,8 +1758,10 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) " protection.\n")); scsi_host_set_prot(vha->host, SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION); scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC); } else diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d2b299f2c50..4e4c21fafe3 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -712,6 +712,25 @@ qla24xx_set_t10dif_tags(struct scsi_cmnd *cmd, struct fw_dif_context *pkt, * match LBA in CDB + N */ case SCSI_PROT_DIF_TYPE2: + if (!ql2xenablehba_err_chk) + break; + + if (scsi_prot_sg_count(cmd)) { + spt = page_address(sg_page(scsi_prot_sglist(cmd))) + + scsi_prot_sglist(cmd)[0].offset; + pkt->app_tag = swab32(spt->app_tag); + pkt->app_tag_mask[0] = 0xff; + pkt->app_tag_mask[1] = 0xff; + } + + pkt->ref_tag = cpu_to_le32((uint32_t) + (0xffffffff & scsi_get_lba(cmd))); + + /* enable ALL bytes of the ref tag */ + pkt->ref_tag_mask[0] = 0xff; + pkt->ref_tag_mask[1] = 0xff; + pkt->ref_tag_mask[2] = 0xff; + pkt->ref_tag_mask[3] = 0xff; break; /* For Type 3 protection: 16 bit GUARD only */ @@ -1062,7 +1081,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, total_bytes = data_bytes; dif_bytes = 0; blk_size = cmd->device->sector_size; - if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE1) { + if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { dif_bytes = (data_bytes / blk_size) * 8; total_bytes += dif_bytes; } @@ -1100,6 +1119,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, vha->host_no, dif_bytes, dif_bytes, total_bytes, total_bytes, crc_ctx_pkt->blk_size, crc_ctx_pkt->blk_size)); + if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { + DEBUG18(printk(KERN_INFO "%s: Zero data bytes or DMA-NONE %d\n", + __func__, data_bytes)); + cmd_pkt->byte_count = __constant_cpu_to_le32(0); + return QLA_SUCCESS; + } /* Walks data segments */ cmd_pkt->control_flags |= @@ -1310,9 +1335,11 @@ qla24xx_dif_start_scsi(srb_t *sp) #define QDSS_GOT_Q_SPACE BIT_0 - /* Only process protection in this routine */ - if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) - return qla24xx_start_scsi(sp); + /* Only process protection or >16 cdb in this routine */ + if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { + if (cmd->cmd_len <= 16) + return qla24xx_start_scsi(sp); + } /* Setup device pointers. */ diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 9a82c34f620..987c5b0ca78 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -399,7 +399,10 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) host->can_queue = base_vha->req->length + 128; host->this_id = 255; host->cmd_per_lun = 3; - host->max_cmd_len = MAX_CMDSZ; + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) + host->max_cmd_len = 32; + else + host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; host->max_lun = MAX_LUNS; host->unique_id = host->host_no; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index aeb2f1b504c..ff2172da7c1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2147,7 +2147,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->this_id = 255; host->cmd_per_lun = 3; host->unique_id = host->host_no; - host->max_cmd_len = MAX_CMDSZ; + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) + host->max_cmd_len = 32; + else + host->max_cmd_len = MAX_CMDSZ; host->max_channel = MAX_BUSES - 1; host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; @@ -2255,8 +2258,10 @@ skip_dpc: " protection.\n")); scsi_host_set_prot(host, SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION); scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC); } else -- cgit v1.2.3-70-g09d2 From 0dcae66fd9cb47f4db64aba20a59d26e09e78fe4 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 1 Jul 2009 22:43:39 +0200 Subject: [SCSI] aacraid: Do not set DMA mask to 32 bit first if adapter only supports 31 Signed-off-by: Rolf Eike Beer Acked-by: Achim Leubner Signed-off-by: James Bottomley --- drivers/scsi/aacraid/linit.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 33898b61fdb..cad6f9abaeb 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1091,6 +1091,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, struct list_head *insert = &aac_devices; int error = -ENODEV; int unique_id = 0; + u64 dmamask; list_for_each_entry(aac, &aac_devices, entry) { if (aac->id > unique_id) @@ -1104,17 +1105,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, goto out; error = -ENODEV; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) || - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) - goto out_disable_pdev; /* * If the quirk31 bit is set, the adapter needs adapter * to driver communication memory to be allocated below 2gig */ if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(31)) || - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(31))) - goto out_disable_pdev; + dmamask = DMA_BIT_MASK(31); + else + dmamask = DMA_BIT_MASK(32); + + if (pci_set_dma_mask(pdev, dmamask) || + pci_set_consistent_dma_mask(pdev, dmamask)) + goto out_disable_pdev; pci_set_master(pdev); -- cgit v1.2.3-70-g09d2 From b5833cbbd7c2bc3462e684feadd8e6a0ca8e5387 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 20 Jul 2010 15:28:41 -0700 Subject: [SCSI] ibmvstgt: add __init/__exit macros Add the __init and __exit macros to the module_init / module_exit functions from drivers/scsi/ibmvscsi/ibmvstgt.c Signed-off-by: Peter Huewe Signed-off-by: Andrew Morton Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvstgt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index e2056d517e9..2256babe047 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -956,7 +956,7 @@ static struct srp_function_template ibmvstgt_transport_functions = { .it_nexus_response = ibmvstgt_it_nexus_response, }; -static int ibmvstgt_init(void) +static int __init ibmvstgt_init(void) { int err = -ENOMEM; @@ -987,7 +987,7 @@ release_transport: return err; } -static void ibmvstgt_exit(void) +static void __exit ibmvstgt_exit(void) { printk("Unregister IBM virtual SCSI driver\n"); -- cgit v1.2.3-70-g09d2 From c9de7dc48307395fb71780b567ae8833b080d1c8 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Mon, 26 Jul 2010 18:56:21 +0530 Subject: [SCSI] mptfusion: Block Error handling for deleting devices or Device in DMD Issue description: In multipath topology, when device deletion is in transient state, multipath driver can call blk_flush_queue() as part of path failure. Before device get deleted from OS, Device may go OFFLINE as part of error handling kicked off triggered from multipathing driver. Above condition hits more frequently if device missing delay timer (which is LSI specific firmware parameter) is non zero value. root cause of this issue is Error handling thread is getting kicked off for device which is not really present(in transient state of deleting). This patch has solution for this issue. driver is now using eh_timed_out callback. See below. mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out Using mptsas_eh_timed_out function, driver can decide weather vdevice is under Device missing delay or deleting state. for either of those cases, there is BLK_EH_RESET_TIMER return to scsi mid and error handling thread will not be kicked off for that particular scsi command. Signed-off-by: Kashyap Desai Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 2 + drivers/message/fusion/mptsas.c | 125 +++++++++++++++++++++++++++++++++++++- drivers/message/fusion/mptscsih.c | 40 +++++++++--- 3 files changed, 157 insertions(+), 10 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 0d149c82e76..7f31973b3f7 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -396,6 +396,8 @@ typedef struct _VirtTarget { u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ u8 deleted; /* target in process of being removed */ + u8 inDMD; /* currently in the device + removal delay timer */ u32 num_luns; } VirtTarget; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index f705a235300..235113ac08e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include "mptbase.h" @@ -1912,6 +1913,48 @@ mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) return mptscsih_qcmd(SCpnt,done); } +/** + * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout + * if the device under question is currently in the + * device removal delay. + * @sc: scsi command that the midlayer is about to time out + * + **/ +static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc) +{ + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; + VirtDevice *vdevice; + enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; + + hd = shost_priv(sc->device->host); + if (hd == NULL) { + printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n", + __func__, sc); + goto done; + } + + ioc = hd->ioc; + if (ioc->bus_type != SAS) { + printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n", + __func__, sc); + goto done; + } + + vdevice = sc->device->hostdata; + if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD + || vdevice->vtarget->deleted)) { + dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed " + "or in device removal delay (sc=%p)\n", + ioc->name, __func__, sc)); + rc = BLK_EH_RESET_TIMER; + goto done; + } + +done: + return rc; +} + static struct scsi_host_template mptsas_driver_template = { .module = THIS_MODULE, @@ -2984,6 +3027,7 @@ static int mptsas_probe_one_phy(struct device *dev, struct sas_phy *phy; struct sas_port *port; int error = 0; + VirtTarget *vtarget; if (!dev) { error = -ENODEV; @@ -3206,6 +3250,16 @@ static int mptsas_probe_one_phy(struct device *dev, rphy_to_expander_device(rphy)); } + /* If the device exists,verify it wasn't previously flagged + as a missing device. If so, clear it */ + vtarget = mptsas_find_vtarget(ioc, + phy_info->attached.channel, + phy_info->attached.id); + if (vtarget && vtarget->inDMD) { + printk(KERN_INFO "Device returned, unsetting inDMD\n"); + vtarget->inDMD = 0; + } + out: return error; } @@ -3659,9 +3713,42 @@ mptsas_send_link_status_event(struct fw_event_work *fw_event) MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION) phy_info->phy->negotiated_linkrate = SAS_LINK_RATE_FAILED; - else + else { phy_info->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + if (ioc->device_missing_delay && + mptsas_is_end_device(&phy_info->attached)) { + struct scsi_device *sdev; + VirtDevice *vdevice; + u8 channel, id; + id = phy_info->attached.id; + channel = phy_info->attached.channel; + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Link down for fw_id %d:fw_channel %d\n", + ioc->name, phy_info->attached.id, + phy_info->attached.channel)); + + shost_for_each_device(sdev, ioc->sh) { + vdevice = sdev->hostdata; + if ((vdevice == NULL) || + (vdevice->vtarget == NULL)) + continue; + if ((vdevice->vtarget->tflags & + MPT_TARGET_FLAGS_RAID_COMPONENT || + vdevice->vtarget->raidVolume)) + continue; + if (vdevice->vtarget->id == id && + vdevice->vtarget->channel == + channel) + devtprintk(ioc, + printk(MYIOC_s_DEBUG_FMT + "SDEV OUTSTANDING CMDS" + "%d\n", ioc->name, + sdev->device_busy)); + } + + } + } } out: mptsas_free_fw_event(ioc, fw_event); @@ -4906,12 +4993,47 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) { EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data; + u16 ioc_stat; + ioc_stat = le16_to_cpu(reply->IOCStatus); if (sas_event_data->ReasonCode == MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) { mptsas_target_reset_queue(ioc, sas_event_data); return 0; } + if (sas_event_data->ReasonCode == + MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && + ioc->device_missing_delay && + (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) { + VirtTarget *vtarget = NULL; + u8 id, channel; + u32 log_info = le32_to_cpu(reply->IOCLogInfo); + + id = sas_event_data->TargetID; + channel = sas_event_data->Bus; + + vtarget = mptsas_find_vtarget(ioc, channel, id); + if (vtarget) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "LogInfo (0x%x) available for " + "INTERNAL_DEVICE_RESET" + "fw_id %d fw_channel %d\n", ioc->name, + log_info, id, channel)); + if (vtarget->raidVolume) { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Skipping Raid Volume for inDMD\n", + ioc->name)); + } else { + devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT + "Setting device flag inDMD\n", + ioc->name)); + vtarget->inDMD = 1; + } + + } + + } + break; } case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: @@ -5244,6 +5366,7 @@ mptsas_init(void) sas_attach_transport(&mptsas_transport_functions); if (!mptsas_transport_template) return -ENODEV; + mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out; mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index dceb67a2182..59b8f53d1ec 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -664,6 +664,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) u32 log_info; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; + scsi_state = pScsiReply->SCSIState; scsi_status = pScsiReply->SCSIStatus; xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); @@ -738,15 +739,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ if ( ioc->bus_type == SAS ) { - u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus); - if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { - if ((log_info & SAS_LOGINFO_MASK) - == SAS_LOGINFO_NEXUS_LOSS) { - sc->result = - (DID_TRANSPORT_DISRUPTED - << 16); - break; - } + u16 ioc_status = + le16_to_cpu(pScsiReply->IOCStatus); + if ((ioc_status & + MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) + && + ((log_info & SAS_LOGINFO_MASK) == + SAS_LOGINFO_NEXUS_LOSS)) { + VirtDevice *vdevice = + sc->device->hostdata; + + /* flag the device as being in + * device removal delay so we can + * notify the midlayer to hold off + * on timeout eh */ + if (vdevice && vdevice-> + vtarget && + vdevice->vtarget-> + raidVolume) + printk(KERN_INFO + "Skipping Raid Volume" + "for inDMD\n"); + else if (vdevice && + vdevice->vtarget) + vdevice->vtarget-> + inDMD = 1; + + sc->result = + (DID_TRANSPORT_DISRUPTED + << 16); + break; } } else if (ioc->bus_type == FC) { /* -- cgit v1.2.3-70-g09d2 From 213aaca3e5727f3eb56002b04a1405db34a54ed8 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Mon, 26 Jul 2010 18:57:36 +0530 Subject: [SCSI] mptfusion: Extra debug prints added relavent to Device missing delay error handling Adding function name in original debug prints and few more debug prints are added. Signed-off-by: Kashyap Desai Cc: Stable Tree Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 27 ++++++++++++++++----------- drivers/message/fusion/mptbase.h | 3 ++- drivers/message/fusion/mptctl.c | 6 ++++-- drivers/message/fusion/mptfc.c | 9 ++++++--- drivers/message/fusion/mptlan.c | 4 +++- drivers/message/fusion/mptsas.c | 15 ++++++++++----- drivers/message/fusion/mptspi.c | 9 ++++++--- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index e319abcd849..82800393771 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -115,6 +115,7 @@ MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault" " and halt Firmware on fault - (default=0)"); +static char MptCallbacksName[MPT_MAX_PROTOCOL_DRIVERS][50]; #ifdef MFCNT static int mfcounter = 0; @@ -213,7 +214,7 @@ static int ProcessEventNotification(MPT_ADAPTER *ioc, static void mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info); -static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info , u8 cb_idx); static int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); static void mpt_inactive_raid_list_free(MPT_ADAPTER *ioc); @@ -490,7 +491,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa) else if (ioc->bus_type == SPI) mpt_spi_log_info(ioc, log_info); else if (ioc->bus_type == SAS) - mpt_sas_log_info(ioc, log_info); + mpt_sas_log_info(ioc, log_info, cb_idx); } if (ioc_stat & MPI_IOCSTATUS_MASK) @@ -644,7 +645,7 @@ mptbase_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) * considered an error by the caller. */ u8 -mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) +mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, char *func_name) { u8 cb_idx; last_drv_idx = MPT_MAX_PROTOCOL_DRIVERS; @@ -659,6 +660,8 @@ mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass) MptDriverClass[cb_idx] = dclass; MptEvHandlers[cb_idx] = NULL; last_drv_idx = cb_idx; + memcpy(MptCallbacksName[cb_idx], func_name, + strlen(func_name) > 50 ? 50 : strlen(func_name)); break; } } @@ -8002,7 +8005,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) * Refer to lsi/mpi_log_sas.h. **/ static void -mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) +mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info, u8 cb_idx) { union loginfo_type { u32 loginfo; @@ -8056,21 +8059,22 @@ union loginfo_type { if (sub_code_desc != NULL) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code={%s}," - " SubCode={%s}\n", + " SubCode={%s} cb_idx %s\n", ioc->name, log_info, originator_desc, code_desc, - sub_code_desc); + sub_code_desc, MptCallbacksName[cb_idx]); else if (code_desc != NULL) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code={%s}," - " SubCode(0x%04x)\n", + " SubCode(0x%04x) cb_idx %s\n", ioc->name, log_info, originator_desc, code_desc, - sas_loginfo.dw.subcode); + sas_loginfo.dw.subcode, MptCallbacksName[cb_idx]); else printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," - " SubCode(0x%04x)\n", + " SubCode(0x%04x) cb_idx %s\n", ioc->name, log_info, originator_desc, - sas_loginfo.dw.code, sas_loginfo.dw.subcode); + sas_loginfo.dw.code, sas_loginfo.dw.subcode, + MptCallbacksName[cb_idx]); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -8435,7 +8439,8 @@ fusion_init(void) /* Register ourselves (mptbase) in order to facilitate * EventNotification handling. */ - mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER); + mpt_base_index = mpt_register(mptbase_reply, MPTBASE_DRIVER, + "mptbase_reply"); /* Register for hard reset handling callbacks. */ diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 7f31973b3f7..0b23c426a57 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -926,7 +926,8 @@ extern void mpt_detach(struct pci_dev *pdev); extern int mpt_suspend(struct pci_dev *pdev, pm_message_t state); extern int mpt_resume(struct pci_dev *pdev); #endif -extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass); +extern u8 mpt_register(MPT_CALLBACK cbfunc, MPT_DRIVER_CLASS dclass, + char *func_name); extern void mpt_deregister(u8 cb_idx); extern int mpt_event_register(u8 cb_idx, MPT_EVHANDLER ev_cbfunc); extern void mpt_event_deregister(u8 cb_idx); diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 40046f595f1..d8ddfdf8be1 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -3018,7 +3018,8 @@ static int __init mptctl_init(void) * Install our handler */ ++where; - mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER); + mptctl_id = mpt_register(mptctl_reply, MPTCTL_DRIVER, + "mptctl_reply"); if (!mptctl_id || mptctl_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); misc_deregister(&mptctl_miscdev); @@ -3026,7 +3027,8 @@ static int __init mptctl_init(void) goto out_fail; } - mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER); + mptctl_taskmgmt_id = mpt_register(mptctl_taskmgmt_reply, MPTCTL_DRIVER, + "mptctl_taskmgmt_reply"); if (!mptctl_taskmgmt_id || mptctl_taskmgmt_id >= MPT_MAX_PROTOCOL_DRIVERS) { printk(KERN_ERR MYNAM ": ERROR: Failed to register with Fusion MPT base driver\n"); mpt_deregister(mptctl_id); diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index b5f03ad8156..e15220ff52f 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -1472,9 +1472,12 @@ mptfc_init(void) 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); + mptfcDoneCtx = mpt_register(mptscsih_io_done, MPTFC_DRIVER, + "mptscsih_scandv_complete"); + mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER, + "mptscsih_scandv_complete"); + mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER, + "mptscsih_scandv_complete"); mpt_event_register(mptfcDoneCtx, mptfc_event_process); mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 4fa9665cbe9..cbe96072a6c 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -1452,7 +1452,9 @@ static int __init mpt_lan_init (void) { show_mptmod_ver(LANAME, LANVER); - if ((LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER)) <= 0) { + LanCtx = mpt_register(lan_reply, MPTLAN_DRIVER, + "lan_reply"); + if (LanCtx <= 0) { printk (KERN_ERR MYNAM ": Failed to register with MPT base driver\n"); return -EBUSY; } diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 235113ac08e..83a5115f025 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -5368,13 +5368,18 @@ mptsas_init(void) return -ENODEV; mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out; - mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); - mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); + mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER, + "mptscsih_io_done"); + mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER, + "mptscsih_taskmgmt_complete"); mptsasInternalCtx = - mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); - mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); + mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER, + "mptscsih_scandv_complete"); + mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER, + "mptsas_mgmt_done"); mptsasDeviceResetCtx = - mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER); + mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER, + "mptsas_taskmgmt_complete"); mpt_event_register(mptsasDoneCtx, mptsas_event_process); mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 1abaa5d01ae..0e2803155ae 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -1551,9 +1551,12 @@ mptspi_init(void) if (!mptspi_transport_template) return -ENODEV; - mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER); - mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER); - mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER); + mptspiDoneCtx = mpt_register(mptscsih_io_done, MPTSPI_DRIVER, + "mptscsih_io_done"); + mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER, + "mptscsih_taskmgmt_complete"); + mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, + MPTSPI_DRIVER, "mptscsih_scandv_complete"); mpt_event_register(mptspiDoneCtx, mptspi_event_process); mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset); -- cgit v1.2.3-70-g09d2 From 943a2df8c8fb95a9d4243d4878db1c302ff85725 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Mon, 26 Jul 2010 18:58:44 +0530 Subject: [SCSI] mptfusion: Bump version 03.04.17 Version upgrade patch. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 0b23c426a57..23ed3dec72a 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.16" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.16" +#define MPT_LINUX_VERSION_COMMON "3.04.17" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.17" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ -- cgit v1.2.3-70-g09d2 From 653c42d552d0fd0b05485442aed45dd2d62269c0 Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Mon, 26 Jul 2010 16:41:13 +0200 Subject: [SCSI] mptfusion: release resources in error return path We should release the resources in error return code path. The requested pci bars should be released under an error condition, when mpt_mapresources fails. Signed-off-by: Tomas Henzl Acked-by: "Desai, Kashyap" Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 82800393771..2a52559058a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1635,6 +1635,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) } else { printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", ioc->name, pci_name(pdev)); + pci_release_selected_regions(pdev, ioc->bars); return r; } } else { @@ -1648,6 +1649,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) } else { printk(MYIOC_s_WARN_FMT "no suitable DMA mask for %s\n", ioc->name, pci_name(pdev)); + pci_release_selected_regions(pdev, ioc->bars); return r; } } @@ -1678,6 +1680,7 @@ mpt_mapresources(MPT_ADAPTER *ioc) if (mem == NULL) { printk(MYIOC_s_ERR_FMT ": ERROR - Unable to map adapter" " memory!\n", ioc->name); + pci_release_selected_regions(pdev, ioc->bars); return -EINVAL; } ioc->memmap = mem; -- cgit v1.2.3-70-g09d2 From df64d3caab8db6ae17dacd229a03d7689a10c432 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 27 Jul 2010 15:51:13 -0500 Subject: [SCSI] Unify SAM_ and SAM_STAT_ macros We have two separate definitions for identical constants with nearly the same name. One comes from the generic headers in scsi.h; the other is an enum in libsas.h ... it's causing confusion about which one is correct (fortunately they both are). Fix this by eliminating the libsas.h duplicate Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_task.c | 2 +- drivers/scsi/libsas/sas_ata.c | 12 ++++++------ drivers/scsi/libsas/sas_expander.c | 2 +- drivers/scsi/libsas/sas_scsi_host.c | 4 ++-- drivers/scsi/libsas/sas_task.c | 6 +++--- drivers/scsi/mvsas/mv_sas.c | 16 ++++++++-------- drivers/scsi/pm8001/pm8001_hwi.c | 14 +++++++------- drivers/scsi/pm8001/pm8001_sas.c | 4 ++-- include/scsi/libsas.h | 11 +---------- 9 files changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 75d20f72501..532d212b6b2 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -223,7 +223,7 @@ Again: switch (opcode) { case TC_NO_ERROR: ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_GOOD; + ts->stat = SAM_STAT_GOOD; break; case TC_UNDERRUN: ts->resp = SAS_TASK_COMPLETE; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 8c496b56556..042153cbbde 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -71,7 +71,7 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) case SAS_SG_ERR: return AC_ERR_INVALID; - case SAM_CHECK_COND: + case SAM_STAT_CHECK_CONDITION: case SAS_OPEN_TO: case SAS_OPEN_REJECT: SAS_DPRINTK("%s: Saw error %d. What to do?\n", @@ -107,7 +107,7 @@ static void sas_ata_task_done(struct sas_task *task) sas_ha = dev->port->ha; spin_lock_irqsave(dev->sata_dev.ap->lock, flags); - if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) { + if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD) { ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command); dev->sata_dev.sstatus = resp->sstatus; @@ -511,12 +511,12 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size, goto ex_err; } } - if (task->task_status.stat == SAM_BUSY || - task->task_status.stat == SAM_TASK_SET_FULL || + if (task->task_status.stat == SAM_STAT_BUSY || + task->task_status.stat == SAM_STAT_TASK_SET_FULL || task->task_status.stat == SAS_QUEUE_FULL) { SAS_DPRINTK("task: q busy, sleeping...\n"); schedule_timeout_interruptible(HZ); - } else if (task->task_status.stat == SAM_CHECK_COND) { + } else if (task->task_status.stat == SAM_STAT_CHECK_CONDITION) { struct scsi_sense_hdr shdr; if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size, @@ -549,7 +549,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size, shdr.asc, shdr.ascq); } } else if (task->task_status.resp != SAS_TASK_COMPLETE || - task->task_status.stat != SAM_GOOD) { + task->task_status.stat != SAM_STAT_GOOD) { SAS_DPRINTK("task finished with resp:0x%x, " "stat:0x%x\n", task->task_status.resp, diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index c65af02dcfe..83dd5070a15 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -107,7 +107,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size, } } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_GOOD) { + task->task_status.stat == SAM_STAT_GOOD) { res = 0; break; } if (task->task_status.resp == SAS_TASK_COMPLETE && diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index a7890c6d878..f0cfba9a1fc 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -113,10 +113,10 @@ static void sas_scsi_task_done(struct sas_task *task) case SAS_ABORTED_TASK: hs = DID_ABORT; break; - case SAM_CHECK_COND: + case SAM_STAT_CHECK_CONDITION: memcpy(sc->sense_buffer, ts->buf, min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); - stat = SAM_CHECK_COND; + stat = SAM_STAT_CHECK_CONDITION; break; default: stat = ts->stat; diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c index 594524d5bfa..b13a3346894 100644 --- a/drivers/scsi/libsas/sas_task.c +++ b/drivers/scsi/libsas/sas_task.c @@ -15,13 +15,13 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task, else if (iu->datapres == 1) tstat->stat = iu->resp_data[3]; else if (iu->datapres == 2) { - tstat->stat = SAM_CHECK_COND; + tstat->stat = SAM_STAT_CHECK_CONDITION; tstat->buf_valid_size = min_t(int, SAS_STATUS_BUF_SIZE, be32_to_cpu(iu->sense_data_len)); memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size); - if (iu->status != SAM_CHECK_COND) + if (iu->status != SAM_STAT_CHECK_CONDITION) dev_printk(KERN_WARNING, dev, "dev %llx sent sense data, but " "stat(%x) is not CHECK CONDITION\n", @@ -30,7 +30,7 @@ void sas_ssp_task_response(struct device *dev, struct sas_task *task, } else /* when datapres contains corrupt/unknown value... */ - tstat->stat = SAM_CHECK_COND; + tstat->stat = SAM_STAT_CHECK_CONDITION; } EXPORT_SYMBOL_GPL(sas_ssp_task_response); diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index cab92423986..adedaa916ec 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1483,7 +1483,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev, } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_GOOD) { + task->task_status.stat == SAM_STAT_GOOD) { res = TMF_RESP_FUNC_COMPLETE; break; } @@ -1758,7 +1758,7 @@ static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, struct mvs_device *mvi_dev = task->dev->lldd_dev; struct task_status_struct *tstat = &task->task_status; struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; - int stat = SAM_GOOD; + int stat = SAM_STAT_GOOD; resp->frame_len = sizeof(struct dev_to_host_fis); @@ -1790,13 +1790,13 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, MVS_CHIP_DISP->command_active(mvi, slot_idx); - stat = SAM_CHECK_COND; + stat = SAM_STAT_CHECK_CONDITION; switch (task->task_proto) { case SAS_PROTOCOL_SSP: stat = SAS_ABORTED_TASK; break; case SAS_PROTOCOL_SMP: - stat = SAM_CHECK_COND; + stat = SAM_STAT_CHECK_CONDITION; break; case SAS_PROTOCOL_SATA: @@ -1881,7 +1881,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) case SAS_PROTOCOL_SSP: /* hw says status == 0, datapres == 0 */ if (rx_desc & RXQ_GOOD) { - tstat->stat = SAM_GOOD; + tstat->stat = SAM_STAT_GOOD; tstat->resp = SAS_TASK_COMPLETE; } /* response frame present */ @@ -1890,12 +1890,12 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) sizeof(struct mvs_err_info); sas_ssp_task_response(mvi->dev, task, iu); } else - tstat->stat = SAM_CHECK_COND; + tstat->stat = SAM_STAT_CHECK_CONDITION; break; case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; - tstat->stat = SAM_GOOD; + tstat->stat = SAM_STAT_GOOD; to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); memcpy(to + sg_resp->offset, slot->response + sizeof(struct mvs_err_info), @@ -1912,7 +1912,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) } default: - tstat->stat = SAM_CHECK_COND; + tstat->stat = SAM_STAT_CHECK_CONDITION; break; } if (!slot->port->port_attached) { diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 5ff8261c5d6..356ad268de6 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1480,7 +1480,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) ",param = %d \n", param)); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_GOOD; + ts->stat = SAM_STAT_GOOD; } else { ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_PROTO_RESPONSE; @@ -1909,7 +1909,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); if (param == 0) { ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_GOOD; + ts->stat = SAM_STAT_GOOD; } else { u8 len; ts->resp = SAS_TASK_COMPLETE; @@ -2450,7 +2450,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) case IO_SUCCESS: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_GOOD; + ts->stat = SAM_STAT_GOOD; if (pm8001_dev) pm8001_dev->running_req--; break; @@ -2479,19 +2479,19 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_ERROR_HW_TIMEOUT\n")); ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_BUSY; + ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_BREAK: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_XFER_ERROR_BREAK\n")); ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_BUSY; + ts->stat = SAM_STAT_BUSY; break; case IO_XFER_ERROR_PHY_NOT_READY: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_BUSY; + ts->stat = SAM_STAT_BUSY; break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: PM8001_IO_DBG(pm8001_ha, @@ -3260,7 +3260,7 @@ mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) case IO_SUCCESS: PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_GOOD; + ts->stat = SAM_STAT_GOOD; break; case IO_NOT_VALID: PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n")); diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index cd02ceaf67f..6ae059ebb4b 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -763,7 +763,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev, } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_GOOD) { + task->task_status.stat == SAM_STAT_GOOD) { res = TMF_RESP_FUNC_COMPLETE; break; } @@ -853,7 +853,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, } if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_GOOD) { + task->task_status.stat == SAM_STAT_GOOD) { res = TMF_RESP_FUNC_COMPLETE; break; diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 3b586859669..d06e13be717 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -422,16 +422,7 @@ enum service_response { }; enum exec_status { - SAM_GOOD = 0, - SAM_CHECK_COND = 2, - SAM_COND_MET = 4, - SAM_BUSY = 8, - SAM_INTERMEDIATE = 0x10, - SAM_IM_COND_MET = 0x12, - SAM_RESV_CONFLICT= 0x14, - SAM_TASK_SET_FULL= 0x28, - SAM_ACA_ACTIVE = 0x30, - SAM_TASK_ABORTED = 0x40, + /* The SAM_STAT_.. codes fit in the lower 6 bits */ SAS_DEV_NO_RESPONSE = 0x80, SAS_DATA_UNDERRUN, -- cgit v1.2.3-70-g09d2 From db5bd1e0b505c54ff492172ce4abc245cf6cd639 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jun 2010 10:36:49 -0400 Subject: [SCSI] convert to the new PM framework This patch (as1397b) converts the SCSI midlayer to use the new PM callbacks (struct dev_pm_ops). A new source file, scsi_pm.c, is created to hold the new callback routines, and the existing suspend/resume code is moved there. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/Makefile | 1 + drivers/scsi/scsi_pm.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_priv.h | 7 ++++ drivers/scsi/scsi_sysfs.c | 48 +----------------------- 4 files changed, 105 insertions(+), 47 deletions(-) create mode 100644 drivers/scsi/scsi_pm.c diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1c7ac49be64..2a3fca2eca6 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -163,6 +163,7 @@ scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o scsi_mod-y += scsi_trace.o +scsi_mod-$(CONFIG_PM_OPS) += scsi_pm.o scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c new file mode 100644 index 00000000000..cd83758ce0a --- /dev/null +++ b/drivers/scsi/scsi_pm.c @@ -0,0 +1,96 @@ +/* + * scsi_pm.c Copyright (C) 2010 Alan Stern + * + * SCSI dynamic Power Management + * Initial version: Alan Stern + */ + +#include + +#include +#include +#include +#include + +#include "scsi_priv.h" + +static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg) +{ + struct device_driver *drv; + int err; + + err = scsi_device_quiesce(to_scsi_device(dev)); + if (err == 0) { + drv = dev->driver; + if (drv && drv->suspend) + err = drv->suspend(dev, msg); + } + dev_dbg(dev, "scsi suspend: %d\n", err); + return err; +} + +static int scsi_dev_type_resume(struct device *dev) +{ + struct device_driver *drv; + int err = 0; + + drv = dev->driver; + if (drv && drv->resume) + err = drv->resume(dev); + scsi_device_resume(to_scsi_device(dev)); + dev_dbg(dev, "scsi resume: %d\n", err); + return err; +} + +#ifdef CONFIG_PM_SLEEP + +static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg) +{ + int err = 0; + + if (scsi_is_sdev_device(dev)) + err = scsi_dev_type_suspend(dev, msg); + return err; +} + +static int scsi_bus_resume_common(struct device *dev) +{ + int err = 0; + + if (scsi_is_sdev_device(dev)) + err = scsi_dev_type_resume(dev); + return err; +} + +static int scsi_bus_suspend(struct device *dev) +{ + return scsi_bus_suspend_common(dev, PMSG_SUSPEND); +} + +static int scsi_bus_freeze(struct device *dev) +{ + return scsi_bus_suspend_common(dev, PMSG_FREEZE); +} + +static int scsi_bus_poweroff(struct device *dev) +{ + return scsi_bus_suspend_common(dev, PMSG_HIBERNATE); +} + +#else /* CONFIG_PM_SLEEP */ + +#define scsi_bus_resume_common NULL +#define scsi_bus_suspend NULL +#define scsi_bus_freeze NULL +#define scsi_bus_poweroff NULL + +#endif /* CONFIG_PM_SLEEP */ + +const struct dev_pm_ops scsi_bus_pm_ops = { + .suspend = scsi_bus_suspend, + .resume = scsi_bus_resume_common, + .freeze = scsi_bus_freeze, + .thaw = scsi_bus_resume_common, + .poweroff = scsi_bus_poweroff, + .restore = scsi_bus_resume_common, +}; diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 1fbf7c78bba..dddacc73255 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -144,6 +144,13 @@ static inline void scsi_netlink_init(void) {} static inline void scsi_netlink_exit(void) {} #endif +/* scsi_pm.c */ +#ifdef CONFIG_PM_OPS +extern const struct dev_pm_ops scsi_bus_pm_ops; +#else +#define scsi_bus_pm_ops (*NULL) +#endif + /* * internal scsi timeout functions: for use by mid-layer and transport * classes. diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index c23ab978c3b..5f85f8e831f 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -376,57 +376,11 @@ static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -static int scsi_bus_suspend(struct device * dev, pm_message_t state) -{ - struct device_driver *drv; - struct scsi_device *sdev; - int err; - - if (dev->type != &scsi_dev_type) - return 0; - - drv = dev->driver; - sdev = to_scsi_device(dev); - - err = scsi_device_quiesce(sdev); - if (err) - return err; - - if (drv && drv->suspend) { - err = drv->suspend(dev, state); - if (err) - return err; - } - - return 0; -} - -static int scsi_bus_resume(struct device * dev) -{ - struct device_driver *drv; - struct scsi_device *sdev; - int err = 0; - - if (dev->type != &scsi_dev_type) - return 0; - - drv = dev->driver; - sdev = to_scsi_device(dev); - - if (drv && drv->resume) - err = drv->resume(dev); - - scsi_device_resume(sdev); - - return err; -} - struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, - .suspend = scsi_bus_suspend, - .resume = scsi_bus_resume, + .pm = &scsi_bus_pm_ops, }; EXPORT_SYMBOL_GPL(scsi_bus_type); -- cgit v1.2.3-70-g09d2 From bc4f24014de58f045f169742701a6598884d93db Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Jun 2010 10:41:42 -0400 Subject: [SCSI] implement runtime Power Management This patch (as1398b) adds runtime PM support to the SCSI layer. Only the machanism is provided; use of it is up to the various high-level drivers, and the patch doesn't change any of them. Except for sg -- the patch expicitly prevents a device from being runtime-suspended while its sg device file is open. The implementation is simplistic. In general, hosts and targets are automatically suspended when all their children are asleep, but for them the runtime-suspend code doesn't actually do anything. (A host's runtime PM status is propagated up the device tree, though, so a runtime-PM-aware lower-level driver could power down the host adapter hardware at the appropriate times.) There are comments indicating where a transport class might be notified or some other hooks added. LUNs are runtime-suspended by calling the drivers' existing suspend handlers (and likewise for runtime-resume). Somewhat arbitrarily, the implementation delays for 100 ms before suspending an eligible LUN. This is because there typically are occasions during bootup when the same device file is opened and closed several times in quick succession. The way this all works is that the SCSI core increments a device's PM-usage count when it is registered. If a high-level driver does nothing then the device will not be eligible for runtime-suspend because of the elevated usage count. If a high-level driver wants to use runtime PM then it can call scsi_autopm_put_device() in its probe routine to decrement the usage count and scsi_autopm_get_device() in its remove routine to restore the original count. Hosts, targets, and LUNs are not suspended while they are being probed or removed, or while the error handler is running. In fact, a fairly large part of the patch consists of code to make sure that things aren't suspended at such times. [jejb: fix up compile issues in PM config variations] Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 10 ++++- drivers/scsi/scsi_error.c | 16 ++++++- drivers/scsi/scsi_pm.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_priv.h | 14 +++++- drivers/scsi/scsi_scan.c | 24 ++++++++-- drivers/scsi/scsi_sysfs.c | 20 ++++++++- drivers/scsi/sg.c | 10 ++++- include/scsi/scsi_device.h | 8 ++++ 8 files changed, 201 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index a2b1414da28..8a8f803439e 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -156,6 +157,7 @@ EXPORT_SYMBOL(scsi_host_set_state); void scsi_remove_host(struct Scsi_Host *shost) { unsigned long flags; + mutex_lock(&shost->scan_mutex); spin_lock_irqsave(shost->host_lock, flags); if (scsi_host_set_state(shost, SHOST_CANCEL)) @@ -165,6 +167,8 @@ void scsi_remove_host(struct Scsi_Host *shost) return; } spin_unlock_irqrestore(shost->host_lock, flags); + + scsi_autopm_get_host(shost); scsi_forget_host(shost); mutex_unlock(&shost->scan_mutex); scsi_proc_host_rm(shost); @@ -216,12 +220,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, shost->shost_gendev.parent = dev ? dev : &platform_bus; shost->dma_dev = dma_dev; - device_enable_async_suspend(&shost->shost_gendev); - error = device_add(&shost->shost_gendev); if (error) goto out; + pm_runtime_set_active(&shost->shost_gendev); + pm_runtime_enable(&shost->shost_gendev); + device_enable_async_suspend(&shost->shost_gendev); + scsi_host_set_state(shost, SHOST_RUNNING); get_device(shost->shost_gendev.parent); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index c60cffbefa3..2bf98469dc4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1775,6 +1775,14 @@ int scsi_error_handler(void *data) * what we need to do to get it up and online again (if we can). * If we fail, we end up taking the thing offline. */ + if (scsi_autopm_get_host(shost) != 0) { + SCSI_LOG_ERROR_RECOVERY(1, + printk(KERN_ERR "Error handler scsi_eh_%d " + "unable to autoresume\n", + shost->host_no)); + continue; + } + if (shost->transportt->eh_strategy_handler) shost->transportt->eh_strategy_handler(shost); else @@ -1788,6 +1796,7 @@ int scsi_error_handler(void *data) * which are still online. */ scsi_restart_operations(shost); + scsi_autopm_put_host(shost); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); @@ -1885,12 +1894,16 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd) int scsi_reset_provider(struct scsi_device *dev, int flag) { - struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); + struct scsi_cmnd *scmd; struct Scsi_Host *shost = dev->host; struct request req; unsigned long flags; int rtn; + if (scsi_autopm_get_host(shost) < 0) + return FAILED; + + scmd = scsi_get_command(dev, GFP_KERNEL); blk_rq_init(NULL, &req); scmd->request = &req; @@ -1947,6 +1960,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scsi_run_host_queues(shost); scsi_next_command(scmd); + scsi_autopm_put_host(shost); return rtn; } EXPORT_SYMBOL(scsi_reset_provider); diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index cd83758ce0a..d70e91ae60a 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -59,6 +59,12 @@ static int scsi_bus_resume_common(struct device *dev) if (scsi_is_sdev_device(dev)) err = scsi_dev_type_resume(dev); + + if (err == 0) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } return err; } @@ -86,6 +92,107 @@ static int scsi_bus_poweroff(struct device *dev) #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_RUNTIME + +static int scsi_runtime_suspend(struct device *dev) +{ + int err = 0; + + dev_dbg(dev, "scsi_runtime_suspend\n"); + if (scsi_is_sdev_device(dev)) { + err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND); + if (err == -EAGAIN) + pm_schedule_suspend(dev, jiffies_to_msecs( + round_jiffies_up_relative(HZ/10))); + } + + /* Insert hooks here for targets, hosts, and transport classes */ + + return err; +} + +static int scsi_runtime_resume(struct device *dev) +{ + int err = 0; + + dev_dbg(dev, "scsi_runtime_resume\n"); + if (scsi_is_sdev_device(dev)) + err = scsi_dev_type_resume(dev); + + /* Insert hooks here for targets, hosts, and transport classes */ + + return err; +} + +static int scsi_runtime_idle(struct device *dev) +{ + int err; + + dev_dbg(dev, "scsi_runtime_idle\n"); + + /* Insert hooks here for targets, hosts, and transport classes */ + + if (scsi_is_sdev_device(dev)) + err = pm_schedule_suspend(dev, 100); + else + err = pm_runtime_suspend(dev); + return err; +} + +int scsi_autopm_get_device(struct scsi_device *sdev) +{ + int err; + + err = pm_runtime_get_sync(&sdev->sdev_gendev); + if (err < 0) + pm_runtime_put_sync(&sdev->sdev_gendev); + else if (err > 0) + err = 0; + return err; +} +EXPORT_SYMBOL_GPL(scsi_autopm_get_device); + +void scsi_autopm_put_device(struct scsi_device *sdev) +{ + pm_runtime_put_sync(&sdev->sdev_gendev); +} +EXPORT_SYMBOL_GPL(scsi_autopm_put_device); + +void scsi_autopm_get_target(struct scsi_target *starget) +{ + pm_runtime_get_sync(&starget->dev); +} + +void scsi_autopm_put_target(struct scsi_target *starget) +{ + pm_runtime_put_sync(&starget->dev); +} + +int scsi_autopm_get_host(struct Scsi_Host *shost) +{ + int err; + + err = pm_runtime_get_sync(&shost->shost_gendev); + if (err < 0) + pm_runtime_put_sync(&shost->shost_gendev); + else if (err > 0) + err = 0; + return err; +} + +void scsi_autopm_put_host(struct Scsi_Host *shost) +{ + pm_runtime_put_sync(&shost->shost_gendev); +} + +#else + +#define scsi_runtime_suspend NULL +#define scsi_runtime_resume NULL +#define scsi_runtime_idle NULL + +#endif /* CONFIG_PM_RUNTIME */ + const struct dev_pm_ops scsi_bus_pm_ops = { .suspend = scsi_bus_suspend, .resume = scsi_bus_resume_common, @@ -93,4 +200,7 @@ const struct dev_pm_ops scsi_bus_pm_ops = { .thaw = scsi_bus_resume_common, .poweroff = scsi_bus_poweroff, .restore = scsi_bus_resume_common, + .runtime_suspend = scsi_runtime_suspend, + .runtime_resume = scsi_runtime_resume, + .runtime_idle = scsi_runtime_idle, }; diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index dddacc73255..026295e2c53 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -7,6 +7,7 @@ struct request_queue; struct request; struct scsi_cmnd; struct scsi_device; +struct scsi_target; struct scsi_host_template; struct Scsi_Host; struct scsi_nl_hdr; @@ -147,9 +148,20 @@ static inline void scsi_netlink_exit(void) {} /* scsi_pm.c */ #ifdef CONFIG_PM_OPS extern const struct dev_pm_ops scsi_bus_pm_ops; -#else +#else /* CONFIG_PM_OPS */ #define scsi_bus_pm_ops (*NULL) #endif +#ifdef CONFIG_PM_RUNTIME +extern void scsi_autopm_get_target(struct scsi_target *); +extern void scsi_autopm_put_target(struct scsi_target *); +extern int scsi_autopm_get_host(struct Scsi_Host *); +extern void scsi_autopm_put_host(struct Scsi_Host *); +#else +static inline void scsi_autopm_get_target(struct scsi_target *t) {} +static inline void scsi_autopm_put_target(struct scsi_target *t) {} +static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; } +static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} +#endif /* CONFIG_PM_RUNTIME */ /* * internal scsi timeout functions: for use by mid-layer and transport diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1c027a97d8b..3d0a1e6e9c4 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1513,14 +1513,18 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, starget = scsi_alloc_target(parent, channel, id); if (!starget) return ERR_PTR(-ENOMEM); + scsi_autopm_get_target(starget); mutex_lock(&shost->scan_mutex); if (!shost->async_scan) scsi_complete_async_scans(); - if (scsi_host_scan_allowed(shost)) + if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); + scsi_autopm_put_host(shost); + } mutex_unlock(&shost->scan_mutex); + scsi_autopm_put_target(starget); scsi_target_reap(starget); put_device(&starget->dev); @@ -1574,6 +1578,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, starget = scsi_alloc_target(parent, channel, id); if (!starget) return; + scsi_autopm_get_target(starget); if (lun != SCAN_WILD_CARD) { /* @@ -1599,6 +1604,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, } out_reap: + scsi_autopm_put_target(starget); /* now determine if the target has any children at all * and if not, nuke it */ scsi_target_reap(starget); @@ -1633,8 +1639,10 @@ void scsi_scan_target(struct device *parent, unsigned int channel, if (!shost->async_scan) scsi_complete_async_scans(); - if (scsi_host_scan_allowed(shost)) + if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { __scsi_scan_target(parent, channel, id, lun, rescan); + scsi_autopm_put_host(shost); + } mutex_unlock(&shost->scan_mutex); } EXPORT_SYMBOL(scsi_scan_target); @@ -1686,7 +1694,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, if (!shost->async_scan) scsi_complete_async_scans(); - if (scsi_host_scan_allowed(shost)) { + if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { if (channel == SCAN_WILD_CARD) for (channel = 0; channel <= shost->max_channel; channel++) @@ -1694,6 +1702,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, rescan); else scsi_scan_channel(shost, channel, id, lun, rescan); + scsi_autopm_put_host(shost); } mutex_unlock(&shost->scan_mutex); @@ -1831,8 +1840,11 @@ static void do_scsi_scan_host(struct Scsi_Host *shost) static int do_scan_async(void *_data) { struct async_scan_data *data = _data; - do_scsi_scan_host(data->shost); + struct Scsi_Host *shost = data->shost; + + do_scsi_scan_host(shost); scsi_finish_async_scan(data); + scsi_autopm_put_host(shost); return 0; } @@ -1847,16 +1859,20 @@ void scsi_scan_host(struct Scsi_Host *shost) if (strncmp(scsi_scan_type, "none", 4) == 0) return; + if (scsi_autopm_get_host(shost) < 0) + return; data = scsi_prep_async_scan(shost); if (!data) { do_scsi_scan_host(shost); + scsi_autopm_put_host(shost); return; } p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); if (IS_ERR(p)) do_scan_async(data); + /* scsi_autopm_put_host(shost) is called in do_scan_async() */ } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 5f85f8e831f..562fb3bce26 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -802,8 +803,6 @@ static int scsi_target_add(struct scsi_target *starget) if (starget->state != STARGET_CREATED) return 0; - device_enable_async_suspend(&starget->dev); - error = device_add(&starget->dev); if (error) { dev_err(&starget->dev, "target device_add failed, error %d\n", error); @@ -812,6 +811,10 @@ static int scsi_target_add(struct scsi_target *starget) transport_add_device(&starget->dev); starget->state = STARGET_RUNNING; + pm_runtime_set_active(&starget->dev); + pm_runtime_enable(&starget->dev); + device_enable_async_suspend(&starget->dev); + return 0; } @@ -841,7 +844,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) return error; transport_configure_device(&starget->dev); + device_enable_async_suspend(&sdev->sdev_gendev); + scsi_autopm_get_target(starget); + pm_runtime_set_active(&sdev->sdev_gendev); + pm_runtime_forbid(&sdev->sdev_gendev); + pm_runtime_enable(&sdev->sdev_gendev); + scsi_autopm_put_target(starget); + + /* The following call will keep sdev active indefinitely, until + * its driver does a corresponding scsi_autopm_pm_device(). Only + * drivers supporting autosuspend will do this. + */ + scsi_autopm_get_device(sdev); + error = device_add(&sdev->sdev_gendev); if (error) { printk(KERN_INFO "error 1\n"); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index d4549092400..2968c6b83dd 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -245,6 +245,10 @@ sg_open(struct inode *inode, struct file *filp) if (retval) goto sg_put; + retval = scsi_autopm_get_device(sdp->device); + if (retval) + goto sdp_put; + if (!((flags & O_NONBLOCK) || scsi_block_when_processing_errors(sdp->device))) { retval = -ENXIO; @@ -302,8 +306,11 @@ sg_open(struct inode *inode, struct file *filp) } retval = 0; error_out: - if (retval) + if (retval) { + scsi_autopm_put_device(sdp->device); +sdp_put: scsi_device_put(sdp->device); + } sg_put: if (sdp) sg_put_dev(sdp); @@ -327,6 +334,7 @@ sg_release(struct inode *inode, struct file *filp) sdp->exclude = 0; wake_up_interruptible(&sdp->o_excl_wait); + scsi_autopm_put_device(sdp->device); kref_put(&sfp->f_ref, sg_remove_sfp); return 0; } diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index d80b6dbed1c..50cb34ffef1 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -381,6 +381,14 @@ extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, struct scsi_sense_hdr *, int timeout, int retries, int *resid); +#ifdef CONFIG_PM_RUNTIME +extern int scsi_autopm_get_device(struct scsi_device *); +extern void scsi_autopm_put_device(struct scsi_device *); +#else +static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; } +static inline void scsi_autopm_put_device(struct scsi_device *d) {} +#endif /* CONFIG_PM_RUNTIME */ + static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) { return device_reprobe(&sdev->sdev_gendev); -- cgit v1.2.3-70-g09d2 From 478a8a0543021172220feeb0b39bb1b3e43c988f Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 16 Jun 2010 14:52:17 -0400 Subject: [SCSI] sd: add support for runtime PM This patch (as1399) adds runtime-PM support to the sd driver. The support is unsophisticated: If a SCSI disk device is mounted, or if its device file is held open, then the device will not be runtime-suspended; otherwise it will (provided userspace gives permission by writing "auto" to the sysfs power/control attribute). In order to make this work, a dev_set_drvdata() call had to be moved from sd_probe_async() to sd_probe(). Also, a few lines of code were changed to use a local variable instead of recalculating the address of an embedded struct device. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8802e48bc06..cc8a1d1d915 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -759,6 +759,10 @@ static int sd_open(struct block_device *bdev, fmode_t mode) sdev = sdkp->device; + retval = scsi_autopm_get_device(sdev); + if (retval) + goto error_autopm; + /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. @@ -803,6 +807,8 @@ static int sd_open(struct block_device *bdev, fmode_t mode) return 0; error_out: + scsi_autopm_put_device(sdev); +error_autopm: scsi_disk_put(sdkp); return retval; } @@ -834,6 +840,8 @@ static int sd_release(struct gendisk *disk, fmode_t mode) * XXX and what if there are packets in flight and this close() * XXX is followed by a "rmmod sd_mod"? */ + + scsi_autopm_put_device(sdev); scsi_disk_put(sdkp); return 0; } @@ -2232,7 +2240,6 @@ static void sd_probe_async(void *data, async_cookie_t cookie) if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; - dev_set_drvdata(dev, sdkp); add_disk(gd); sd_dif_config_host(sdkp); @@ -2240,6 +2247,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); + scsi_autopm_put_device(sdp); put_device(&sdkp->dev); } @@ -2317,14 +2325,15 @@ static int sd_probe(struct device *dev) } device_initialize(&sdkp->dev); - sdkp->dev.parent = &sdp->sdev_gendev; + sdkp->dev.parent = dev; sdkp->dev.class = &sd_disk_class; - dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); + dev_set_name(&sdkp->dev, dev_name(dev)); if (device_add(&sdkp->dev)) goto out_free_index; - get_device(&sdp->sdev_gendev); + get_device(dev); + dev_set_drvdata(dev, sdkp); get_device(&sdkp->dev); /* prevent release before async_schedule */ async_schedule(sd_probe_async, sdkp); @@ -2358,8 +2367,10 @@ static int sd_remove(struct device *dev) { struct scsi_disk *sdkp; - async_synchronize_full(); sdkp = dev_get_drvdata(dev); + scsi_autopm_get_device(sdkp->device); + + async_synchronize_full(); blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); device_del(&sdkp->dev); del_gendisk(sdkp->disk); -- cgit v1.2.3-70-g09d2 From 5767620c383a226e39891e7e654a70ebb8e95e69 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:05 +0200 Subject: [SCSI] zfcp: Do not unblock rport from REOPEN_PORT_FORCED When the REOPEN_PORT_FORCED erp action succeeds, the port has been closed. A REOPEN_PORT will try to open the port after the REPORT_PORT_FORCED. The rport should only be unblocked after the successful completion of the reopen port. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index fd068bc1bd0..c663eb2ecf3 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1197,10 +1197,11 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) put_device(&unit->dev); break; - case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: if (result == ZFCP_ERP_SUCCEEDED) zfcp_scsi_schedule_rport_register(port); + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: put_device(&port->dev); break; -- cgit v1.2.3-70-g09d2 From 097ef3bd0cd4f156fee039e52855d095b7ba3db4 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:06 +0200 Subject: [SCSI] zfcp: Do not try "forced close" when port is already closed When the port is already "physically closed" try the reopen instead. There is no way to send a "physically close" to an already closed port. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c663eb2ecf3..5a71b73211d 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -141,8 +141,12 @@ static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_PORT; /* fall through */ - case ZFCP_ERP_ACTION_REOPEN_PORT: case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + p_status = atomic_read(&port->status); + if (!(p_status & ZFCP_STATUS_COMMON_OPEN)) + need = ZFCP_ERP_ACTION_REOPEN_PORT; + /* fall through */ + case ZFCP_ERP_ACTION_REOPEN_PORT: p_status = atomic_read(&port->status); if (p_status & ZFCP_STATUS_COMMON_ERP_INUSE) return 0; -- cgit v1.2.3-70-g09d2 From 5a7de559b4e0169ff4cfca654b4e4f0014996e57 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:07 +0200 Subject: [SCSI] zfcp: Register SCSI devices after successful fc_remote_port_add When the successful return of an adisc is the final step to set the port online, the registration of SCSI devices might be omitted. SCSI devices that have been removed before (due to a short dev_loss_tmo setting) might not be attached again. The problem is that the registration of SCSI devices is done only after erp has finished. The correct place would be after the call to fc_remote_port_add to mimick the scan in the FC transport class. Change the registration of SCSI devices to be triggered after the fc_remote_port_add call. For the initial inquiry command to succeed, the unit must also be open. If the unit reopen is still pending, the inquiry command to the LUN will be deferred with DID_IMM_RETRY, so there is no harm from this approach. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 6 ------ drivers/s390/scsi/zfcp_ext.h | 3 ++- drivers/s390/scsi/zfcp_scsi.c | 37 +++++++++++++++++++++++++++++-------- drivers/s390/scsi/zfcp_sysfs.c | 2 +- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index e331df2122f..6e9c7f33e27 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -314,7 +314,7 @@ struct zfcp_unit *zfcp_unit_enqueue(struct zfcp_port *port, u64 fcp_lun) } retval = -EINVAL; - INIT_WORK(&unit->scsi_work, zfcp_scsi_scan); + INIT_WORK(&unit->scsi_work, zfcp_scsi_scan_work); spin_lock_init(&unit->latencies.lock); unit->latencies.write.channel.min = 0xFFFFFFFF; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 5a71b73211d..03cd6365ed0 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1192,12 +1192,6 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) switch (act->action) { case ZFCP_ERP_ACTION_REOPEN_UNIT: - if ((result == ZFCP_ERP_SUCCEEDED) && !unit->device) { - get_device(&unit->dev); - if (scsi_queue_work(unit->port->adapter->scsi_host, - &unit->scsi_work) <= 0) - put_device(&unit->dev); - } put_device(&unit->dev); break; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 48a8f93b72f..6abe2909e75 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -159,7 +159,8 @@ extern void zfcp_scsi_rport_work(struct work_struct *); extern void zfcp_scsi_schedule_rport_register(struct zfcp_port *); extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); -extern void zfcp_scsi_scan(struct work_struct *); +extern void zfcp_scsi_scan(struct zfcp_unit *); +extern void zfcp_scsi_scan_work(struct work_struct *); /* zfcp_sysfs.c */ extern struct attribute_group zfcp_sysfs_unit_attrs; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index be5d2c60453..153f69b26e7 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -524,6 +524,20 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) } } +static void zfcp_scsi_queue_unit_register(struct zfcp_port *port) +{ + struct zfcp_unit *unit; + + read_lock_irq(&port->unit_list_lock); + list_for_each_entry(unit, &port->unit_list, list) { + get_device(&unit->dev); + if (scsi_queue_work(port->adapter->scsi_host, + &unit->scsi_work) <= 0) + put_device(&unit->dev); + } + read_unlock_irq(&port->unit_list_lock); +} + static void zfcp_scsi_rport_register(struct zfcp_port *port) { struct fc_rport_identifiers ids; @@ -548,6 +562,8 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) rport->maxframe_size = port->maxframe_size; rport->supported_classes = port->supported_classes; port->rport = rport; + + zfcp_scsi_queue_unit_register(port); } static void zfcp_scsi_rport_block(struct zfcp_port *port) @@ -610,21 +626,26 @@ void zfcp_scsi_rport_work(struct work_struct *work) put_device(&port->dev); } - -void zfcp_scsi_scan(struct work_struct *work) +/** + * zfcp_scsi_scan - Register LUN with SCSI midlayer + * @unit: The LUN/unit to register + */ +void zfcp_scsi_scan(struct zfcp_unit *unit) { - struct zfcp_unit *unit = container_of(work, struct zfcp_unit, - scsi_work); - struct fc_rport *rport; - - flush_work(&unit->port->rport_work); - rport = unit->port->rport; + struct fc_rport *rport = unit->port->rport; if (rport && rport->port_state == FC_PORTSTATE_ONLINE) scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, scsilun_to_int((struct scsi_lun *) &unit->fcp_lun), 0); +} + +void zfcp_scsi_scan_work(struct work_struct *work) +{ + struct zfcp_unit *unit = container_of(work, struct zfcp_unit, + scsi_work); + zfcp_scsi_scan(unit); put_device(&unit->dev); } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index f5f60698dc4..205b9f8056e 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -275,7 +275,7 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev, zfcp_erp_unit_reopen(unit, 0, "syuas_1", NULL); zfcp_erp_wait(unit->port->adapter); - flush_work(&unit->scsi_work); + zfcp_scsi_scan(unit); out: put_device(&port->dev); return retval ? retval : (ssize_t) count; -- cgit v1.2.3-70-g09d2 From 835dc29887073eec7817559a07558f955383d099 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:08 +0200 Subject: [SCSI] zfcp: Use forced_reopen in terminate_rport_io callback When running in non-NPIV mode, the port_reopen in terminate_rport_io might succeed even though the remote port is not available. If the same port connection is held open from another operating system, the reopen is only a virtual operation and might not hit the SAN. Fix this by changing the call to forced_reopen that forces a logout/login operation in the SAN. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_scsi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 153f69b26e7..4cab33a2f7b 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -506,8 +506,10 @@ static void zfcp_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) * @rport: The FC rport where to teminate I/O * * Abort all pending SCSI commands for a port by closing the - * port. Using a reopen avoiding a conflict with a shutdown - * overwriting a reopen. + * port. Using a reopen avoids a conflict with a shutdown + * overwriting a reopen. The "forced" ensures that a disappeared port + * is not opened again as valid due to the cached plogi data in + * non-NPIV mode. */ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) { @@ -519,7 +521,7 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) port = zfcp_get_port_by_wwpn(adapter, rport->port_name); if (port) { - zfcp_erp_port_reopen(port, 0, "sctrpi1", NULL); + zfcp_erp_port_forced_reopen(port, 0, "sctrpi1", NULL); put_device(&port->dev); } } -- cgit v1.2.3-70-g09d2 From 9c785d944e6fa7eef390c799b93e43243505780c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:09 +0200 Subject: [SCSI] zfcp: Fail erp after timeout After a timeout notification, do not try to run the erp strategy. Return from the erp with "failed" to possibly trigger a retry. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 03cd6365ed0..64471ba6ac0 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1246,6 +1246,11 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) goto unlock; } + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { + retval = ZFCP_ERP_FAILED; + goto check_target; + } + zfcp_erp_action_to_running(erp_action); /* no lock to allow for blocking operations */ @@ -1278,6 +1283,7 @@ static int zfcp_erp_strategy(struct zfcp_erp_action *erp_action) goto unlock; } +check_target: retval = zfcp_erp_strategy_check_target(erp_action, retval); zfcp_erp_action_dequeue(erp_action); retval = zfcp_erp_strategy_statechange(erp_action, retval); -- cgit v1.2.3-70-g09d2 From f7bd7c3627a3cf06bf1c6da55339469ec1853a48 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 8 Jul 2010 09:53:10 +0200 Subject: [SCSI] zfcp: Fix retry after failed "open port" erp action Trying to enqueue a port erp action from the port erp strategy will fail in zfcp_erp_required_act. To try the same action again, return ZFCP_ERP_FAILED. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_erp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 64471ba6ac0..160b432c907 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -897,8 +897,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) } if (port->d_id && !(p_status & ZFCP_STATUS_COMMON_NOESC)) { port->d_id = 0; - _zfcp_erp_port_reopen(port, 0, "erpsoc1", NULL); - return ZFCP_ERP_EXIT; + return ZFCP_ERP_FAILED; } /* fall through otherwise */ } -- cgit v1.2.3-70-g09d2 From 674c3a993c278b7469e1cf12bfc13e6838dfd877 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 16 Jul 2010 15:37:34 +0200 Subject: [SCSI] zfcp: Use memdup_user and kstrdup Use the functions memdup_user and kstrdup to allocate memory and copy the data in one step, saving some lines of code. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 +--- drivers/s390/scsi/zfcp_cfdc.c | 12 +++--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 6e9c7f33e27..7c01c4c3f6b 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -98,13 +98,11 @@ static void __init zfcp_init_device_setup(char *devstr) u64 wwpn, lun; /* duplicate devstr and keep the original for sysfs presentation*/ - str_saved = kmalloc(strlen(devstr) + 1, GFP_KERNEL); + str_saved = kstrdup(devstr, GFP_KERNEL); str = str_saved; if (!str) return; - strcpy(str, devstr); - token = strsep(&str, ","); if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) goto err_out; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 1a2db0a3573..fcbd2b756da 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -189,18 +189,12 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, if (!fsf_cfdc) return -ENOMEM; - data = kmalloc(sizeof(struct zfcp_cfdc_data), GFP_KERNEL); - if (!data) { - retval = -ENOMEM; + data = memdup_user(data_user, sizeof(*data_user)); + if (IS_ERR(data)) { + retval = PTR_ERR(data); goto no_mem_sense; } - retval = copy_from_user(data, data_user, sizeof(*data)); - if (retval) { - retval = -EFAULT; - goto free_buffer; - } - if (data->signature != 0xCFDCACDF) { retval = -EINVAL; goto free_buffer; -- cgit v1.2.3-70-g09d2 From 1bf3ff02ca6247b2d7c9ebda93002392bf60a61d Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 16 Jul 2010 15:37:35 +0200 Subject: [SCSI] zfcp: Remove SCSI device when removing unit Configuring a LUN in zfcp, also creates a SCSI device. For consistency, it makes sense to remove the SCSI device when the LUN is deconfigured. Replace the flush_work with the call to scsi_remove_device: scsi_remove_device also takes the scan_mutex that synchronizes itself with any long running device discovery. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_scsi.c | 1 + drivers/s390/scsi/zfcp_sysfs.c | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9fa1b064893..86a8725430a 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -212,6 +212,7 @@ struct zfcp_port { struct work_struct test_link_work; struct work_struct rport_work; enum { RPORT_NONE, RPORT_ADD, RPORT_DEL } rport_task; + unsigned int starget_id; }; struct zfcp_unit { diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 4cab33a2f7b..9d117ee7159 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -564,6 +564,7 @@ static void zfcp_scsi_rport_register(struct zfcp_port *port) rport->maxframe_size = port->maxframe_size; rport->supported_classes = port->supported_classes; port->rport = rport; + port->starget_id = rport->scsi_target_id; zfcp_scsi_queue_unit_register(port); } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 205b9f8056e..b4561c86e23 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -290,6 +290,7 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, struct zfcp_unit *unit; u64 fcp_lun; int retval = -EINVAL; + struct scsi_device *sdev; if (!(port && get_device(&port->dev))) return -EBUSY; @@ -303,8 +304,13 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev, else retval = 0; - /* wait for possible timeout during SCSI probe */ - flush_work(&unit->scsi_work); + sdev = scsi_device_lookup(port->adapter->scsi_host, 0, + port->starget_id, + scsilun_to_int((struct scsi_lun *)&fcp_lun)); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } write_lock_irq(&port->unit_list_lock); list_del(&unit->list); -- cgit v1.2.3-70-g09d2 From faf4cd854203b26527d81e7e13d66e78774dad44 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 16 Jul 2010 15:37:36 +0200 Subject: [SCSI] zfcp: Use correct width for timer_interval field The timer_interval is 14 bits in width. Introduce a define for properly masking the value. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_fsf.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 71663fb7731..ee0c1df8a6d 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -495,7 +495,7 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; adapter->hydra_version = bottom->adapter_type; - adapter->timer_ticks = bottom->timer_interval; + adapter->timer_ticks = bottom->timer_interval & ZFCP_FSF_TIMER_INT_MASK; adapter->stat_read_buf_num = max(bottom->status_read_buf_num, (u16)FSF_STATUS_READS_RECOM); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 519083fd6e8..ca45e32d6b6 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -352,6 +352,8 @@ struct fsf_qtcb_bottom_support { u8 els[256]; } __attribute__ ((packed)); +#define ZFCP_FSF_TIMER_INT_MASK 0x3FFF + struct fsf_qtcb_bottom_config { u32 lic_version; u32 feature_selection; -- cgit v1.2.3-70-g09d2 From 01b047599ade30051bf6c14fbe64181d1fec3dfa Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Fri, 16 Jul 2010 15:37:37 +0200 Subject: [SCSI] zfcp: Cleanup function parameters for sbal value. A lot of functions require the amount of SBALs as one of their parameter which is most times invariable. Therefore remove this parameter and set the SBAL value explicitly if a non standard value is required. In addition the warning message "oversized data" is replaced with a BUG_ON() statement assuring the limits defined and requested by zfcp. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_ext.h | 2 +- drivers/s390/scsi/zfcp_fsf.c | 40 ++++++++++++++-------------------------- drivers/s390/scsi/zfcp_fsf.h | 8 -------- drivers/s390/scsi/zfcp_qdio.c | 15 ++------------- drivers/s390/scsi/zfcp_qdio.h | 28 ++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_scsi.c | 4 ++-- 6 files changed, 47 insertions(+), 50 deletions(-) diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 6abe2909e75..3aab0f5544d 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -146,7 +146,7 @@ extern void zfcp_qdio_destroy(struct zfcp_qdio *); extern int zfcp_qdio_sbal_get(struct zfcp_qdio *); extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *); extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *, - struct scatterlist *, int); + struct scatterlist *); extern int zfcp_qdio_open(struct zfcp_qdio *); extern void zfcp_qdio_close(struct zfcp_qdio *); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index ee0c1df8a6d..5f502c9cb06 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -959,8 +959,7 @@ static void zfcp_fsf_setup_ct_els_unchained(struct zfcp_qdio *qdio, static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, struct scatterlist *sg_req, - struct scatterlist *sg_resp, - int max_sbals) + struct scatterlist *sg_resp) { struct zfcp_adapter *adapter = req->adapter; u32 feat = adapter->adapter_features; @@ -983,15 +982,14 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, return 0; } - bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, - sg_req, max_sbals); + bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); if (bytes <= 0) return -EIO; req->qtcb->bottom.support.req_buf_length = bytes; zfcp_qdio_skip_to_last_sbale(&req->qdio_req); bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, - sg_resp, max_sbals); + sg_resp); req->qtcb->bottom.support.resp_buf_length = bytes; if (bytes <= 0) return -EIO; @@ -1002,11 +1000,11 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req, struct scatterlist *sg_req, struct scatterlist *sg_resp, - int max_sbals, unsigned int timeout) + unsigned int timeout) { int ret; - ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals); + ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp); if (ret) return ret; @@ -1046,8 +1044,7 @@ int zfcp_fsf_send_ct(struct zfcp_fc_wka_port *wka_port, } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, - ZFCP_FSF_MAX_SBALS_PER_REQ, timeout); + ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp, timeout); if (ret) goto failed_send; @@ -1143,7 +1140,10 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, } req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; - ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2, timeout); + + zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2); + + ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout); if (ret) goto failed_send; @@ -2259,20 +2259,9 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, - scsi_sglist(scsi_cmnd), - ZFCP_FSF_MAX_SBALS_PER_REQ); - if (unlikely(real_bytes < 0)) { - if (req->qdio_req.sbal_number >= ZFCP_FSF_MAX_SBALS_PER_REQ) { - dev_err(&adapter->ccw_device->dev, - "Oversize data package, unit 0x%016Lx " - "on port 0x%016Lx closed\n", - (unsigned long long)unit->fcp_lun, - (unsigned long long)unit->port->wwpn); - zfcp_erp_unit_shutdown(unit, 0, "fssfct1", req); - retval = -EINVAL; - } + scsi_sglist(scsi_cmnd)); + if (unlikely(real_bytes < 0)) goto failed_scsi_cmnd; - } retval = zfcp_fsf_req_send(req); if (unlikely(retval)) @@ -2391,9 +2380,8 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; bottom->option = fsf_cfdc->option; - bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, - fsf_cfdc->sg, - ZFCP_FSF_MAX_SBALS_PER_REQ); + bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg); + if (bytes != ZFCP_CFDC_MAX_SIZE) { zfcp_fsf_req_free(req); goto out; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index ca45e32d6b6..ca110e38676 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -151,14 +151,6 @@ /* fc service class */ #define FSF_CLASS_3 0x00000003 -/* SBAL chaining */ -#define ZFCP_FSF_MAX_SBALS_PER_REQ 36 - -/* max. number of (data buffer) SBALEs in largest SBAL chain - * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ -#define ZFCP_FSF_MAX_SBALES_PER_REQ \ - (ZFCP_FSF_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2) - /* logging space behind QTCB */ #define FSF_QTCB_LOG_SIZE 1024 diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 6fa5e045317..7ab1ac16a11 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -141,15 +141,6 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, zfcp_qdio_resp_put_back(qdio, count); } -static void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, - struct zfcp_qdio_req *q_req, int max_sbals) -{ - int count = atomic_read(&qdio->req_q.count); - count = min(count, max_sbals); - q_req->sbal_limit = (q_req->sbal_first + count - 1) - % QDIO_MAX_BUFFERS_PER_Q; -} - static struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { @@ -173,6 +164,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) /* keep this requests number of SBALs up-to-date */ q_req->sbal_number++; + BUG_ON(q_req->sbal_number > ZFCP_QDIO_MAX_SBALS_PER_REQ); /* start at first SBALE of new SBAL */ q_req->sbale_curr = 0; @@ -213,14 +205,11 @@ static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio, * Returns: number of bytes, or error (negativ) */ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, - struct scatterlist *sg, int max_sbals) + struct scatterlist *sg) { struct qdio_buffer_element *sbale; int bytes = 0; - /* figure out last allowed SBAL */ - zfcp_qdio_sbal_limit(qdio, q_req, max_sbals); - /* set storage-block type for this request */ sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->flags |= q_req->sbtype; diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 138fba577b4..8bb00545f19 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -19,6 +19,14 @@ /* index of last SBALE (with respect to DMQ bug workaround) */ #define ZFCP_QDIO_LAST_SBALE_PER_SBAL (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1) +/* Max SBALS for chaining */ +#define ZFCP_QDIO_MAX_SBALS_PER_REQ 36 + +/* max. number of (data buffer) SBALEs in largest SBAL chain + * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ +#define ZFCP_QDIO_MAX_SBALES_PER_REQ \ + (ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2) + /** * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count * @sbal: qdio buffers @@ -134,10 +142,14 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, unsigned long req_id, u32 sbtype, void *data, u32 len) { struct qdio_buffer_element *sbale; + int count = min(atomic_read(&qdio->req_q.count), + ZFCP_QDIO_MAX_SBALS_PER_REQ); q_req->sbal_first = q_req->sbal_last = qdio->req_q.first; q_req->sbal_number = 1; q_req->sbtype = sbtype; + q_req->sbal_limit = (q_req->sbal_first + count - 1) + % QDIO_MAX_BUFFERS_PER_Q; sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->addr = (void *) req_id; @@ -210,4 +222,20 @@ void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req) q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL; } +/** + * zfcp_qdio_sbal_limit - set the sbal limit for a request in q_req + * @qdio: pointer to struct zfcp_qdio + * @q_req: The current zfcp_qdio_req + * @max_sbals: maximum number of SBALs allowed + */ +static inline +void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, + struct zfcp_qdio_req *q_req, int max_sbals) +{ + int count = min(atomic_read(&qdio->req_q.count), max_sbals); + + q_req->sbal_limit = (q_req->sbal_first + count - 1) % + QDIO_MAX_BUFFERS_PER_Q; +} + #endif /* ZFCP_QDIO_H */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 9d117ee7159..eb471a1723c 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -701,11 +701,11 @@ struct zfcp_data zfcp_data = { .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .can_queue = 4096, .this_id = -1, - .sg_tablesize = ZFCP_FSF_MAX_SBALES_PER_REQ, + .sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ, .cmd_per_lun = 1, .use_clustering = 1, .sdev_attrs = zfcp_sysfs_sdev_attrs, - .max_sectors = (ZFCP_FSF_MAX_SBALES_PER_REQ * 8), + .max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8), .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, .shost_attrs = zfcp_sysfs_shost_attrs, }, -- cgit v1.2.3-70-g09d2 From 706eca49a044a1ea89352dcc4b96ffc1631b2cb5 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Fri, 16 Jul 2010 15:37:38 +0200 Subject: [SCSI] zfcp: Cleanup QDIO attachment and improve processing. Some definitions and structures in the zfcp QDIO processing are improved by the removal of not required variables and processing steps. I addition the naming of some variables is changed to make their purpose more clear. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_fsf.c | 10 ++- drivers/s390/scsi/zfcp_qdio.c | 141 ++++++++++++++---------------------------- drivers/s390/scsi/zfcp_qdio.h | 57 +++++------------ 3 files changed, 69 insertions(+), 139 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5f502c9cb06..0710c59b80a 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -732,7 +732,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) zfcp_reqlist_add(adapter->req_list, req); - req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q.count); + req->qdio_req.qdio_outb_usage = atomic_read(&qdio->req_q_free); req->issued = get_clock(); if (zfcp_qdio_send(qdio, &req->qdio_req)) { del_timer(&req->timer); @@ -2025,7 +2025,7 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) blktrc.magic = ZFCP_BLK_DRV_DATA_MAGIC; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) blktrc.flags |= ZFCP_BLK_REQ_ERROR; - blktrc.inb_usage = req->qdio_req.qdio_inb_usage; + blktrc.inb_usage = 0; blktrc.outb_usage = req->qdio_req.qdio_outb_usage; if (req->adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA && @@ -2207,7 +2207,7 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, return -EBUSY; spin_lock(&qdio->req_q_lock); - if (atomic_read(&qdio->req_q.count) <= 0) { + if (atomic_read(&qdio->req_q_free) <= 0) { atomic_inc(&qdio->req_q_full); goto out; } @@ -2407,7 +2407,7 @@ out: void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) { struct zfcp_adapter *adapter = qdio->adapter; - struct qdio_buffer *sbal = qdio->resp_q.sbal[sbal_idx]; + struct qdio_buffer *sbal = qdio->res_q[sbal_idx]; struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; unsigned long req_id; @@ -2428,8 +2428,6 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) req_id, dev_name(&adapter->ccw_device->dev)); fsf_req->qdio_req.sbal_response = sbal_idx; - fsf_req->qdio_req.qdio_inb_usage = - atomic_read(&qdio->resp_q.count); zfcp_fsf_req_complete(fsf_req); if (likely(sbale->flags & SBAL_FLAGS_LAST_ENTRY)) diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 7ab1ac16a11..a638278c602 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -55,71 +55,46 @@ static void zfcp_qdio_zero_sbals(struct qdio_buffer *sbal[], int first, int cnt) static inline void zfcp_qdio_account(struct zfcp_qdio *qdio) { unsigned long long now, span; - int free, used; + int used; spin_lock(&qdio->stat_lock); now = get_clock_monotonic(); span = (now - qdio->req_q_time) >> 12; - free = atomic_read(&qdio->req_q.count); - used = QDIO_MAX_BUFFERS_PER_Q - free; + used = QDIO_MAX_BUFFERS_PER_Q - atomic_read(&qdio->req_q_free); qdio->req_q_util += used * span; qdio->req_q_time = now; spin_unlock(&qdio->stat_lock); } static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, - int queue_no, int first, int count, + int queue_no, int idx, int count, unsigned long parm) { struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; - struct zfcp_qdio_queue *queue = &qdio->req_q; if (unlikely(qdio_err)) { - zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, - count); + zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); zfcp_qdio_handler_error(qdio, "qdireq1"); return; } /* cleanup all SBALs being program-owned now */ - zfcp_qdio_zero_sbals(queue->sbal, first, count); + zfcp_qdio_zero_sbals(qdio->req_q, idx, count); zfcp_qdio_account(qdio); - atomic_add(count, &queue->count); + atomic_add(count, &qdio->req_q_free); wake_up(&qdio->req_q_wq); } -static void zfcp_qdio_resp_put_back(struct zfcp_qdio *qdio, int processed) -{ - struct zfcp_qdio_queue *queue = &qdio->resp_q; - struct ccw_device *cdev = qdio->adapter->ccw_device; - u8 count, start = queue->first; - unsigned int retval; - - count = atomic_read(&queue->count) + processed; - - retval = do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, start, count); - - if (unlikely(retval)) { - atomic_set(&queue->count, count); - zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdrpb_1", NULL); - } else { - queue->first += count; - queue->first %= QDIO_MAX_BUFFERS_PER_Q; - atomic_set(&queue->count, 0); - } -} - static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, - int queue_no, int first, int count, + int queue_no, int idx, int count, unsigned long parm) { struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; int sbal_idx, sbal_no; if (unlikely(qdio_err)) { - zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, first, - count); + zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); zfcp_qdio_handler_error(qdio, "qdires1"); return; } @@ -129,16 +104,16 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, * returned by QDIO layer */ for (sbal_no = 0; sbal_no < count; sbal_no++) { - sbal_idx = (first + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; + sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q; /* go through all SBALEs of SBAL */ zfcp_fsf_reqid_check(qdio, sbal_idx); } /* - * put range of SBALs back to response queue - * (including SBALs which have already been free before) + * put SBALs back to response queue */ - zfcp_qdio_resp_put_back(qdio, count); + if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, idx, count)) + zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2", NULL); } static struct qdio_buffer_element * @@ -185,17 +160,6 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) return zfcp_qdio_sbale_curr(qdio, q_req); } -static void zfcp_qdio_undo_sbals(struct zfcp_qdio *qdio, - struct zfcp_qdio_req *q_req) -{ - struct qdio_buffer **sbal = qdio->req_q.sbal; - int first = q_req->sbal_first; - int last = q_req->sbal_last; - int count = (last - first + QDIO_MAX_BUFFERS_PER_Q) % - QDIO_MAX_BUFFERS_PER_Q + 1; - zfcp_qdio_zero_sbals(sbal, first, count); -} - /** * zfcp_qdio_sbals_from_sg - fill SBALs from scatter-gather list * @qdio: pointer to struct zfcp_qdio @@ -218,7 +182,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, sbale = zfcp_qdio_sbale_next(qdio, q_req); if (!sbale) { atomic_inc(&qdio->req_q_full); - zfcp_qdio_undo_sbals(qdio, q_req); + zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first, + q_req->sbal_number); return -EINVAL; } @@ -237,10 +202,8 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) { - struct zfcp_qdio_queue *req_q = &qdio->req_q; - spin_lock_bh(&qdio->req_q_lock); - if (atomic_read(&req_q->count) || + if (atomic_read(&qdio->req_q_free) || !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return 1; spin_unlock_bh(&qdio->req_q_lock); @@ -289,25 +252,25 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) */ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { - struct zfcp_qdio_queue *req_q = &qdio->req_q; - int first = q_req->sbal_first; - int count = q_req->sbal_number; int retval; - unsigned int qdio_flags = QDIO_FLAG_SYNC_OUTPUT; + u8 sbal_number = q_req->sbal_number; zfcp_qdio_account(qdio); - retval = do_QDIO(qdio->adapter->ccw_device, qdio_flags, 0, first, - count); + retval = do_QDIO(qdio->adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, + q_req->sbal_first, sbal_number); + if (unlikely(retval)) { - zfcp_qdio_zero_sbals(req_q->sbal, first, count); + zfcp_qdio_zero_sbals(qdio->req_q, q_req->sbal_first, + sbal_number); return retval; } /* account for transferred buffers */ - atomic_sub(count, &req_q->count); - req_q->first += count; - req_q->first %= QDIO_MAX_BUFFERS_PER_Q; + atomic_sub(sbal_number, &qdio->req_q_free); + qdio->req_q_idx += sbal_number; + qdio->req_q_idx %= QDIO_MAX_BUFFERS_PER_Q; + return 0; } @@ -329,8 +292,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->input_handler = zfcp_qdio_int_resp; id->output_handler = zfcp_qdio_int_req; id->int_parm = (unsigned long) qdio; - id->input_sbal_addr_array = (void **) (qdio->resp_q.sbal); - id->output_sbal_addr_array = (void **) (qdio->req_q.sbal); + id->input_sbal_addr_array = (void **) (qdio->res_q); + id->output_sbal_addr_array = (void **) (qdio->req_q); } /** @@ -343,8 +306,8 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) { struct qdio_initialize init_data; - if (zfcp_qdio_buffers_enqueue(qdio->req_q.sbal) || - zfcp_qdio_buffers_enqueue(qdio->resp_q.sbal)) + if (zfcp_qdio_buffers_enqueue(qdio->req_q) || + zfcp_qdio_buffers_enqueue(qdio->res_q)) return -ENOMEM; zfcp_qdio_setup_init_data(&init_data, qdio); @@ -358,34 +321,30 @@ static int zfcp_qdio_allocate(struct zfcp_qdio *qdio) */ void zfcp_qdio_close(struct zfcp_qdio *qdio) { - struct zfcp_qdio_queue *req_q; - int first, count; + struct zfcp_adapter *adapter = qdio->adapter; + int idx, count; - if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) + if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return; /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ - req_q = &qdio->req_q; spin_lock_bh(&qdio->req_q_lock); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); spin_unlock_bh(&qdio->req_q_lock); wake_up(&qdio->req_q_wq); - qdio_shutdown(qdio->adapter->ccw_device, - QDIO_FLAG_CLEANUP_USING_CLEAR); + qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); /* cleanup used outbound sbals */ - count = atomic_read(&req_q->count); + count = atomic_read(&qdio->req_q_free); if (count < QDIO_MAX_BUFFERS_PER_Q) { - first = (req_q->first + count) % QDIO_MAX_BUFFERS_PER_Q; + idx = (qdio->req_q_idx + count) % QDIO_MAX_BUFFERS_PER_Q; count = QDIO_MAX_BUFFERS_PER_Q - count; - zfcp_qdio_zero_sbals(req_q->sbal, first, count); + zfcp_qdio_zero_sbals(qdio->req_q, idx, count); } - req_q->first = 0; - atomic_set(&req_q->count, 0); - qdio->resp_q.first = 0; - atomic_set(&qdio->resp_q.count, 0); + qdio->req_q_idx = 0; + atomic_set(&qdio->req_q_free, 0); } /** @@ -397,10 +356,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) { struct qdio_buffer_element *sbale; struct qdio_initialize init_data; - struct ccw_device *cdev = qdio->adapter->ccw_device; + struct zfcp_adapter *adapter = qdio->adapter; + struct ccw_device *cdev = adapter->ccw_device; int cc; - if (atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) + if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) return -EIO; zfcp_qdio_setup_init_data(&init_data, qdio); @@ -412,19 +372,18 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) goto failed_qdio; for (cc = 0; cc < QDIO_MAX_BUFFERS_PER_Q; cc++) { - sbale = &(qdio->resp_q.sbal[cc]->element[0]); + sbale = &(qdio->res_q[cc]->element[0]); sbale->length = 0; sbale->flags = SBAL_FLAGS_LAST_ENTRY; sbale->addr = NULL; } - if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, - QDIO_MAX_BUFFERS_PER_Q)) + if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q)) goto failed_qdio; /* set index of first avalable SBALS / number of available SBALS */ - qdio->req_q.first = 0; - atomic_set(&qdio->req_q.count, QDIO_MAX_BUFFERS_PER_Q); + qdio->req_q_idx = 0; + atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); return 0; @@ -438,7 +397,6 @@ failed_establish: void zfcp_qdio_destroy(struct zfcp_qdio *qdio) { - struct qdio_buffer **sbal_req, **sbal_resp; int p; if (!qdio) @@ -447,12 +405,9 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio) if (qdio->adapter->ccw_device) qdio_free(qdio->adapter->ccw_device); - sbal_req = qdio->req_q.sbal; - sbal_resp = qdio->resp_q.sbal; - for (p = 0; p < QDIO_MAX_BUFFERS_PER_Q; p += QBUFF_PER_PAGE) { - free_page((unsigned long) sbal_req[p]); - free_page((unsigned long) sbal_resp[p]); + free_page((unsigned long) qdio->req_q[p]); + free_page((unsigned long) qdio->res_q[p]); } kfree(qdio); diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 8bb00545f19..10d0df99dbf 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -27,22 +27,12 @@ #define ZFCP_QDIO_MAX_SBALES_PER_REQ \ (ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2) -/** - * struct zfcp_qdio_queue - qdio queue buffer, zfcp index and free count - * @sbal: qdio buffers - * @first: index of next free buffer in queue - * @count: number of free buffers in queue - */ -struct zfcp_qdio_queue { - struct qdio_buffer *sbal[QDIO_MAX_BUFFERS_PER_Q]; - u8 first; - atomic_t count; -}; - /** * struct zfcp_qdio - basic qdio data structure - * @resp_q: response queue + * @res_q: response queue * @req_q: request queue + * @req_q_idx: index of next free buffer + * @req_q_free: number of free buffers in queue * @stat_lock: lock to protect req_q_util and req_q_time * @req_q_lock: lock to serialize access to request queue * @req_q_time: time of last fill level change @@ -52,8 +42,10 @@ struct zfcp_qdio_queue { * @adapter: adapter used in conjunction with this qdio structure */ struct zfcp_qdio { - struct zfcp_qdio_queue resp_q; - struct zfcp_qdio_queue req_q; + struct qdio_buffer *res_q[QDIO_MAX_BUFFERS_PER_Q]; + struct qdio_buffer *req_q[QDIO_MAX_BUFFERS_PER_Q]; + u8 req_q_idx; + atomic_t req_q_free; spinlock_t stat_lock; spinlock_t req_q_lock; unsigned long long req_q_time; @@ -73,7 +65,6 @@ struct zfcp_qdio { * @sbale_curr: current sbale at creation of this request * @sbal_response: sbal used in interrupt * @qdio_outb_usage: usage of outbound queue - * @qdio_inb_usage: usage of inbound queue */ struct zfcp_qdio_req { u32 sbtype; @@ -84,21 +75,8 @@ struct zfcp_qdio_req { u8 sbale_curr; u8 sbal_response; u16 qdio_outb_usage; - u16 qdio_inb_usage; }; -/** - * zfcp_qdio_sbale - return pointer to sbale in qdio queue - * @q: queue where to find sbal - * @sbal_idx: sbal index in queue - * @sbale_idx: sbale index in sbal - */ -static inline struct qdio_buffer_element * -zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) -{ - return &q->sbal[sbal_idx]->element[sbale_idx]; -} - /** * zfcp_qdio_sbale_req - return pointer to sbale on req_q for a request * @qdio: pointer to struct zfcp_qdio @@ -108,7 +86,7 @@ zfcp_qdio_sbale(struct zfcp_qdio_queue *q, int sbal_idx, int sbale_idx) static inline struct qdio_buffer_element * zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { - return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, 0); + return &qdio->req_q[q_req->sbal_last]->element[0]; } /** @@ -120,8 +98,7 @@ zfcp_qdio_sbale_req(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) static inline struct qdio_buffer_element * zfcp_qdio_sbale_curr(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) { - return zfcp_qdio_sbale(&qdio->req_q, q_req->sbal_last, - q_req->sbale_curr); + return &qdio->req_q[q_req->sbal_last]->element[q_req->sbale_curr]; } /** @@ -142,25 +119,25 @@ void zfcp_qdio_req_init(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, unsigned long req_id, u32 sbtype, void *data, u32 len) { struct qdio_buffer_element *sbale; - int count = min(atomic_read(&qdio->req_q.count), + int count = min(atomic_read(&qdio->req_q_free), ZFCP_QDIO_MAX_SBALS_PER_REQ); - q_req->sbal_first = q_req->sbal_last = qdio->req_q.first; + q_req->sbal_first = q_req->sbal_last = qdio->req_q_idx; q_req->sbal_number = 1; q_req->sbtype = sbtype; + q_req->sbale_curr = 1; q_req->sbal_limit = (q_req->sbal_first + count - 1) % QDIO_MAX_BUFFERS_PER_Q; sbale = zfcp_qdio_sbale_req(qdio, q_req); sbale->addr = (void *) req_id; - sbale->flags |= SBAL_FLAGS0_COMMAND; - sbale->flags |= sbtype; + sbale->flags = SBAL_FLAGS0_COMMAND | sbtype; - q_req->sbale_curr = 1; + if (unlikely(!data)) + return; sbale++; sbale->addr = data; - if (likely(data)) - sbale->length = len; + sbale->length = len; } /** @@ -232,7 +209,7 @@ static inline void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, int max_sbals) { - int count = min(atomic_read(&qdio->req_q.count), max_sbals); + int count = min(atomic_read(&qdio->req_q_free), max_sbals); q_req->sbal_limit = (q_req->sbal_first + count - 1) % QDIO_MAX_BUFFERS_PER_Q; -- cgit v1.2.3-70-g09d2 From 2d1e547f7523514d1da449bcf08645fe13579378 Mon Sep 17 00:00:00 2001 From: Sven Schuetz Date: Fri, 16 Jul 2010 15:37:39 +0200 Subject: [SCSI] zfcp: Post events through FC transport class Post FC transport class netlink events for usage in the userspace, e.g. for HBAAPI. Supported events are those required for the polled events in HBAAPI. - link up - link down - incoming RSCN (events related to FC-AL are not supported, as zfcp has no support for FC-AL) Signed-off-by: Sven Schuetz Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_aux.c | 4 ++++ drivers/s390/scsi/zfcp_def.h | 2 ++ drivers/s390/scsi/zfcp_ext.h | 3 +++ drivers/s390/scsi/zfcp_fc.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fc.h | 24 ++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 3 +++ 6 files changed, 90 insertions(+) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 7c01c4c3f6b..96fa1f53639 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -524,6 +524,10 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) rwlock_init(&adapter->port_list_lock); INIT_LIST_HEAD(&adapter->port_list); + INIT_LIST_HEAD(&adapter->events.list); + INIT_WORK(&adapter->events.work, zfcp_fc_post_event); + spin_lock_init(&adapter->events.list_lock); + init_waitqueue_head(&adapter->erp_ready_wq); init_waitqueue_head(&adapter->erp_done_wqh); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 86a8725430a..cb3640c6477 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -37,6 +37,7 @@ #include #include #include "zfcp_fsf.h" +#include "zfcp_fc.h" #include "zfcp_qdio.h" struct zfcp_reqlist; @@ -190,6 +191,7 @@ struct zfcp_adapter { struct service_level service_level; struct workqueue_struct *work_queue; struct device_dma_parameters dma_parms; + struct zfcp_fc_events events; }; struct zfcp_port { diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 3aab0f5544d..a8bb7488dc9 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -96,6 +96,9 @@ extern void zfcp_erp_adapter_access_changed(struct zfcp_adapter *, char *, extern void zfcp_erp_timeout_handler(unsigned long); /* zfcp_fc.c */ +extern void zfcp_fc_enqueue_event(struct zfcp_adapter *, + enum fc_host_event_code event_code, u32); +extern void zfcp_fc_post_event(struct work_struct *); extern void zfcp_fc_scan_ports(struct work_struct *); extern void zfcp_fc_incoming_els(struct zfcp_fsf_req *); extern void zfcp_fc_port_did_lookup(struct work_struct *); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 6f8ab43a485..6f3ed2b9a34 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -23,6 +23,58 @@ static u32 zfcp_fc_rscn_range_mask[] = { [ELS_ADDR_FMT_FAB] = 0x000000, }; +/** + * zfcp_fc_post_event - post event to userspace via fc_transport + * @work: work struct with enqueued events + */ +void zfcp_fc_post_event(struct work_struct *work) +{ + struct zfcp_fc_event *event = NULL, *tmp = NULL; + LIST_HEAD(tmp_lh); + struct zfcp_fc_events *events = container_of(work, + struct zfcp_fc_events, work); + struct zfcp_adapter *adapter = container_of(events, struct zfcp_adapter, + events); + + spin_lock_bh(&events->list_lock); + list_splice_init(&events->list, &tmp_lh); + spin_unlock_bh(&events->list_lock); + + list_for_each_entry_safe(event, tmp, &tmp_lh, list) { + fc_host_post_event(adapter->scsi_host, fc_get_event_number(), + event->code, event->data); + list_del(&event->list); + kfree(event); + } + +} + +/** + * zfcp_fc_enqueue_event - safely enqueue FC HBA API event from irq context + * @adapter: The adapter where to enqueue the event + * @event_code: The event code (as defined in fc_host_event_code in + * scsi_transport_fc.h) + * @event_data: The event data (e.g. n_port page in case of els) + */ +void zfcp_fc_enqueue_event(struct zfcp_adapter *adapter, + enum fc_host_event_code event_code, u32 event_data) +{ + struct zfcp_fc_event *event; + + event = kmalloc(sizeof(struct zfcp_fc_event), GFP_ATOMIC); + if (!event) + return; + + event->code = event_code; + event->data = event_data; + + spin_lock(&adapter->events.list_lock); + list_add_tail(&event->list, &adapter->events.list); + spin_unlock(&adapter->events.list_lock); + + queue_work(adapter->work_queue, &adapter->events.work); +} + static int zfcp_fc_wka_port_get(struct zfcp_fc_wka_port *wka_port) { if (mutex_lock_interruptible(&wka_port->mutex)) @@ -148,6 +200,8 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) afmt = page->rscn_page_flags & ELS_RSCN_ADDR_FMT_MASK; _zfcp_fc_incoming_rscn(fsf_req, zfcp_fc_rscn_range_mask[afmt], page); + zfcp_fc_enqueue_event(fsf_req->adapter, FCH_EVT_RSCN, + *(u32 *)page); } queue_work(fsf_req->adapter->work_queue, &fsf_req->adapter->scan_work); } diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 0747b087390..85c37d2b82c 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -29,6 +29,30 @@ #define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000) +/** + * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context + * @code: Event code + * @data: Event data + * @list: list_head for zfcp_fc_events list + */ +struct zfcp_fc_event { + enum fc_host_event_code code; + u32 data; + struct list_head list; +}; + +/** + * struct zfcp_fc_events - Infrastructure for posting FC events from irq context + * @list: List for queueing of events from irq context to workqueue + * @list_lock: Lock for event list + * @work: work_struct for forwarding events in workqueue +*/ +struct zfcp_fc_events { + struct list_head list; + spinlock_t list_lock; + struct work_struct work; +}; + /** * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request * @ct_hdr: FC GS common transport header diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 0710c59b80a..63402fd5f9a 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -274,6 +274,7 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) break; case FSF_STATUS_READ_LINK_DOWN: zfcp_fsf_status_read_link_down(req); + zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKDOWN, 0); break; case FSF_STATUS_READ_LINK_UP: dev_info(&adapter->ccw_device->dev, @@ -286,6 +287,8 @@ static void zfcp_fsf_status_read_handler(struct zfcp_fsf_req *req) ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, "fssrh_2", req); + zfcp_fc_enqueue_event(adapter, FCH_EVT_LINKUP, 0); + break; case FSF_STATUS_READ_NOTIFICATION_LOST: if (sr_buf->status_subtype & FSF_STATUS_READ_SUB_ACT_UPDATED) -- cgit v1.2.3-70-g09d2 From d23948ea38c4c6aa13e4df903dfdd71cabd0e6a3 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Fri, 16 Jul 2010 15:37:40 +0200 Subject: [SCSI] zfcp: Prevent access on uninitialized memory. Initialize allocated memory to zero to prevent access on error. This prevents a possible error in the error handling path. Signed-off-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 075852f6968..a08d33a96ec 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -1005,7 +1005,7 @@ int zfcp_dbf_adapter_register(struct zfcp_adapter *adapter) char dbf_name[DEBUG_MAX_NAME_LEN]; struct zfcp_dbf *dbf; - dbf = kmalloc(sizeof(struct zfcp_dbf), GFP_KERNEL); + dbf = kzalloc(sizeof(struct zfcp_dbf), GFP_KERNEL); if (!dbf) return -ENOMEM; -- cgit v1.2.3-70-g09d2 From dcc18f48a2f1a44c5e8848f30d0cf53a8066c62a Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 16 Jul 2010 15:37:41 +0200 Subject: [SCSI] zfcp: Enable data division support for FCP devices Try to enable data division support for FCP devices and indicate in the adapter status flag if it succeeded. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- arch/s390/include/asm/qdio.h | 6 ++++++ drivers/s390/cio/qdio_setup.c | 2 ++ drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_qdio.c | 11 ++++++++++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 0eaae626027..2ba63027629 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h @@ -84,6 +84,7 @@ struct qdr { #define QIB_AC_OUTBOUND_PCI_SUPPORTED 0x40 #define QIB_RFLAGS_ENABLE_QEBSM 0x80 +#define QIB_RFLAGS_ENABLE_DATA_DIV 0x02 /** * struct qib - queue information block (QIB) @@ -284,6 +285,9 @@ struct slsb { u8 val[QDIO_MAX_BUFFERS_PER_Q]; } __attribute__ ((packed, aligned(256))); +#define CHSC_AC2_DATA_DIV_AVAILABLE 0x0010 +#define CHSC_AC2_DATA_DIV_ENABLED 0x0002 + struct qdio_ssqd_desc { u8 flags; u8:8; @@ -332,6 +336,7 @@ typedef void qdio_handler_t(struct ccw_device *, unsigned int, int, * @adapter_name: name for the adapter * @qib_param_field_format: format for qib_parm_field * @qib_param_field: pointer to 128 bytes or NULL, if no param field + * @qib_rflags: rflags to set * @input_slib_elements: pointer to no_input_qs * 128 words of data or NULL * @output_slib_elements: pointer to no_output_qs * 128 words of data or NULL * @no_input_qs: number of input queues @@ -348,6 +353,7 @@ struct qdio_initialize { unsigned char adapter_name[8]; unsigned int qib_param_field_format; unsigned char *qib_param_field; + unsigned char qib_rflags; unsigned long *input_slib_elements; unsigned long *output_slib_elements; unsigned int no_input_qs; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 6326b67c45d..34c7e4046df 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -368,6 +368,8 @@ static void setup_qib(struct qdio_irq *irq_ptr, if (qebsm_possible()) irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM; + irq_ptr->qib.rflags |= init_data->qib_rflags; + irq_ptr->qib.qfmt = init_data->q_format; if (init_data->no_input_qs) irq_ptr->qib.isliba = diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index cb3640c6477..6c6374ba180 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -77,6 +77,7 @@ struct zfcp_reqlist; #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 +#define ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED 0x00000400 /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index a638278c602..c4559b29beb 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -283,6 +283,7 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->q_format = QDIO_ZFCP_QFMT; memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8); ASCEBC(id->adapter_name, 8); + id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV; id->qib_param_field_format = 0; id->qib_param_field = NULL; id->input_slib_elements = NULL; @@ -294,8 +295,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, id->int_parm = (unsigned long) qdio; id->input_sbal_addr_array = (void **) (qdio->res_q); id->output_sbal_addr_array = (void **) (qdio->req_q); - } + /** * zfcp_qdio_allocate - allocate queue memory and initialize QDIO data * @adapter: pointer to struct zfcp_adapter @@ -358,6 +359,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) struct qdio_initialize init_data; struct zfcp_adapter *adapter = qdio->adapter; struct ccw_device *cdev = adapter->ccw_device; + struct qdio_ssqd_desc ssqd; int cc; if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) @@ -368,6 +370,13 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) if (qdio_establish(&init_data)) goto failed_establish; + if (qdio_get_ssqd_desc(init_data.cdev, &ssqd)) + goto failed_qdio; + + if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED) + atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, + &qdio->adapter->status); + if (qdio_activate(cdev)) goto failed_qdio; -- cgit v1.2.3-70-g09d2 From ef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4 Mon Sep 17 00:00:00 2001 From: Felix Beck Date: Fri, 16 Jul 2010 15:37:42 +0200 Subject: [SCSI] zfcp: Introduce experimental support for DIF/DIX Introduce support for DIF/DIX in zfcp: Report the capabilities for the Scsi_host, map the protection data when issuing I/O requests and handle the new error codes. Also add the fsf data_direction field to the hba trace, it is useful information for debugging in that area. This is an EXPERIMENTAL feature for now. Signed-off-by: Felix Beck Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_dbf.c | 3 ++ drivers/s390/scsi/zfcp_dbf.h | 1 + drivers/s390/scsi/zfcp_ext.h | 2 + drivers/s390/scsi/zfcp_fc.h | 3 ++ drivers/s390/scsi/zfcp_fsf.c | 109 +++++++++++++++++++++++++++++++++--------- drivers/s390/scsi/zfcp_fsf.h | 24 ++++++++-- drivers/s390/scsi/zfcp_qdio.c | 4 -- drivers/s390/scsi/zfcp_qdio.h | 16 +++++++ drivers/s390/scsi/zfcp_scsi.c | 53 ++++++++++++++++++++ drivers/scsi/Kconfig | 4 ++ 10 files changed, 189 insertions(+), 30 deletions(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index a08d33a96ec..a86117b0d6e 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -155,6 +155,8 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level, if (scsi_cmnd) { response->u.fcp.cmnd = (unsigned long)scsi_cmnd; response->u.fcp.serial = scsi_cmnd->serial_number; + response->u.fcp.data_dir = + qtcb->bottom.io.data_direction; } break; @@ -326,6 +328,7 @@ static void zfcp_dbf_hba_view_response(char **p, case FSF_QTCB_FCP_CMND: if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) break; + zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir); zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); *p += sprintf(*p, "\n"); diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 457e046f2d2..2bcc3403126 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -111,6 +111,7 @@ struct zfcp_dbf_hba_record_response { struct { u64 cmnd; u64 serial; + u32 data_dir; } fcp; struct { u64 wwpn; diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index a8bb7488dc9..de0925f25dc 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -164,6 +164,8 @@ extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *); extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); extern void zfcp_scsi_scan(struct zfcp_unit *); extern void zfcp_scsi_scan_work(struct work_struct *); +extern void zfcp_scsi_set_prot(struct zfcp_adapter *); +extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); /* zfcp_sysfs.c */ extern struct attribute_group zfcp_sysfs_unit_attrs; diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h index 85c37d2b82c..938d5036016 100644 --- a/drivers/s390/scsi/zfcp_fc.h +++ b/drivers/s390/scsi/zfcp_fc.h @@ -220,6 +220,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi) memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len); fcp->fc_dl = scsi_bufflen(scsi); + + if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1) + fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8; } /** diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 63402fd5f9a..f9be5d60d92 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -526,6 +526,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) return -EIO; } + zfcp_scsi_set_prot(adapter); + return 0; } @@ -988,6 +990,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); if (bytes <= 0) return -EIO; + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); req->qtcb->bottom.support.req_buf_length = bytes; zfcp_qdio_skip_to_last_sbale(&req->qdio_req); @@ -996,6 +999,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, req->qtcb->bottom.support.resp_buf_length = bytes; if (bytes <= 0) return -EIO; + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); return 0; } @@ -2038,9 +2042,13 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi) blktrc.fabric_lat = lat_in->fabric_lat * ticks; switch (req->qtcb->bottom.io.data_direction) { + case FSF_DATADIR_DIF_READ_STRIP: + case FSF_DATADIR_DIF_READ_CONVERT: case FSF_DATADIR_READ: lat = &unit->latencies.read; break; + case FSF_DATADIR_DIF_WRITE_INSERT: + case FSF_DATADIR_DIF_WRITE_CONVERT: case FSF_DATADIR_WRITE: lat = &unit->latencies.write; break; @@ -2081,6 +2089,21 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) goto skip_fsfstatus; } + switch (req->qtcb->header.fsf_status) { + case FSF_INCONSISTENT_PROT_DATA: + case FSF_INVALID_PROT_PARM: + set_host_byte(scpnt, DID_ERROR); + goto skip_fsfstatus; + case FSF_BLOCK_GUARD_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x1); + goto skip_fsfstatus; + case FSF_APP_TAG_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x2); + goto skip_fsfstatus; + case FSF_REF_TAG_CHECK_FAILURE: + zfcp_scsi_dif_sense_error(scpnt, 0x3); + goto skip_fsfstatus; + } fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); @@ -2190,6 +2213,44 @@ skip_fsfstatus: } } +static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir) +{ + switch (scsi_get_prot_op(scsi_cmnd)) { + case SCSI_PROT_NORMAL: + switch (scsi_cmnd->sc_data_direction) { + case DMA_NONE: + *data_dir = FSF_DATADIR_CMND; + break; + case DMA_FROM_DEVICE: + *data_dir = FSF_DATADIR_READ; + break; + case DMA_TO_DEVICE: + *data_dir = FSF_DATADIR_WRITE; + break; + case DMA_BIDIRECTIONAL: + return -EINVAL; + } + break; + + case SCSI_PROT_READ_STRIP: + *data_dir = FSF_DATADIR_DIF_READ_STRIP; + break; + case SCSI_PROT_WRITE_INSERT: + *data_dir = FSF_DATADIR_DIF_WRITE_INSERT; + break; + case SCSI_PROT_READ_PASS: + *data_dir = FSF_DATADIR_DIF_READ_CONVERT; + break; + case SCSI_PROT_WRITE_PASS: + *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT; + break; + default: + return -EINVAL; + } + + return 0; +} + /** * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) * @unit: unit where command is sent to @@ -2201,9 +2262,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, struct zfcp_fsf_req *req; struct fcp_cmnd *fcp_cmnd; unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; - int real_bytes, retval = -EIO; + int real_bytes, retval = -EIO, dix_bytes = 0; struct zfcp_adapter *adapter = unit->port->adapter; struct zfcp_qdio *qdio = adapter->qdio; + struct fsf_qtcb_bottom_io *io; if (unlikely(!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) @@ -2226,46 +2288,46 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit, goto out; } + scsi_cmnd->host_scribble = (unsigned char *) req->req_id; + + io = &req->qtcb->bottom.io; req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; req->unit = unit; req->data = scsi_cmnd; req->handler = zfcp_fsf_send_fcp_command_handler; req->qtcb->header.lun_handle = unit->handle; req->qtcb->header.port_handle = unit->port->handle; - req->qtcb->bottom.io.service_class = FSF_CLASS_3; - req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; + io->service_class = FSF_CLASS_3; + io->fcp_cmnd_length = FCP_CMND_LEN; - scsi_cmnd->host_scribble = (unsigned char *) req->req_id; - - /* - * set depending on data direction: - * data direction bits in SBALE (SB Type) - * data direction bits in QTCB - */ - switch (scsi_cmnd->sc_data_direction) { - case DMA_NONE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND; - break; - case DMA_FROM_DEVICE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ; - break; - case DMA_TO_DEVICE: - req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE; - break; - case DMA_BIDIRECTIONAL: - goto failed_scsi_cmnd; + if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) { + io->data_block_length = scsi_cmnd->device->sector_size; + io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF; } + zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction); + get_device(&unit->dev); fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); + if (scsi_prot_sg_count(scsi_cmnd)) { + zfcp_qdio_set_data_div(qdio, &req->qdio_req, + scsi_prot_sg_count(scsi_cmnd)); + dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, + scsi_prot_sglist(scsi_cmnd)); + io->prot_data_length = dix_bytes; + } + real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, scsi_sglist(scsi_cmnd)); - if (unlikely(real_bytes < 0)) + + if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0)) goto failed_scsi_cmnd; + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); + retval = zfcp_fsf_req_send(req); if (unlikely(retval)) goto failed_scsi_cmnd; @@ -2389,6 +2451,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, zfcp_fsf_req_free(req); goto out; } + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index ca110e38676..db8c85382dc 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -80,11 +80,15 @@ #define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061 #define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062 #define FSF_SBAL_MISMATCH 0x00000063 +#define FSF_INCONSISTENT_PROT_DATA 0x00000070 +#define FSF_INVALID_PROT_PARM 0x00000071 +#define FSF_BLOCK_GUARD_CHECK_FAILURE 0x00000081 +#define FSF_APP_TAG_CHECK_FAILURE 0x00000082 +#define FSF_REF_TAG_CHECK_FAILURE 0x00000083 #define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD #define FSF_UNKNOWN_COMMAND 0x000000E2 #define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3 #define FSF_INVALID_COMMAND_OPTION 0x000000E5 -/* #define FSF_ERROR 0x000000FF */ #define FSF_PROT_STATUS_QUAL_SIZE 16 #define FSF_STATUS_QUALIFIER_SIZE 16 @@ -147,6 +151,13 @@ #define FSF_DATADIR_WRITE 0x00000001 #define FSF_DATADIR_READ 0x00000002 #define FSF_DATADIR_CMND 0x00000004 +#define FSF_DATADIR_DIF_WRITE_INSERT 0x00000009 +#define FSF_DATADIR_DIF_READ_STRIP 0x0000000a +#define FSF_DATADIR_DIF_WRITE_CONVERT 0x0000000b +#define FSF_DATADIR_DIF_READ_CONVERT 0X0000000c + +/* data protection control flags */ +#define FSF_APP_TAG_CHECK_ENABLE 0x10 /* fc service class */ #define FSF_CLASS_3 0x00000003 @@ -162,6 +173,8 @@ #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 +#define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000 +#define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000 /* host connection features */ #define FSF_FEATURE_NPIV_MODE 0x00000001 @@ -316,9 +329,14 @@ struct fsf_qtcb_header { struct fsf_qtcb_bottom_io { u32 data_direction; u32 service_class; - u8 res1[8]; + u8 res1; + u8 data_prot_flags; + u16 app_tag_value; + u32 ref_tag_value; u32 fcp_cmnd_length; - u8 res2[12]; + u32 data_block_length; + u32 prot_data_length; + u8 res2[4]; u8 fcp_cmnd[FSF_FCP_CMND_SIZE]; u8 fcp_rsp[FSF_FCP_RSP_SIZE]; u8 res3[64]; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index c4559b29beb..aceced8ec7e 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -193,10 +193,6 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, bytes += sg->length; } - /* assume that no other SBALEs are to follow in the same SBAL */ - sbale = zfcp_qdio_sbale_curr(qdio, q_req); - sbale->flags |= SBAL_FLAGS_LAST_ENTRY; - return bytes; } diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 10d0df99dbf..2297d8d3e94 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -215,4 +215,20 @@ void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio, QDIO_MAX_BUFFERS_PER_Q; } +/** + * zfcp_qdio_set_data_div - set data division count + * @qdio: pointer to struct zfcp_qdio + * @q_req: The current zfcp_qdio_req + * @count: The data division count + */ +static inline +void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio, + struct zfcp_qdio_req *q_req, u32 count) +{ + struct qdio_buffer_element *sbale; + + sbale = &qdio->req_q[q_req->sbal_first]->element[0]; + sbale->length = count; +} + #endif /* ZFCP_QDIO_H */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index eb471a1723c..cb000c9833b 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "zfcp_ext.h" #include "zfcp_dbf.h" @@ -22,6 +23,13 @@ static unsigned int default_depth = 32; module_param_named(queue_depth, default_depth, uint, 0600); MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); +static bool enable_dif; + +#ifdef CONFIG_ZFCP_DIF +module_param_named(dif, enable_dif, bool, 0600); +MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support"); +#endif + static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) { @@ -652,6 +660,51 @@ void zfcp_scsi_scan_work(struct work_struct *work) put_device(&unit->dev); } +/** + * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host + * @adapter: The adapter where to configure DIF/DIX for the SCSI host + */ +void zfcp_scsi_set_prot(struct zfcp_adapter *adapter) +{ + unsigned int mask = 0; + unsigned int data_div; + struct Scsi_Host *shost = adapter->scsi_host; + + data_div = atomic_read(&adapter->status) & + ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED; + + if (enable_dif && + adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1) + mask |= SHOST_DIF_TYPE1_PROTECTION; + + if (enable_dif && data_div && + adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { + mask |= SHOST_DIX_TYPE1_PROTECTION; + scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); + shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; + shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2; + } + + scsi_host_set_prot(shost, mask); +} + +/** + * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error + * @scmd: The SCSI command to report the error for + * @ascq: The ASCQ to put in the sense buffer + * + * See the error handling in sd_done for the sense codes used here. + * Set DID_SOFT_ERROR to retry the request, if possible. + */ +void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq) +{ + scsi_build_sense_buffer(1, scmd->sense_buffer, + ILLEGAL_REQUEST, 0x10, ascq); + set_driver_byte(scmd, DRIVER_SENSE); + scmd->result |= SAM_STAT_CHECK_CONDITION; + set_host_byte(scmd, DID_SOFT_ERROR); +} + struct fc_function_template zfcp_transport_functions = { .show_starget_port_id = 1, .show_starget_port_name = 1, diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 75f2336807c..158284f0573 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1847,6 +1847,10 @@ config ZFCP called zfcp. If you want to compile it as a module, say M here and read . +config ZFCP_DIF + tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)" + depends on ZFCP && EXPERIMENTAL + config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" depends on PCI && SCSI -- cgit v1.2.3-70-g09d2 From 339f4f4eab80caa6cf0d39fb057ad6ddb84ba91e Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 16 Jul 2010 15:37:43 +0200 Subject: [SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions Exploit the cio siosl function to trigger logging in the FCP channel on qdio error conditions. Add a helper function in zfcp_qdio to ensure that tracing is only triggered once before calling qdio_shutdown. Trigger in zfcp for hardware logs are: - timeout for FSF requests to the FCP channel - "no recommendation" status from FCP channel - invalid FSF protocol status - stalled outbound queue - unknown request id on inbound queue - QDIO_ERROR_SLSB_STATE All of the above triggers run from the Linux qdio softirq context, so no additional synchronization is necessary for the handling of the ZFCP_STATUS_ADAPTER_SIOSL_ISSUED flag. Reviewed-by: Swen Schillig Signed-off-by: Christof Schmitt Signed-off-by: James Bottomley --- drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_fsf.c | 7 ++++++- drivers/s390/scsi/zfcp_qdio.c | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 6c6374ba180..e1c6b6e05a7 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -73,6 +73,7 @@ struct zfcp_reqlist; /* adapter status */ #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 +#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index de0925f25dc..3b93239c6f6 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -152,6 +152,7 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *, struct scatterlist *); extern int zfcp_qdio_open(struct zfcp_qdio *); extern void zfcp_qdio_close(struct zfcp_qdio *); +extern void zfcp_qdio_siosl(struct zfcp_adapter *); /* zfcp_scsi.c */ extern struct zfcp_data zfcp_data; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f9be5d60d92..9d1d7d1842c 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -21,6 +21,7 @@ static void zfcp_fsf_request_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; + zfcp_qdio_siosl(adapter); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "fsrth_1", NULL); } @@ -326,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) dev_err(&req->adapter->ccw_device->dev, "The FCP adapter reported a problem " "that cannot be recovered\n"); + zfcp_qdio_siosl(req->adapter); zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); break; } @@ -416,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "0x%x is not a valid transfer protocol status\n", qtcb->prefix.prot_status); + zfcp_qdio_siosl(adapter); zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); } req->status |= ZFCP_STATUS_FSFREQ_ERROR; @@ -2485,13 +2488,15 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) req_id = (unsigned long) sbale->addr; fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); - if (!fsf_req) + if (!fsf_req) { /* * Unknown request means that we have potentially memory * corruption and must stop the machine immediately. */ + zfcp_qdio_siosl(adapter); panic("error: unknown req_id (%lx) on adapter %s.\n", req_id, dev_name(&adapter->ccw_device->dev)); + } fsf_req->qdio_req.sbal_response = sbal_idx; zfcp_fsf_req_complete(fsf_req); diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index aceced8ec7e..b2635759721 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) return 0; } -static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id) +static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, + unsigned int qdio_err) { struct zfcp_adapter *adapter = qdio->adapter; dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); + if (qdio_err & QDIO_ERROR_SLSB_STATE) + zfcp_qdio_siosl(adapter); zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); @@ -74,7 +77,7 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, if (unlikely(qdio_err)) { zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); - zfcp_qdio_handler_error(qdio, "qdireq1"); + zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); return; } @@ -95,7 +98,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, if (unlikely(qdio_err)) { zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); - zfcp_qdio_handler_error(qdio, "qdires1"); + zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); return; } @@ -361,6 +364,9 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) return -EIO; + atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + &qdio->adapter->status); + zfcp_qdio_setup_init_data(&init_data, qdio); if (qdio_establish(&init_data)) @@ -440,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) return 0; } +/** + * zfcp_qdio_siosl - Trigger logging in FCP channel + * @adapter: The zfcp_adapter where to trigger logging + * + * Call the cio siosl function to trigger hardware logging. This + * wrapper function sets a flag to ensure hardware logging is only + * triggered once before going through qdio shutdown. + * + * The triggers are always run from qdio tasklet context, so no + * additional synchronization is necessary. + */ +void zfcp_qdio_siosl(struct zfcp_adapter *adapter) +{ + int rc; + + if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED) + return; + + rc = ccw_device_siosl(adapter->ccw_device); + if (!rc) + atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + &adapter->status); +} -- cgit v1.2.3-70-g09d2